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 "src/heap/base/stack.h"
8 #include "src/heap/cppgc/garbage-collector.h"
9 #include "src/heap/cppgc/gc-invoker.h"
10 #include "src/heap/cppgc/heap-object-header.h"
11 #include "src/heap/cppgc/heap-visitor.h"
12 #include "src/heap/cppgc/marker.h"
13 #include "src/heap/cppgc/marking-verifier.h"
14 #include "src/heap/cppgc/prefinalizer-handler.h"
15
16 namespace cppgc {
17
18 namespace {
19
VerifyCustomSpaces(const std::vector<std::unique_ptr<CustomSpaceBase>> & custom_spaces)20 void VerifyCustomSpaces(
21 const std::vector<std::unique_ptr<CustomSpaceBase>>& custom_spaces) {
22 // Ensures that user-provided custom spaces have indices that form a sequence
23 // starting at 0.
24 #ifdef DEBUG
25 for (size_t i = 0; i < custom_spaces.size(); ++i) {
26 DCHECK_EQ(i, custom_spaces[i]->GetCustomSpaceIndex().value);
27 }
28 #endif // DEBUG
29 }
30
31 } // namespace
32
Create(std::shared_ptr<cppgc::Platform> platform,cppgc::Heap::HeapOptions options)33 std::unique_ptr<Heap> Heap::Create(std::shared_ptr<cppgc::Platform> platform,
34 cppgc::Heap::HeapOptions options) {
35 DCHECK(platform.get());
36 VerifyCustomSpaces(options.custom_spaces);
37 return std::make_unique<internal::Heap>(std::move(platform),
38 std::move(options));
39 }
40
ForceGarbageCollectionSlow(const char * source,const char * reason,Heap::StackState stack_state)41 void Heap::ForceGarbageCollectionSlow(const char* source, const char* reason,
42 Heap::StackState stack_state) {
43 internal::Heap::From(this)->CollectGarbage(
44 {internal::GarbageCollector::Config::CollectionType::kMajor, stack_state,
45 internal::GarbageCollector::Config::MarkingType::kAtomic,
46 internal::GarbageCollector::Config::SweepingType::kAtomic});
47 }
48
GetAllocationHandle()49 AllocationHandle& Heap::GetAllocationHandle() {
50 return internal::Heap::From(this)->object_allocator();
51 }
52
53 namespace internal {
54
55 namespace {
56
57 class Unmarker final : private HeapVisitor<Unmarker> {
58 friend class HeapVisitor<Unmarker>;
59
60 public:
Unmarker(RawHeap * heap)61 explicit Unmarker(RawHeap* heap) { Traverse(heap); }
62
63 private:
VisitHeapObjectHeader(HeapObjectHeader * header)64 bool VisitHeapObjectHeader(HeapObjectHeader* header) {
65 if (header->IsMarked()) header->Unmark();
66 return true;
67 }
68 };
69
CheckConfig(Heap::Config config)70 void CheckConfig(Heap::Config config) {
71 CHECK_WITH_MSG(
72 (config.collection_type != Heap::Config::CollectionType::kMinor) ||
73 (config.stack_state == Heap::Config::StackState::kNoHeapPointers),
74 "Minor GCs with stack is currently not supported");
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 gc_invoker_(this, platform_.get(), options.stack_support),
83 growing_(&gc_invoker_, stats_collector_.get(),
84 options.resource_constraints) {}
85
~Heap()86 Heap::~Heap() {
87 NoGCScope no_gc(*this);
88 // Finish already running GC if any, but don't finalize live objects.
89 sweeper_.FinishIfRunning();
90 }
91
CollectGarbage(Config config)92 void Heap::CollectGarbage(Config config) {
93 DCHECK_EQ(Config::MarkingType::kAtomic, config.marking_type);
94 CheckConfig(config);
95
96 if (in_no_gc_scope()) return;
97
98 config_ = config;
99
100 if (!gc_in_progress_) StartGarbageCollection(config);
101
102 DCHECK(marker_);
103
104 FinalizeGarbageCollection(config.stack_state);
105 }
106
StartIncrementalGarbageCollection(Config config)107 void Heap::StartIncrementalGarbageCollection(Config config) {
108 DCHECK_NE(Config::MarkingType::kAtomic, config.marking_type);
109 CheckConfig(config);
110
111 if (gc_in_progress_ || in_no_gc_scope()) return;
112
113 config_ = config;
114
115 StartGarbageCollection(config);
116 }
117
FinalizeIncrementalGarbageCollectionIfRunning(Config config)118 void Heap::FinalizeIncrementalGarbageCollectionIfRunning(Config config) {
119 if (!gc_in_progress_) return;
120
121 DCHECK(!in_no_gc_scope());
122
123 DCHECK_NE(Config::MarkingType::kAtomic, config_.marking_type);
124 config_ = config;
125 FinalizeGarbageCollection(config.stack_state);
126 }
127
StartGarbageCollection(Config config)128 void Heap::StartGarbageCollection(Config config) {
129 DCHECK(!gc_in_progress_);
130
131 DCHECK(!in_no_gc_scope());
132
133 // Finish sweeping in case it is still running.
134 sweeper_.FinishIfRunning();
135
136 gc_in_progress_ = true;
137 epoch_++;
138
139 #if defined(CPPGC_YOUNG_GENERATION)
140 if (config.collection_type == Config::CollectionType::kMajor)
141 Unmarker unmarker(&raw_heap());
142 #endif
143
144 const Marker::MarkingConfig marking_config{
145 config.collection_type, config.stack_state, config.marking_type};
146 marker_ = MarkerFactory::CreateAndStartMarking<Marker>(
147 AsBase(), platform_.get(), marking_config);
148 }
149
FinalizeGarbageCollection(Config::StackState stack_state)150 void Heap::FinalizeGarbageCollection(Config::StackState stack_state) {
151 DCHECK(gc_in_progress_);
152 DCHECK(!in_no_gc_scope());
153 config_.stack_state = stack_state;
154 DCHECK(marker_);
155 {
156 // Pre finalizers are forbidden from allocating objects. Note that this also
157 // guard atomic pause marking below, meaning that no internal method or
158 // external callbacks are allowed to allocate new objects.
159 ObjectAllocator::NoAllocationScope no_allocation_scope_(object_allocator_);
160 marker_->FinishMarking(stack_state);
161 prefinalizer_handler_->InvokePreFinalizers();
162 }
163 marker_.reset();
164 // TODO(chromium:1056170): replace build flag with dedicated flag.
165 #if DEBUG
166 MarkingVerifier verifier(*this);
167 verifier.Run(stack_state);
168 #endif
169 {
170 NoGCScope no_gc(*this);
171 const Sweeper::SweepingConfig sweeping_config{
172 config_.sweeping_type,
173 Sweeper::SweepingConfig::CompactableSpaceHandling::kSweep};
174 sweeper_.Start(sweeping_config);
175 }
176 gc_in_progress_ = false;
177 }
178
DisableHeapGrowingForTesting()179 void Heap::DisableHeapGrowingForTesting() { growing_.DisableForTesting(); }
180
181 } // namespace internal
182 } // namespace cppgc
183