Commit 3cb46341 authored by Anton Bikineev's avatar Anton Bikineev Committed by V8 LUCI CQ

cppgc: young-gen: Use ref-counting scheme to enable the barrier

The CL uses the different scheme to enable the generational barrier. The
separate global counter (is_enabled_) keeps track of the number of heaps
that enable generational GC. If at least one of the heaps enables the
generational GC, the counter will enable the write barrier. Technically,
the counter could be merged with WriteBarrier::is_enabled_, but having a
separate variable allows us to keep DCHECKs if generational barrier is
enabled.

Bug: chromium:1029379
Change-Id: Iafaa76f96acb18a73f8bde7231434e68c04cb683
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3616518Reviewed-by: 's avatarMichael Lippautz <mlippautz@chromium.org>
Commit-Queue: Anton Bikineev <bikineev@chromium.org>
Cr-Commit-Position: refs/heads/main@{#80281}
parent 671dcfac
...@@ -663,10 +663,9 @@ void CppHeap::TraceEpilogue() { ...@@ -663,10 +663,9 @@ void CppHeap::TraceEpilogue() {
#if defined(CPPGC_YOUNG_GENERATION) #if defined(CPPGC_YOUNG_GENERATION)
// Check if the young generation was enabled via flag. // Check if the young generation was enabled via flag.
if (FLAG_cppgc_young_generation) if (FLAG_cppgc_young_generation) EnableGenerationalGC();
cppgc::internal::YoungGenerationEnabler::Enable();
ResetRememberedSetAndEnableMinorGCIfNeeded(); ResetRememberedSet();
#endif // defined(CPPGC_YOUNG_GENERATION) #endif // defined(CPPGC_YOUNG_GENERATION)
{ {
......
...@@ -122,7 +122,16 @@ size_t HeapBase::ExecutePreFinalizers() { ...@@ -122,7 +122,16 @@ size_t HeapBase::ExecutePreFinalizers() {
} }
#if defined(CPPGC_YOUNG_GENERATION) #if defined(CPPGC_YOUNG_GENERATION)
void HeapBase::ResetRememberedSetAndEnableMinorGCIfNeeded() { void HeapBase::EnableGenerationalGC() {
DCHECK(in_atomic_pause());
// Notify the global flag that the write barrier must always be enabled.
YoungGenerationEnabler::Enable();
// Enable young generation for the current heap.
caged_heap().EnableGenerationalGC();
generation_support_ = GenerationSupport::kYoungAndOldGenerations;
}
void HeapBase::ResetRememberedSet() {
DCHECK(in_atomic_pause()); DCHECK(in_atomic_pause());
class AllLABsAreEmpty final : protected HeapVisitor<AllLABsAreEmpty> { class AllLABsAreEmpty final : protected HeapVisitor<AllLABsAreEmpty> {
friend class HeapVisitor<AllLABsAreEmpty>; friend class HeapVisitor<AllLABsAreEmpty>;
...@@ -144,27 +153,14 @@ void HeapBase::ResetRememberedSetAndEnableMinorGCIfNeeded() { ...@@ -144,27 +153,14 @@ void HeapBase::ResetRememberedSetAndEnableMinorGCIfNeeded() {
}; };
DCHECK(AllLABsAreEmpty(raw_heap()).value()); DCHECK(AllLABsAreEmpty(raw_heap()).value());
if (generational_gc_supported()) { if (!generational_gc_supported()) {
caged_heap().local_data().age_table.Reset(&caged_heap().allocator()); DCHECK(remembered_set_.IsEmpty());
remembered_set_.Reset();
return; return;
} }
DCHECK(remembered_set_.IsEmpty()); caged_heap().local_data().age_table.Reset(&caged_heap().allocator());
// Check if the young generation was enabled since the last cycle. remembered_set_.Reset();
if (YoungGenerationEnabler::IsEnabled()) { return;
// Enable young generation for the current heap.
caged_heap().EnableGenerationalGC();
generation_support_ = GenerationSupport::kYoungAndOldGenerations;
}
}
void HeapBase::DisableGenerationalGCForTesting() {
DCHECK(caged_heap().local_data().is_young_generation_enabled);
DCHECK_EQ(GenerationSupport::kYoungAndOldGenerations, generation_support_);
caged_heap().local_data().is_young_generation_enabled = false;
generation_support_ = GenerationSupport::kSingleGeneration;
} }
#endif // defined(CPPGC_YOUNG_GENERATION) #endif // defined(CPPGC_YOUNG_GENERATION)
...@@ -175,6 +171,17 @@ void HeapBase::Terminate() { ...@@ -175,6 +171,17 @@ void HeapBase::Terminate() {
sweeper().FinishIfRunning(); sweeper().FinishIfRunning();
#if defined(CPPGC_YOUNG_GENERATION)
if (generational_gc_supported()) {
DCHECK(caged_heap().local_data().is_young_generation_enabled);
DCHECK_EQ(GenerationSupport::kYoungAndOldGenerations, generation_support_);
caged_heap().local_data().is_young_generation_enabled = false;
generation_support_ = GenerationSupport::kSingleGeneration;
YoungGenerationEnabler::Disable();
}
#endif // defined(CPPGC_YOUNG_GENERATION)
constexpr size_t kMaxTerminationGCs = 20; constexpr size_t kMaxTerminationGCs = 20;
size_t gc_count = 0; size_t gc_count = 0;
bool more_termination_gcs_needed = false; bool more_termination_gcs_needed = false;
......
...@@ -224,10 +224,6 @@ class V8_EXPORT_PRIVATE HeapBase : public cppgc::HeapHandle { ...@@ -224,10 +224,6 @@ class V8_EXPORT_PRIVATE HeapBase : public cppgc::HeapHandle {
return supported; return supported;
} }
#if defined(CPPGC_YOUNG_GENERATION)
void DisableGenerationalGCForTesting();
#endif // defined(CPPGC_YOUNG_GENERATION)
protected: protected:
enum class GenerationSupport : uint8_t { enum class GenerationSupport : uint8_t {
kSingleGeneration, kSingleGeneration,
...@@ -246,7 +242,8 @@ class V8_EXPORT_PRIVATE HeapBase : public cppgc::HeapHandle { ...@@ -246,7 +242,8 @@ class V8_EXPORT_PRIVATE HeapBase : public cppgc::HeapHandle {
size_t ExecutePreFinalizers(); size_t ExecutePreFinalizers();
#if defined(CPPGC_YOUNG_GENERATION) #if defined(CPPGC_YOUNG_GENERATION)
void ResetRememberedSetAndEnableMinorGCIfNeeded(); void EnableGenerationalGC();
void ResetRememberedSet();
#endif // defined(CPPGC_YOUNG_GENERATION) #endif // defined(CPPGC_YOUNG_GENERATION)
PageAllocator* page_allocator() const; PageAllocator* page_allocator() const;
......
...@@ -190,7 +190,10 @@ void Heap::FinalizeGarbageCollection(Config::StackState stack_state) { ...@@ -190,7 +190,10 @@ void Heap::FinalizeGarbageCollection(Config::StackState stack_state) {
USE(bytes_allocated_in_prefinalizers); USE(bytes_allocated_in_prefinalizers);
#if defined(CPPGC_YOUNG_GENERATION) #if defined(CPPGC_YOUNG_GENERATION)
ResetRememberedSetAndEnableMinorGCIfNeeded(); if (generational_gc_enabled_) {
HeapBase::EnableGenerationalGC();
}
ResetRememberedSet();
#endif // defined(CPPGC_YOUNG_GENERATION) #endif // defined(CPPGC_YOUNG_GENERATION)
subtle::NoGarbageCollectionScope no_gc(*this); subtle::NoGarbageCollectionScope no_gc(*this);
...@@ -203,6 +206,12 @@ void Heap::FinalizeGarbageCollection(Config::StackState stack_state) { ...@@ -203,6 +206,12 @@ void Heap::FinalizeGarbageCollection(Config::StackState stack_state) {
sweeper_.NotifyDoneIfNeeded(); sweeper_.NotifyDoneIfNeeded();
} }
void Heap::EnableGenerationalGC() {
DCHECK(!IsMarking());
DCHECK(!generational_gc_enabled_);
generational_gc_enabled_ = true;
}
void Heap::DisableHeapGrowingForTesting() { growing_.DisableForTesting(); } void Heap::DisableHeapGrowingForTesting() { growing_.DisableForTesting(); }
void Heap::FinalizeIncrementalGarbageCollectionIfNeeded( void Heap::FinalizeIncrementalGarbageCollectionIfNeeded(
......
...@@ -41,6 +41,8 @@ class V8_EXPORT_PRIVATE Heap final : public HeapBase, ...@@ -41,6 +41,8 @@ class V8_EXPORT_PRIVATE Heap final : public HeapBase,
return HeapBase::override_stack_state(); return HeapBase::override_stack_state();
} }
void EnableGenerationalGC();
void DisableHeapGrowingForTesting(); void DisableHeapGrowingForTesting();
private: private:
...@@ -55,6 +57,7 @@ class V8_EXPORT_PRIVATE Heap final : public HeapBase, ...@@ -55,6 +57,7 @@ class V8_EXPORT_PRIVATE Heap final : public HeapBase,
Config config_; Config config_;
GCInvoker gc_invoker_; GCInvoker gc_invoker_;
HeapGrowing growing_; HeapGrowing growing_;
bool generational_gc_enabled_ = false;
size_t epoch_ = 0; size_t epoch_ = 0;
}; };
......
...@@ -25,7 +25,7 @@ AtomicEntryFlag WriteBarrier::write_barrier_enabled_; ...@@ -25,7 +25,7 @@ AtomicEntryFlag WriteBarrier::write_barrier_enabled_;
#if defined(CPPGC_YOUNG_GENERATION) #if defined(CPPGC_YOUNG_GENERATION)
// static // static
bool YoungGenerationEnabler::is_enabled_; size_t YoungGenerationEnabler::is_enabled_;
// static // static
v8::base::LeakyObject<v8::base::Mutex> YoungGenerationEnabler::mutex_; v8::base::LeakyObject<v8::base::Mutex> YoungGenerationEnabler::mutex_;
#endif // defined(CPPGC_YOUNG_GENERATION) #endif // defined(CPPGC_YOUNG_GENERATION)
...@@ -209,18 +209,19 @@ bool WriteBarrierTypeForCagedHeapPolicy::IsMarking( ...@@ -209,18 +209,19 @@ bool WriteBarrierTypeForCagedHeapPolicy::IsMarking(
#if defined(CPPGC_YOUNG_GENERATION) #if defined(CPPGC_YOUNG_GENERATION)
void YoungGenerationEnabler::Enable() { void YoungGenerationEnabler::Enable() {
v8::base::LockGuard _(mutex_.get()); v8::base::LockGuard _(mutex_.get());
if (is_enabled_) return; if (++is_enabled_ == 1) {
// Enter the flag so that the check in the write barrier will always trigger // Enter the flag so that the check in the write barrier will always trigger
// when young generation is enabled. // when young generation is enabled.
WriteBarrier::FlagUpdater::Enter(); WriteBarrier::FlagUpdater::Enter();
is_enabled_ = true; }
} }
void YoungGenerationEnabler::DisableForTesting() { void YoungGenerationEnabler::Disable() {
v8::base::LockGuard _(mutex_.get()); v8::base::LockGuard _(mutex_.get());
if (!is_enabled_) return; DCHECK_LT(0, is_enabled_);
WriteBarrier::FlagUpdater::Exit(); if (--is_enabled_ == 0) {
is_enabled_ = false; WriteBarrier::FlagUpdater::Exit();
}
} }
bool YoungGenerationEnabler::IsEnabled() { bool YoungGenerationEnabler::IsEnabled() {
......
...@@ -25,14 +25,14 @@ class WriteBarrier::FlagUpdater final { ...@@ -25,14 +25,14 @@ class WriteBarrier::FlagUpdater final {
class V8_EXPORT_PRIVATE YoungGenerationEnabler final { class V8_EXPORT_PRIVATE YoungGenerationEnabler final {
public: public:
static void Enable(); static void Enable();
static void DisableForTesting(); static void Disable();
static bool IsEnabled(); static bool IsEnabled();
private: private:
YoungGenerationEnabler() = delete; YoungGenerationEnabler() = delete;
static bool is_enabled_; static size_t is_enabled_;
static v8::base::LeakyObject<v8::base::Mutex> mutex_; static v8::base::LeakyObject<v8::base::Mutex> mutex_;
}; };
#endif // defined(CPPGC_YOUNG_GENERATION) #endif // defined(CPPGC_YOUNG_GENERATION)
......
...@@ -67,16 +67,13 @@ class MinorGCTest : public testing::TestWithHeap { ...@@ -67,16 +67,13 @@ class MinorGCTest : public testing::TestWithHeap {
MinorGCTest() : testing::TestWithHeap() { MinorGCTest() : testing::TestWithHeap() {
// Enable young generation flag and run GC. After the first run the heap // Enable young generation flag and run GC. After the first run the heap
// will enable minor GC. // will enable minor GC.
YoungGenerationEnabler::Enable(); Heap::From(GetHeap())->EnableGenerationalGC();
CollectMajor(); CollectMajor();
SimpleGCedBase::destructed_objects = 0; SimpleGCedBase::destructed_objects = 0;
} }
~MinorGCTest() override { ~MinorGCTest() override { Heap::From(GetHeap())->Terminate(); }
YoungGenerationEnabler::DisableForTesting();
Heap::From(GetHeap())->DisableGenerationalGCForTesting();
}
static size_t DestructedObjects() { static size_t DestructedObjects() {
return SimpleGCedBase::destructed_objects; return SimpleGCedBase::destructed_objects;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment