v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
heap-base.cc
Go to the documentation of this file.
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
6
7#include <memory>
8
11#include "src/base/logging.h"
13#include "src/heap/base/stack.h"
28
29namespace cppgc {
30namespace internal {
31
32namespace {
33
34class ObjectSizeCounter : private HeapVisitor<ObjectSizeCounter> {
35 friend class HeapVisitor<ObjectSizeCounter>;
36
37 public:
38 size_t GetSize(RawHeap& heap) {
39 Traverse(heap);
40 return accumulated_size_;
41 }
42
43 private:
44 static size_t ObjectSize(const HeapObjectHeader& header) {
45 return ObjectView<>(header).Size();
46 }
47
48 bool VisitHeapObjectHeader(HeapObjectHeader& header) {
49 if (header.IsFree()) return true;
50 accumulated_size_ += ObjectSize(header);
51 return true;
52 }
53
55};
56
57#if defined(CPPGC_YOUNG_GENERATION)
58class AgeTableResetter final : protected HeapVisitor<AgeTableResetter> {
59 friend class HeapVisitor<AgeTableResetter>;
60
61 public:
62 AgeTableResetter() : age_table_(CagedHeapLocalData::Get().age_table) {}
63
64 void Run(RawHeap& raw_heap) { Traverse(raw_heap); }
65
66 protected:
67 bool VisitPage(BasePage& page) {
68 if (!page.contains_young_objects()) {
69#if defined(DEBUG)
70 DCHECK_EQ(AgeTable::Age::kOld,
71 age_table_.GetAgeForRange(
72 CagedHeap::OffsetFromAddress(page.PayloadStart()),
73 CagedHeap::OffsetFromAddress(page.PayloadEnd())));
74#endif // defined(DEBUG)
75 return true;
76 }
77
78 // Mark the entire page as old in the age-table.
79 // TODO(chromium:1029379): Consider decommitting pages once in a while.
80 age_table_.SetAgeForRange(CagedHeap::OffsetFromAddress(page.PayloadStart()),
81 CagedHeap::OffsetFromAddress(page.PayloadEnd()),
82 AgeTable::Age::kOld,
83 AgeTable::AdjacentCardsPolicy::kIgnore);
84 // Promote page.
85 page.set_as_containing_young_objects(false);
86 return true;
87 }
88
89 bool VisitNormalPage(NormalPage& page) { return VisitPage(page); }
90 bool VisitLargePage(LargePage& page) { return VisitPage(page); }
91
92 private:
93 AgeTable& age_table_;
94};
95#endif // defined(CPPGC_YOUNG_GENERATION)
96
97} // namespace
98
100 std::shared_ptr<cppgc::Platform> platform,
101 const std::vector<std::unique_ptr<CustomSpaceBase>>& custom_spaces,
102 StackSupport stack_support, MarkingType marking_support,
103 SweepingType sweeping_support, GarbageCollector& garbage_collector)
104 : raw_heap_(this, custom_spaces),
105 platform_(std::move(platform)),
106 oom_handler_(std::make_unique<FatalOutOfMemoryHandler>(this)),
107#if defined(LEAK_SANITIZER)
108 lsan_page_allocator_(std::make_unique<v8::base::LsanPageAllocator>(
109 platform_->GetPageAllocator())),
110#endif // LEAK_SANITIZER
111 page_backend_(InitializePageBackend(*page_allocator())),
112 stats_collector_(std::make_unique<StatsCollector>(platform_.get())),
113 stack_(std::make_unique<heap::base::Stack>()),
114 prefinalizer_handler_(std::make_unique<PreFinalizerHandler>(*this)),
115 compactor_(raw_heap_),
116 object_allocator_(raw_heap_, *page_backend_, *stats_collector_,
117 *prefinalizer_handler_, *oom_handler_,
118 garbage_collector),
119 sweeper_(*this),
120 strong_persistent_region_(*this, *oom_handler_),
121 weak_persistent_region_(*this, *oom_handler_),
122 strong_cross_thread_persistent_region_(*oom_handler_),
123 weak_cross_thread_persistent_region_(*oom_handler_),
124#if defined(CPPGC_YOUNG_GENERATION)
125 remembered_set_(*this),
126#endif // defined(CPPGC_YOUNG_GENERATION)
127 stack_support_(stack_support),
128 marking_support_(marking_support),
129 sweeping_support_(sweeping_support) {
133}
134
135HeapBase::~HeapBase() = default;
136
138#if defined(LEAK_SANITIZER)
139 return lsan_page_allocator_.get();
140#else // !LEAK_SANITIZER
141 return platform_->GetPageAllocator();
142#endif // !LEAK_SANITIZER
143}
144
146 return ObjectSizeCounter().GetSize(const_cast<RawHeap&>(raw_heap()));
147}
148
149// static
150std::unique_ptr<PageBackend> HeapBase::InitializePageBackend(
151 PageAllocator& allocator) {
152#if defined(CPPGC_CAGED_HEAP)
153 auto& caged_heap = CagedHeap::Instance();
154 return std::make_unique<PageBackend>(caged_heap.page_allocator(),
155 caged_heap.page_allocator());
156#else // !CPPGC_CAGED_HEAP
157 return std::make_unique<PageBackend>(allocator, allocator);
158#endif // !CPPGC_CAGED_HEAP
159}
160
162#ifdef CPPGC_ALLOW_ALLOCATIONS_IN_PREFINALIZERS
163 // Allocations in pre finalizers should not trigger another GC.
165#else
166 // Pre finalizers are forbidden from allocating objects.
168#endif // CPPGC_ALLOW_ALLOCATIONS_IN_PREFINALIZERS
169 prefinalizer_handler_->InvokePreFinalizers();
170 return prefinalizer_handler_->ExtractBytesAllocatedInPrefinalizers();
171}
172
173#if defined(CPPGC_YOUNG_GENERATION)
174void HeapBase::EnableGenerationalGC() {
177#if defined(CPPGC_CAGED_HEAP)
178 // Commit storage for the age table.
180#endif // defined(CPPGC_CAGED_HEAP)
181 // Notify the global flag that the write barrier must always be enabled.
182 YoungGenerationEnabler::Enable();
183 // Enable young generation for the current heap.
185 // Assume everything that has so far been allocated is young.
187}
188
189void HeapBase::ResetRememberedSet() {
191 class AllLABsAreEmpty final : protected HeapVisitor<AllLABsAreEmpty> {
192 friend class HeapVisitor<AllLABsAreEmpty>;
193
194 public:
195 explicit AllLABsAreEmpty(RawHeap& raw_heap) { Traverse(raw_heap); }
196
197 bool value() const { return !some_lab_is_set_; }
198
199 protected:
200 bool VisitNormalPageSpace(NormalPageSpace& space) {
201 some_lab_is_set_ |=
202 static_cast<bool>(space.linear_allocation_buffer().size());
203 return true;
204 }
205
206 private:
207 bool some_lab_is_set_ = false;
208 };
209 DCHECK(AllLABsAreEmpty(raw_heap()).value());
210
212 DCHECK(remembered_set_.IsEmpty());
213 return;
214 }
215
216 AgeTableResetter age_table_resetter;
217 age_table_resetter.Run(raw_heap());
218
219 remembered_set_.Reset();
220}
221
222#endif // defined(CPPGC_YOUNG_GENERATION)
223
225 CHECK(!IsMarking());
227 // Cannot use IsGCAllowed() as `Terminate()` will be invoked after detaching
228 // which implies GC is prohibited at this point.
229 CHECK(!sweeper().IsSweepingOnMutatorThread());
230
232
233#if defined(CPPGC_YOUNG_GENERATION)
237 YoungGenerationEnabler::Disable();
238 }
239#endif // defined(CPPGC_YOUNG_GENERATION)
240
241 constexpr size_t kMaxTerminationGCs = 20;
242 size_t gc_count = 0;
243 bool more_termination_gcs_needed = false;
244 do {
245 // Clear root sets.
248 {
252 }
253
254#if defined(CPPGC_YOUNG_GENERATION)
256 // Unmark the heap so that the sweeper destructs all objects.
257 // TODO(chromium:1029379): Merge two heap iterations (unmarking +
258 // sweeping) into forced finalization.
259 SequentialUnmarker unmarker(raw_heap());
260 }
261#endif // defined(CPPGC_YOUNG_GENERATION)
262
263 in_atomic_pause_ = true;
265 GCConfig::MarkingType::kAtomic,
266 GCConfig::IsForcedGC::kForced);
270 // TODO(chromium:1029379): Prefinalizers may black-allocate objects (under a
271 // compile-time option). Run sweeping with forced finalization here.
272 sweeper().Start({SweepingConfig::SweepingType::kAtomic,
274 in_atomic_pause_ = false;
276 more_termination_gcs_needed =
278 weak_persistent_region_.NodesInUse() || [this]() {
282 }();
283 gc_count++;
284 } while (more_termination_gcs_needed && (gc_count < kMaxTerminationGCs));
285
288 {
292 }
293 CHECK_LE(gc_count, kMaxTerminationGCs);
294
297}
298
300 HeapStatistics::DetailLevel detail_level) {
301 if (detail_level == HeapStatistics::DetailLevel::kBrief) {
302 const size_t pooled_memory = page_backend_->page_pool().PooledMemory();
303 const size_t committed_memory =
304 stats_collector_->allocated_memory_size() + pooled_memory;
305 const size_t resident_memory =
306 stats_collector_->resident_memory_size() + pooled_memory;
307
308 return {committed_memory,
309 resident_memory,
310 stats_collector_->allocated_object_size(),
311 pooled_memory,
313 {},
314 {}};
315 }
316
320}
321
323 size_t size_including_header) {
324 for (const auto& listener : move_listeners_) {
325 listener->OnMove(from, to, size_including_header);
326 }
327}
328
330 // Registering the same listener multiple times would work, but probably
331 // indicates a mistake in the component requesting the registration.
332 DCHECK_EQ(std::find(move_listeners_.begin(), move_listeners_.end(), listener),
333 move_listeners_.end());
334 move_listeners_.push_back(listener);
335}
336
338 auto it =
339 std::remove(move_listeners_.begin(), move_listeners_.end(), listener);
340 move_listeners_.erase(it, move_listeners_.end());
341}
342
343bool HeapBase::IsGCForbidden() const { return disallow_gc_scope_ > 0; }
344
346 // GC is prohibited in a GC forbidden scope, or when currently sweeping an
347 // object.
349}
350
354
361
365
366} // namespace internal
367} // namespace cppgc
bool is_young_generation_enabled_
Definition heap-handle.h:39
V8_INLINE bool is_young_generation_enabled() const
Definition heap-handle.h:34
friend class internal::HeapBase
Definition heap-handle.h:41
MarkingType
Definition heap.h:60
StackSupport
Definition heap.h:45
SweepingType
Definition heap.h:80
virtual PageAllocator * GetPageAllocator()=0
static void CommitAgeTable(PageAllocator &platform_allocator)
static CagedHeap & Instance()
Definition caged-heap.cc:93
const HeapObjectNameForUnnamedObject saved_heap_object_name_value_
Definition heap-base.h:357
void RegisterMoveListener(MoveListener *listener)
Definition heap-base.cc:329
void CallMoveListeners(Address from, Address to, size_t size_including_header)
Definition heap-base.cc:322
std::vector< MoveListener * > move_listeners_
Definition heap-base.h:343
std::unique_ptr< StatsCollector > stats_collector_
Definition heap-base.h:307
std::unique_ptr< heap::base::Stack > stack_
Definition heap-base.h:308
PageAllocator * page_allocator() const
Definition heap-base.cc:137
PersistentRegion weak_persistent_region_
Definition heap-base.h:317
ObjectAllocator object_allocator_
Definition heap-base.h:313
HeapStatistics CollectStatistics(HeapStatistics::DetailLevel)
Definition heap-base.cc:299
size_t ObjectPayloadSize() const
Definition heap-base.cc:145
std::shared_ptr< cppgc::Platform > platform_
Definition heap-base.h:295
std::unique_ptr< PreFinalizerHandler > prefinalizer_handler_
Definition heap-base.h:309
virtual bool CurrentThreadIsHeapThread() const
Definition heap-base.cc:351
bool generational_gc_supported() const
Definition heap-base.h:218
bool in_atomic_pause() const
Definition heap-base.h:188
std::unique_ptr< PageBackend > page_backend_
Definition heap-base.h:302
static std::unique_ptr< PageBackend > InitializePageBackend(PageAllocator &allocator)
Definition heap-base.cc:150
StatsCollector * stats_collector()
Definition heap-base.h:118
CrossThreadPersistentRegion weak_cross_thread_persistent_region_
Definition heap-base.h:319
CrossThreadPersistentRegion strong_cross_thread_persistent_region_
Definition heap-base.h:318
virtual bool IsGCForbidden() const
Definition heap-base.cc:343
void set_name_of_unnamed_object(HeapObjectNameForUnnamedObject value)
Definition heap-base.h:236
void UnregisterMoveListener(MoveListener *listener)
Definition heap-base.cc:337
virtual bool IsGCAllowed() const
Definition heap-base.cc:345
PersistentRegion strong_persistent_region_
Definition heap-base.h:316
ProcessHeapStatisticsUpdater::AllocationObserverImpl allocation_observer_for_PROCESS_HEAP_STATISTICS_
Definition heap-base.h:322
ObjectAllocator & object_allocator()
Definition heap-base.h:135
bool in_no_gc_scope() const
Definition heap-base.h:276
void RegisterObserver(AllocationObserver *)
void NotifyMarkingCompleted(size_t marked_bytes)
void NotifyMarkingStarted(CollectionType, MarkingType, IsForcedGC)
bool IsSweepingOnMutatorThread() const
Definition sweeper.cc:1676
void Start(SweepingConfig)
Definition sweeper.cc:1661
void SetStackStart()
Definition stack.h:38
static int GetCurrentThreadId()
Definition platform.cc:29
v8::Platform * platform_
Definition cpp-heap.cc:193
StatsCollector * stats_collector_
Definition sweeper.cc:595
size_t accumulated_size_
Definition heap-base.cc:54
bool defined
uint8_t * Address
Definition globals.h:17
STL namespace.
#define CHECK(condition)
Definition logging.h:124
#define CHECK_LE(lhs, rhs)
#define CHECK_EQ(lhs, rhs)
#define DCHECK(condition)
Definition logging.h:482
#define DCHECK_EQ(v1, v2)
Definition logging.h:485
Heap * heap_
std::unique_ptr< ValueMirror > value