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-js/cpp-heap.h"
6
7 #include "include/cppgc/platform.h"
8 #include "include/v8-platform.h"
9 #include "include/v8.h"
10 #include "src/base/macros.h"
11 #include "src/base/platform/time.h"
12 #include "src/execution/isolate.h"
13 #include "src/flags/flags.h"
14 #include "src/heap/base/stack.h"
15 #include "src/heap/cppgc-js/cpp-snapshot.h"
16 #include "src/heap/cppgc-js/unified-heap-marking-state.h"
17 #include "src/heap/cppgc-js/unified-heap-marking-verifier.h"
18 #include "src/heap/cppgc-js/unified-heap-marking-visitor.h"
19 #include "src/heap/cppgc/concurrent-marker.h"
20 #include "src/heap/cppgc/gc-info-table.h"
21 #include "src/heap/cppgc/heap-base.h"
22 #include "src/heap/cppgc/heap-object-header.h"
23 #include "src/heap/cppgc/marker.h"
24 #include "src/heap/cppgc/marking-state.h"
25 #include "src/heap/cppgc/marking-visitor.h"
26 #include "src/heap/cppgc/object-allocator.h"
27 #include "src/heap/cppgc/prefinalizer-handler.h"
28 #include "src/heap/cppgc/stats-collector.h"
29 #include "src/heap/cppgc/sweeper.h"
30 #include "src/heap/marking-worklist.h"
31 #include "src/heap/sweeper.h"
32 #include "src/init/v8.h"
33 #include "src/profiler/heap-profiler.h"
34
35 namespace v8 {
36 namespace internal {
37
38 namespace {
39
40 class CppgcPlatformAdapter final : public cppgc::Platform {
41 public:
CppgcPlatformAdapter(v8::Isolate * isolate)42 explicit CppgcPlatformAdapter(v8::Isolate* isolate)
43 : platform_(V8::GetCurrentPlatform()), isolate_(isolate) {}
44
45 CppgcPlatformAdapter(const CppgcPlatformAdapter&) = delete;
46 CppgcPlatformAdapter& operator=(const CppgcPlatformAdapter&) = delete;
47
GetPageAllocator()48 PageAllocator* GetPageAllocator() final {
49 return platform_->GetPageAllocator();
50 }
51
MonotonicallyIncreasingTime()52 double MonotonicallyIncreasingTime() final {
53 return platform_->MonotonicallyIncreasingTime();
54 }
55
GetForegroundTaskRunner()56 std::shared_ptr<TaskRunner> GetForegroundTaskRunner() final {
57 return platform_->GetForegroundTaskRunner(isolate_);
58 }
59
PostJob(TaskPriority priority,std::unique_ptr<JobTask> job_task)60 std::unique_ptr<JobHandle> PostJob(TaskPriority priority,
61 std::unique_ptr<JobTask> job_task) final {
62 return platform_->PostJob(priority, std::move(job_task));
63 }
64
65 private:
66 v8::Platform* platform_;
67 v8::Isolate* isolate_;
68 };
69
70 class UnifiedHeapConcurrentMarker
71 : public cppgc::internal::ConcurrentMarkerBase {
72 public:
UnifiedHeapConcurrentMarker(cppgc::internal::HeapBase & heap,cppgc::internal::MarkingWorklists & marking_worklists,cppgc::internal::IncrementalMarkingSchedule & incremental_marking_schedule,cppgc::Platform * platform,UnifiedHeapMarkingState & unified_heap_marking_state)73 UnifiedHeapConcurrentMarker(
74 cppgc::internal::HeapBase& heap,
75 cppgc::internal::MarkingWorklists& marking_worklists,
76 cppgc::internal::IncrementalMarkingSchedule& incremental_marking_schedule,
77 cppgc::Platform* platform,
78 UnifiedHeapMarkingState& unified_heap_marking_state)
79 : cppgc::internal::ConcurrentMarkerBase(
80 heap, marking_worklists, incremental_marking_schedule, platform),
81 unified_heap_marking_state_(unified_heap_marking_state) {}
82
83 std::unique_ptr<cppgc::Visitor> CreateConcurrentMarkingVisitor(
84 ConcurrentMarkingState&) const final;
85
86 private:
87 UnifiedHeapMarkingState& unified_heap_marking_state_;
88 };
89
90 std::unique_ptr<cppgc::Visitor>
CreateConcurrentMarkingVisitor(ConcurrentMarkingState & marking_state) const91 UnifiedHeapConcurrentMarker::CreateConcurrentMarkingVisitor(
92 ConcurrentMarkingState& marking_state) const {
93 return std::make_unique<ConcurrentUnifiedHeapMarkingVisitor>(
94 heap(), marking_state, unified_heap_marking_state_);
95 }
96
97 class UnifiedHeapMarker final : public cppgc::internal::MarkerBase {
98 public:
99 UnifiedHeapMarker(Key, Heap& v8_heap, cppgc::internal::HeapBase& cpp_heap,
100 cppgc::Platform* platform, MarkingConfig config);
101
102 ~UnifiedHeapMarker() final = default;
103
104 void AddObject(void*);
105
106 protected:
visitor()107 cppgc::Visitor& visitor() final { return marking_visitor_; }
conservative_visitor()108 cppgc::internal::ConservativeTracingVisitor& conservative_visitor() final {
109 return conservative_marking_visitor_;
110 }
stack_visitor()111 ::heap::base::StackVisitor& stack_visitor() final {
112 return conservative_marking_visitor_;
113 }
114
115 private:
116 UnifiedHeapMarkingState unified_heap_marking_state_;
117 MutatorUnifiedHeapMarkingVisitor marking_visitor_;
118 cppgc::internal::ConservativeMarkingVisitor conservative_marking_visitor_;
119 };
120
UnifiedHeapMarker(Key key,Heap & v8_heap,cppgc::internal::HeapBase & heap,cppgc::Platform * platform,MarkingConfig config)121 UnifiedHeapMarker::UnifiedHeapMarker(Key key, Heap& v8_heap,
122 cppgc::internal::HeapBase& heap,
123 cppgc::Platform* platform,
124 MarkingConfig config)
125 : cppgc::internal::MarkerBase(key, heap, platform, config),
126 unified_heap_marking_state_(v8_heap),
127 marking_visitor_(heap, mutator_marking_state_,
128 unified_heap_marking_state_),
129 conservative_marking_visitor_(heap, mutator_marking_state_,
130 marking_visitor_) {
131 concurrent_marker_ = std::make_unique<UnifiedHeapConcurrentMarker>(
132 heap_, marking_worklists_, schedule_, platform_,
133 unified_heap_marking_state_);
134 }
135
AddObject(void * object)136 void UnifiedHeapMarker::AddObject(void* object) {
137 mutator_marking_state_.MarkAndPush(
138 cppgc::internal::HeapObjectHeader::FromPayload(object));
139 }
140
141 } // namespace
142
CppHeap(v8::Isolate * isolate,const std::vector<std::unique_ptr<cppgc::CustomSpaceBase>> & custom_spaces)143 CppHeap::CppHeap(
144 v8::Isolate* isolate,
145 const std::vector<std::unique_ptr<cppgc::CustomSpaceBase>>& custom_spaces)
146 : cppgc::internal::HeapBase(std::make_shared<CppgcPlatformAdapter>(isolate),
147 custom_spaces,
148 cppgc::internal::HeapBase::StackSupport::
149 kSupportsConservativeStackScan),
150 isolate_(*reinterpret_cast<Isolate*>(isolate)) {
151 CHECK(!FLAG_incremental_marking_wrappers);
152 isolate_.heap_profiler()->AddBuildEmbedderGraphCallback(&CppGraphBuilder::Run,
153 this);
154 }
155
~CppHeap()156 CppHeap::~CppHeap() {
157 isolate_.heap_profiler()->RemoveBuildEmbedderGraphCallback(
158 &CppGraphBuilder::Run, this);
159 }
160
RegisterV8References(const std::vector<std::pair<void *,void * >> & embedder_fields)161 void CppHeap::RegisterV8References(
162 const std::vector<std::pair<void*, void*> >& embedder_fields) {
163 DCHECK(marker_);
164 for (auto& tuple : embedder_fields) {
165 // First field points to type.
166 // Second field points to object.
167 static_cast<UnifiedHeapMarker*>(marker_.get())->AddObject(tuple.second);
168 }
169 marking_done_ = false;
170 }
171
TracePrologue(TraceFlags flags)172 void CppHeap::TracePrologue(TraceFlags flags) {
173 // Finish sweeping in case it is still running.
174 sweeper_.FinishIfRunning();
175
176 const UnifiedHeapMarker::MarkingConfig marking_config{
177 UnifiedHeapMarker::MarkingConfig::CollectionType::kMajor,
178 cppgc::Heap::StackState::kNoHeapPointers,
179 UnifiedHeapMarker::MarkingConfig::MarkingType::kIncrementalAndConcurrent};
180 if ((flags == TraceFlags::kReduceMemory) || (flags == TraceFlags::kForced)) {
181 // Only enable compaction when in a memory reduction garbage collection as
182 // it may significantly increase the final garbage collection pause.
183 compactor_.InitializeIfShouldCompact(marking_config.marking_type,
184 marking_config.stack_state);
185 }
186 marker_ =
187 cppgc::internal::MarkerFactory::CreateAndStartMarking<UnifiedHeapMarker>(
188 *isolate_.heap(), AsBase(), platform_.get(), marking_config);
189 marking_done_ = false;
190 }
191
AdvanceTracing(double deadline_in_ms)192 bool CppHeap::AdvanceTracing(double deadline_in_ms) {
193 // TODO(chromium:1056170): Replace std::numeric_limits<size_t>::max() with a
194 // proper deadline when unified heap transitions to bytes-based deadline.
195 marking_done_ = marker_->AdvanceMarkingWithMaxDuration(
196 v8::base::TimeDelta::FromMillisecondsD(deadline_in_ms));
197 return marking_done_;
198 }
199
IsTracingDone()200 bool CppHeap::IsTracingDone() { return marking_done_; }
201
EnterFinalPause(EmbedderStackState stack_state)202 void CppHeap::EnterFinalPause(EmbedderStackState stack_state) {
203 marker_->EnterAtomicPause(stack_state);
204 if (compactor_.CancelIfShouldNotCompact(
205 UnifiedHeapMarker::MarkingConfig::MarkingType::kAtomic,
206 stack_state)) {
207 marker_->NotifyCompactionCancelled();
208 }
209 }
210
TraceEpilogue(TraceSummary * trace_summary)211 void CppHeap::TraceEpilogue(TraceSummary* trace_summary) {
212 CHECK(marking_done_);
213 {
214 // Weakness callbacks and pre-finalizers are forbidden from allocating
215 // objects.
216 cppgc::internal::ObjectAllocator::NoAllocationScope no_allocation_scope_(
217 object_allocator_);
218 marker_->LeaveAtomicPause();
219 prefinalizer_handler()->InvokePreFinalizers();
220 }
221 marker_.reset();
222 // TODO(chromium:1056170): replace build flag with dedicated flag.
223 #if DEBUG
224 UnifiedHeapMarkingVerifier verifier(*this);
225 verifier.Run(cppgc::Heap::StackState::kNoHeapPointers);
226 #endif
227 cppgc::internal::Sweeper::SweepingConfig::CompactableSpaceHandling
228 compactable_space_handling = compactor_.CompactSpacesIfEnabled();
229 {
230 NoGCScope no_gc(*this);
231 const cppgc::internal::Sweeper::SweepingConfig sweeping_config{
232 cppgc::internal::Sweeper::SweepingConfig::SweepingType::
233 kIncrementalAndConcurrent,
234 compactable_space_handling};
235 sweeper().Start(sweeping_config);
236 }
237 }
238
239 } // namespace internal
240 } // namespace v8
241