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