• 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/heap.h"
6 
7 #include "include/cppgc/heap-consistency.h"
8 #include "src/heap/base/stack.h"
9 #include "src/heap/cppgc/garbage-collector.h"
10 #include "src/heap/cppgc/gc-invoker.h"
11 #include "src/heap/cppgc/heap-object-header.h"
12 #include "src/heap/cppgc/heap-visitor.h"
13 #include "src/heap/cppgc/marker.h"
14 #include "src/heap/cppgc/marking-verifier.h"
15 #include "src/heap/cppgc/prefinalizer-handler.h"
16 #include "src/heap/cppgc/stats-collector.h"
17 #include "src/heap/cppgc/sweeper.h"
18 #include "src/heap/cppgc/unmarker.h"
19 
20 namespace cppgc {
21 
22 namespace {
23 
VerifyCustomSpaces(const std::vector<std::unique_ptr<CustomSpaceBase>> & custom_spaces)24 void VerifyCustomSpaces(
25     const std::vector<std::unique_ptr<CustomSpaceBase>>& custom_spaces) {
26   // Ensures that user-provided custom spaces have indices that form a sequence
27   // starting at 0.
28 #ifdef DEBUG
29   for (size_t i = 0; i < custom_spaces.size(); ++i) {
30     DCHECK_EQ(i, custom_spaces[i]->GetCustomSpaceIndex().value);
31   }
32 #endif  // DEBUG
33 }
34 
35 }  // namespace
36 
Create(std::shared_ptr<cppgc::Platform> platform,cppgc::Heap::HeapOptions options)37 std::unique_ptr<Heap> Heap::Create(std::shared_ptr<cppgc::Platform> platform,
38                                    cppgc::Heap::HeapOptions options) {
39   DCHECK(platform.get());
40   VerifyCustomSpaces(options.custom_spaces);
41   return std::make_unique<internal::Heap>(std::move(platform),
42                                           std::move(options));
43 }
44 
ForceGarbageCollectionSlow(const char * source,const char * reason,Heap::StackState stack_state)45 void Heap::ForceGarbageCollectionSlow(const char* source, const char* reason,
46                                       Heap::StackState stack_state) {
47   internal::Heap::From(this)->CollectGarbage(
48       {internal::GarbageCollector::Config::CollectionType::kMajor, stack_state,
49        MarkingType::kAtomic, SweepingType::kAtomic,
50        internal::GarbageCollector::Config::FreeMemoryHandling::
51            kDiscardWherePossible,
52        internal::GarbageCollector::Config::IsForcedGC::kForced});
53 }
54 
GetAllocationHandle()55 AllocationHandle& Heap::GetAllocationHandle() {
56   return internal::Heap::From(this)->object_allocator();
57 }
58 
GetHeapHandle()59 HeapHandle& Heap::GetHeapHandle() { return *internal::Heap::From(this); }
60 
61 namespace internal {
62 
63 namespace {
64 
CheckConfig(Heap::Config config,HeapBase::MarkingType marking_support,HeapBase::SweepingType sweeping_support)65 void CheckConfig(Heap::Config config, HeapBase::MarkingType marking_support,
66                  HeapBase::SweepingType sweeping_support) {
67   CHECK_WITH_MSG(
68       (config.collection_type != Heap::Config::CollectionType::kMinor) ||
69           (config.stack_state == Heap::Config::StackState::kNoHeapPointers),
70       "Minor GCs with stack is currently not supported");
71   CHECK_LE(static_cast<int>(config.marking_type),
72            static_cast<int>(marking_support));
73   CHECK_LE(static_cast<int>(config.sweeping_type),
74            static_cast<int>(sweeping_support));
75 }
76 
77 }  // namespace
78 
Heap(std::shared_ptr<cppgc::Platform> platform,cppgc::Heap::HeapOptions options)79 Heap::Heap(std::shared_ptr<cppgc::Platform> platform,
80            cppgc::Heap::HeapOptions options)
81     : HeapBase(platform, options.custom_spaces, options.stack_support,
82                options.marking_support, options.sweeping_support),
83       gc_invoker_(this, platform_.get(), options.stack_support),
84       growing_(&gc_invoker_, stats_collector_.get(),
85                options.resource_constraints, options.marking_support,
86                options.sweeping_support) {
87   CHECK_IMPLIES(options.marking_support != HeapBase::MarkingType::kAtomic,
88                 platform_->GetForegroundTaskRunner());
89   CHECK_IMPLIES(options.sweeping_support != HeapBase::SweepingType::kAtomic,
90                 platform_->GetForegroundTaskRunner());
91 }
92 
~Heap()93 Heap::~Heap() {
94   // Gracefully finish already running GC if any, but don't finalize live
95   // objects.
96   FinalizeIncrementalGarbageCollectionIfRunning(
97       {Config::CollectionType::kMajor,
98        Config::StackState::kMayContainHeapPointers,
99        Config::MarkingType::kAtomic, Config::SweepingType::kAtomic});
100   {
101     subtle::NoGarbageCollectionScope no_gc(*this);
102     sweeper_.FinishIfRunning();
103   }
104 }
105 
CollectGarbage(Config config)106 void Heap::CollectGarbage(Config config) {
107   DCHECK_EQ(Config::MarkingType::kAtomic, config.marking_type);
108   CheckConfig(config, marking_support_, sweeping_support_);
109 
110   if (in_no_gc_scope()) return;
111 
112   config_ = config;
113 
114   if (!IsMarking()) {
115     StartGarbageCollection(config);
116   }
117   DCHECK(IsMarking());
118   FinalizeGarbageCollection(config.stack_state);
119 }
120 
StartIncrementalGarbageCollection(Config config)121 void Heap::StartIncrementalGarbageCollection(Config config) {
122   DCHECK_NE(Config::MarkingType::kAtomic, config.marking_type);
123   DCHECK_NE(marking_support_, Config::MarkingType::kAtomic);
124   CheckConfig(config, marking_support_, sweeping_support_);
125 
126   if (IsMarking() || in_no_gc_scope()) return;
127 
128   config_ = config;
129 
130   StartGarbageCollection(config);
131 }
132 
FinalizeIncrementalGarbageCollectionIfRunning(Config config)133 void Heap::FinalizeIncrementalGarbageCollectionIfRunning(Config config) {
134   CheckConfig(config, marking_support_, sweeping_support_);
135 
136   if (!IsMarking()) return;
137 
138   DCHECK(!in_no_gc_scope());
139 
140   DCHECK_NE(Config::MarkingType::kAtomic, config_.marking_type);
141   config_ = config;
142   FinalizeGarbageCollection(config.stack_state);
143 }
144 
StartGarbageCollection(Config config)145 void Heap::StartGarbageCollection(Config config) {
146   DCHECK(!IsMarking());
147   DCHECK(!in_no_gc_scope());
148 
149   // Finish sweeping in case it is still running.
150   sweeper_.FinishIfRunning();
151 
152   epoch_++;
153 
154 #if defined(CPPGC_YOUNG_GENERATION)
155   if (config.collection_type == Config::CollectionType::kMajor)
156     SequentialUnmarker unmarker(raw_heap());
157 #endif  // defined(CPPGC_YOUNG_GENERATION)
158 
159   const Marker::MarkingConfig marking_config{
160       config.collection_type, config.stack_state, config.marking_type,
161       config.is_forced_gc};
162   marker_ = std::make_unique<Marker>(AsBase(), platform_.get(), marking_config);
163   marker_->StartMarking();
164 }
165 
FinalizeGarbageCollection(Config::StackState stack_state)166 void Heap::FinalizeGarbageCollection(Config::StackState stack_state) {
167   DCHECK(IsMarking());
168   DCHECK(!in_no_gc_scope());
169   CHECK(!in_disallow_gc_scope());
170   config_.stack_state = stack_state;
171   SetStackEndOfCurrentGC(v8::base::Stack::GetCurrentStackPosition());
172   in_atomic_pause_ = true;
173   {
174     // This guards atomic pause marking, meaning that no internal method or
175     // external callbacks are allowed to allocate new objects.
176     cppgc::subtle::DisallowGarbageCollectionScope no_gc_scope(*this);
177     marker_->FinishMarking(config_.stack_state);
178   }
179   marker_.reset();
180   const size_t bytes_allocated_in_prefinalizers = ExecutePreFinalizers();
181 #if CPPGC_VERIFY_HEAP
182   MarkingVerifier verifier(*this, config_.collection_type);
183   verifier.Run(config_.stack_state, stack_end_of_current_gc(),
184                stats_collector()->marked_bytes_on_current_cycle() +
185                    bytes_allocated_in_prefinalizers);
186 #endif  // CPPGC_VERIFY_HEAP
187 #ifndef CPPGC_ALLOW_ALLOCATIONS_IN_PREFINALIZERS
188   DCHECK_EQ(0u, bytes_allocated_in_prefinalizers);
189 #endif
190   USE(bytes_allocated_in_prefinalizers);
191 
192 #if defined(CPPGC_YOUNG_GENERATION)
193   ResetRememberedSet();
194 #endif  // defined(CPPGC_YOUNG_GENERATION)
195 
196   subtle::NoGarbageCollectionScope no_gc(*this);
197   const Sweeper::SweepingConfig sweeping_config{
198       config_.sweeping_type,
199       Sweeper::SweepingConfig::CompactableSpaceHandling::kSweep,
200       config_.free_memory_handling};
201   sweeper_.Start(sweeping_config);
202   in_atomic_pause_ = false;
203   sweeper_.NotifyDoneIfNeeded();
204 }
205 
DisableHeapGrowingForTesting()206 void Heap::DisableHeapGrowingForTesting() { growing_.DisableForTesting(); }
207 
FinalizeIncrementalGarbageCollectionIfNeeded(Config::StackState stack_state)208 void Heap::FinalizeIncrementalGarbageCollectionIfNeeded(
209     Config::StackState stack_state) {
210   StatsCollector::EnabledScope stats_scope(
211       stats_collector(), StatsCollector::kMarkIncrementalFinalize);
212   FinalizeGarbageCollection(stack_state);
213 }
214 
StartIncrementalGarbageCollectionForTesting()215 void Heap::StartIncrementalGarbageCollectionForTesting() {
216   DCHECK(!IsMarking());
217   DCHECK(!in_no_gc_scope());
218   StartGarbageCollection({Config::CollectionType::kMajor,
219                           Config::StackState::kNoHeapPointers,
220                           Config::MarkingType::kIncrementalAndConcurrent,
221                           Config::SweepingType::kIncrementalAndConcurrent});
222 }
223 
FinalizeIncrementalGarbageCollectionForTesting(EmbedderStackState stack_state)224 void Heap::FinalizeIncrementalGarbageCollectionForTesting(
225     EmbedderStackState stack_state) {
226   DCHECK(!in_no_gc_scope());
227   DCHECK(IsMarking());
228   FinalizeGarbageCollection(stack_state);
229   sweeper_.FinishIfRunning();
230 }
231 
232 }  // namespace internal
233 }  // namespace cppgc
234