// Copyright 2020 the V8 project authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "src/heap/cppgc/gc-invoker.h" #include #include "include/cppgc/platform.h" #include "src/heap/cppgc/heap.h" #include "src/heap/cppgc/task-handle.h" namespace cppgc { namespace internal { class GCInvoker::GCInvokerImpl final : public GarbageCollector { public: GCInvokerImpl(GarbageCollector*, cppgc::Platform*, cppgc::Heap::StackSupport); ~GCInvokerImpl(); GCInvokerImpl(const GCInvokerImpl&) = delete; GCInvokerImpl& operator=(const GCInvokerImpl&) = delete; void CollectGarbage(GarbageCollector::Config) final; size_t epoch() const final { return collector_->epoch(); } private: class GCTask final : public cppgc::Task { public: using Handle = SingleThreadedHandle; static Handle Post(GarbageCollector* collector, cppgc::TaskRunner* runner) { auto task = std::make_unique(collector); auto handle = task->GetHandle(); runner->PostNonNestableTask(std::move(task)); return handle; } explicit GCTask(GarbageCollector* collector) : collector_(collector), saved_epoch_(collector->epoch()) {} private: void Run() final { if (handle_.IsCanceled() || (collector_->epoch() != saved_epoch_)) return; collector_->CollectGarbage( GarbageCollector::Config::PreciseAtomicConfig()); handle_.Cancel(); } Handle GetHandle() { return handle_; } GarbageCollector* collector_; Handle handle_; size_t saved_epoch_; }; GarbageCollector* collector_; cppgc::Platform* platform_; cppgc::Heap::StackSupport stack_support_; GCTask::Handle gc_task_handle_; }; GCInvoker::GCInvokerImpl::GCInvokerImpl(GarbageCollector* collector, cppgc::Platform* platform, cppgc::Heap::StackSupport stack_support) : collector_(collector), platform_(platform), stack_support_(stack_support) {} GCInvoker::GCInvokerImpl::~GCInvokerImpl() { if (gc_task_handle_) { gc_task_handle_.Cancel(); } } void GCInvoker::GCInvokerImpl::CollectGarbage(GarbageCollector::Config config) { if ((config.stack_state == GarbageCollector::Config::StackState::kNoHeapPointers) || (stack_support_ == cppgc::Heap::StackSupport::kSupportsConservativeStackScan)) { collector_->CollectGarbage(config); } else if (platform_->GetForegroundTaskRunner()->NonNestableTasksEnabled()) { if (!gc_task_handle_) { gc_task_handle_ = GCTask::Post(collector_, platform_->GetForegroundTaskRunner().get()); } } } GCInvoker::GCInvoker(GarbageCollector* collector, cppgc::Platform* platform, cppgc::Heap::StackSupport stack_support) : impl_(std::make_unique(collector, platform, stack_support)) {} GCInvoker::~GCInvoker() = default; void GCInvoker::CollectGarbage(GarbageCollector::Config config) { impl_->CollectGarbage(config); } size_t GCInvoker::epoch() const { return impl_->epoch(); } } // namespace internal } // namespace cppgc