• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2020 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "src/heap/cppgc/gc-invoker.h"
6 
7 #include <memory>
8 
9 #include "include/cppgc/platform.h"
10 #include "src/heap/cppgc/heap.h"
11 #include "src/heap/cppgc/task-handle.h"
12 
13 namespace cppgc {
14 namespace internal {
15 
16 class GCInvoker::GCInvokerImpl final : public GarbageCollector {
17  public:
18   GCInvokerImpl(GarbageCollector*, cppgc::Platform*, cppgc::Heap::StackSupport);
19   ~GCInvokerImpl();
20 
21   GCInvokerImpl(const GCInvokerImpl&) = delete;
22   GCInvokerImpl& operator=(const GCInvokerImpl&) = delete;
23 
24   void CollectGarbage(GarbageCollector::Config) final;
25   void StartIncrementalGarbageCollection(GarbageCollector::Config) final;
epoch() const26   size_t epoch() const final { return collector_->epoch(); }
27 
28  private:
29   class GCTask final : public cppgc::Task {
30    public:
31     using Handle = SingleThreadedHandle;
32 
Post(GarbageCollector * collector,cppgc::TaskRunner * runner)33     static Handle Post(GarbageCollector* collector, cppgc::TaskRunner* runner) {
34       auto task = std::make_unique<GCInvoker::GCInvokerImpl::GCTask>(collector);
35       auto handle = task->GetHandle();
36       runner->PostNonNestableTask(std::move(task));
37       return handle;
38     }
39 
GCTask(GarbageCollector * collector)40     explicit GCTask(GarbageCollector* collector)
41         : collector_(collector),
42           handle_(Handle::NonEmptyTag{}),
43           saved_epoch_(collector->epoch()) {}
44 
45    private:
Run()46     void Run() final {
47       if (handle_.IsCanceled() || (collector_->epoch() != saved_epoch_)) return;
48 
49       collector_->CollectGarbage(
50           GarbageCollector::Config::PreciseAtomicConfig());
51       handle_.Cancel();
52     }
53 
GetHandle()54     Handle GetHandle() { return handle_; }
55 
56     GarbageCollector* collector_;
57     Handle handle_;
58     size_t saved_epoch_;
59   };
60 
61   GarbageCollector* collector_;
62   cppgc::Platform* platform_;
63   cppgc::Heap::StackSupport stack_support_;
64   GCTask::Handle gc_task_handle_;
65 };
66 
GCInvokerImpl(GarbageCollector * collector,cppgc::Platform * platform,cppgc::Heap::StackSupport stack_support)67 GCInvoker::GCInvokerImpl::GCInvokerImpl(GarbageCollector* collector,
68                                         cppgc::Platform* platform,
69                                         cppgc::Heap::StackSupport stack_support)
70     : collector_(collector),
71       platform_(platform),
72       stack_support_(stack_support) {}
73 
~GCInvokerImpl()74 GCInvoker::GCInvokerImpl::~GCInvokerImpl() {
75   if (gc_task_handle_) {
76     gc_task_handle_.Cancel();
77   }
78 }
79 
CollectGarbage(GarbageCollector::Config config)80 void GCInvoker::GCInvokerImpl::CollectGarbage(GarbageCollector::Config config) {
81   if ((config.stack_state ==
82        GarbageCollector::Config::StackState::kNoHeapPointers) ||
83       (stack_support_ ==
84        cppgc::Heap::StackSupport::kSupportsConservativeStackScan)) {
85     collector_->CollectGarbage(config);
86   } else if (platform_->GetForegroundTaskRunner()->NonNestableTasksEnabled()) {
87     if (!gc_task_handle_) {
88       gc_task_handle_ =
89           GCTask::Post(collector_, platform_->GetForegroundTaskRunner().get());
90     }
91   }
92 }
93 
StartIncrementalGarbageCollection(GarbageCollector::Config config)94 void GCInvoker::GCInvokerImpl::StartIncrementalGarbageCollection(
95     GarbageCollector::Config config) {
96   if ((stack_support_ !=
97        cppgc::Heap::StackSupport::kSupportsConservativeStackScan) &&
98       (!platform_->GetForegroundTaskRunner() ||
99        !platform_->GetForegroundTaskRunner()->NonNestableTasksEnabled())) {
100     // In this configuration the GC finalization can only be triggered through
101     // ForceGarbageCollectionSlow. If incremental GC is started, there is no
102     // way to know how long it will remain enabled (and the write barrier with
103     // it). For that reason, we do not support running incremental GCs in this
104     // configuration.
105     return;
106   }
107   // No need to postpone starting incremental GC since the stack is not scanned
108   // until GC finalization.
109   collector_->StartIncrementalGarbageCollection(config);
110 }
111 
GCInvoker(GarbageCollector * collector,cppgc::Platform * platform,cppgc::Heap::StackSupport stack_support)112 GCInvoker::GCInvoker(GarbageCollector* collector, cppgc::Platform* platform,
113                      cppgc::Heap::StackSupport stack_support)
114     : impl_(std::make_unique<GCInvoker::GCInvokerImpl>(collector, platform,
115                                                        stack_support)) {}
116 
117 GCInvoker::~GCInvoker() = default;
118 
CollectGarbage(GarbageCollector::Config config)119 void GCInvoker::CollectGarbage(GarbageCollector::Config config) {
120   impl_->CollectGarbage(config);
121 }
122 
StartIncrementalGarbageCollection(GarbageCollector::Config config)123 void GCInvoker::StartIncrementalGarbageCollection(
124     GarbageCollector::Config config) {
125   impl_->StartIncrementalGarbageCollection(config);
126 }
127 
epoch() const128 size_t GCInvoker::epoch() const { return impl_->epoch(); }
129 
130 }  // namespace internal
131 }  // namespace cppgc
132