blob: 31ca9780bf42ab4ef4c5710826e9a92a8db86bf0 [file] [log] [blame]
Kaido Kertf309f9a2021-04-30 12:09:15 -07001// 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
13namespace cppgc {
14namespace internal {
15
16class 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;
26 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
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
40 explicit GCTask(GarbageCollector* collector)
41 : collector_(collector),
42 handle_(Handle::NonEmptyTag{}),
43 saved_epoch_(collector->epoch()) {}
44
45 private:
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
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
67GCInvoker::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
74GCInvoker::GCInvokerImpl::~GCInvokerImpl() {
75 if (gc_task_handle_) {
76 gc_task_handle_.Cancel();
77 }
78}
79
80void 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
94void 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
112GCInvoker::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
117GCInvoker::~GCInvoker() = default;
118
119void GCInvoker::CollectGarbage(GarbageCollector::Config config) {
120 impl_->CollectGarbage(config);
121}
122
123void GCInvoker::StartIncrementalGarbageCollection(
124 GarbageCollector::Config config) {
125 impl_->StartIncrementalGarbageCollection(config);
126}
127
128size_t GCInvoker::epoch() const { return impl_->epoch(); }
129
130} // namespace internal
131} // namespace cppgc