• 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/common.h"
10 #include "include/cppgc/platform.h"
11 #include "src/heap/cppgc/heap.h"
12 #include "src/heap/cppgc/task-handle.h"
13 
14 namespace cppgc {
15 namespace internal {
16 
17 class GCInvoker::GCInvokerImpl final : public GarbageCollector {
18  public:
19   GCInvokerImpl(GarbageCollector*, cppgc::Platform*, cppgc::Heap::StackSupport);
20   ~GCInvokerImpl();
21 
22   GCInvokerImpl(const GCInvokerImpl&) = delete;
23   GCInvokerImpl& operator=(const GCInvokerImpl&) = delete;
24 
25   void CollectGarbage(GarbageCollector::Config) final;
26   void StartIncrementalGarbageCollection(GarbageCollector::Config) final;
epoch() const27   size_t epoch() const final { return collector_->epoch(); }
override_stack_state() const28   const EmbedderStackState* override_stack_state() const final {
29     return collector_->override_stack_state();
30   }
31 
32  private:
33   class GCTask final : public cppgc::Task {
34    public:
35     using Handle = SingleThreadedHandle;
36 
Post(GarbageCollector * collector,cppgc::TaskRunner * runner,GarbageCollector::Config config)37     static Handle Post(GarbageCollector* collector, cppgc::TaskRunner* runner,
38                        GarbageCollector::Config config) {
39       auto task =
40           std::make_unique<GCInvoker::GCInvokerImpl::GCTask>(collector, config);
41       auto handle = task->GetHandle();
42       runner->PostNonNestableTask(std::move(task));
43       return handle;
44     }
45 
GCTask(GarbageCollector * collector,GarbageCollector::Config config)46     explicit GCTask(GarbageCollector* collector,
47                     GarbageCollector::Config config)
48         : collector_(collector),
49           config_(config),
50           handle_(Handle::NonEmptyTag{}),
51           saved_epoch_(collector->epoch()) {}
52 
53    private:
Run()54     void Run() final {
55       CHECK_NULL(collector_->override_stack_state());
56 
57       if (handle_.IsCanceled() || (collector_->epoch() != saved_epoch_)) return;
58 
59       collector_->CollectGarbage(config_);
60       handle_.Cancel();
61     }
62 
GetHandle()63     Handle GetHandle() { return handle_; }
64 
65     GarbageCollector* collector_;
66     GarbageCollector::Config config_;
67     Handle handle_;
68     size_t saved_epoch_;
69   };
70 
71   GarbageCollector* collector_;
72   cppgc::Platform* platform_;
73   cppgc::Heap::StackSupport stack_support_;
74   GCTask::Handle gc_task_handle_;
75 };
76 
GCInvokerImpl(GarbageCollector * collector,cppgc::Platform * platform,cppgc::Heap::StackSupport stack_support)77 GCInvoker::GCInvokerImpl::GCInvokerImpl(GarbageCollector* collector,
78                                         cppgc::Platform* platform,
79                                         cppgc::Heap::StackSupport stack_support)
80     : collector_(collector),
81       platform_(platform),
82       stack_support_(stack_support) {}
83 
~GCInvokerImpl()84 GCInvoker::GCInvokerImpl::~GCInvokerImpl() {
85   if (gc_task_handle_) {
86     gc_task_handle_.Cancel();
87   }
88 }
89 
CollectGarbage(GarbageCollector::Config config)90 void GCInvoker::GCInvokerImpl::CollectGarbage(GarbageCollector::Config config) {
91   DCHECK_EQ(config.marking_type, cppgc::Heap::MarkingType::kAtomic);
92   if ((config.stack_state ==
93        GarbageCollector::Config::StackState::kNoHeapPointers) ||
94       (stack_support_ ==
95        cppgc::Heap::StackSupport::kSupportsConservativeStackScan)) {
96     collector_->CollectGarbage(config);
97   } else if (platform_->GetForegroundTaskRunner() &&
98              platform_->GetForegroundTaskRunner()->NonNestableTasksEnabled()) {
99     if (!gc_task_handle_) {
100       // Force a precise GC since it will run in a non-nestable task.
101       config.stack_state =
102           GarbageCollector::Config::StackState::kNoHeapPointers;
103       DCHECK_NE(cppgc::Heap::StackSupport::kSupportsConservativeStackScan,
104                 stack_support_);
105       gc_task_handle_ = GCTask::Post(
106           collector_, platform_->GetForegroundTaskRunner().get(), config);
107     }
108   }
109 }
110 
StartIncrementalGarbageCollection(GarbageCollector::Config config)111 void GCInvoker::GCInvokerImpl::StartIncrementalGarbageCollection(
112     GarbageCollector::Config config) {
113   DCHECK_NE(config.marking_type, cppgc::Heap::MarkingType::kAtomic);
114   if ((stack_support_ !=
115        cppgc::Heap::StackSupport::kSupportsConservativeStackScan) &&
116       (!platform_->GetForegroundTaskRunner() ||
117        !platform_->GetForegroundTaskRunner()->NonNestableTasksEnabled())) {
118     // In this configuration the GC finalization can only be triggered through
119     // ForceGarbageCollectionSlow. If incremental GC is started, there is no
120     // way to know how long it will remain enabled (and the write barrier with
121     // it). For that reason, we do not support running incremental GCs in this
122     // configuration.
123     return;
124   }
125   // No need to postpone starting incremental GC since the stack is not scanned
126   // until GC finalization.
127   collector_->StartIncrementalGarbageCollection(config);
128 }
129 
GCInvoker(GarbageCollector * collector,cppgc::Platform * platform,cppgc::Heap::StackSupport stack_support)130 GCInvoker::GCInvoker(GarbageCollector* collector, cppgc::Platform* platform,
131                      cppgc::Heap::StackSupport stack_support)
132     : impl_(std::make_unique<GCInvoker::GCInvokerImpl>(collector, platform,
133                                                        stack_support)) {}
134 
135 GCInvoker::~GCInvoker() = default;
136 
CollectGarbage(GarbageCollector::Config config)137 void GCInvoker::CollectGarbage(GarbageCollector::Config config) {
138   impl_->CollectGarbage(config);
139 }
140 
StartIncrementalGarbageCollection(GarbageCollector::Config config)141 void GCInvoker::StartIncrementalGarbageCollection(
142     GarbageCollector::Config config) {
143   impl_->StartIncrementalGarbageCollection(config);
144 }
145 
epoch() const146 size_t GCInvoker::epoch() const { return impl_->epoch(); }
147 
override_stack_state() const148 const EmbedderStackState* GCInvoker::override_stack_state() const {
149   return impl_->override_stack_state();
150 }
151 
152 }  // namespace internal
153 }  // namespace cppgc
154