cppgc: young-gen: Fix compilation and tests with cppgc_enable_young_gen
The CL prepares the sources and the tests for enabling cppgc_enable_young_generation by default. The static initializer in YoungGenerationEnabler (due to v8::base::Mutex) changed to be lazy. The tests are now checking the runtime flag. Bug: chromium:1029379 Change-Id: I1497a3dd2b8d62c1acd48496821f07324b7944d5 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3616726 Reviewed-by: Michael Lippautz <mlippautz@chromium.org> Auto-Submit: Anton Bikineev <bikineev@chromium.org> Commit-Queue: Anton Bikineev <bikineev@chromium.org> Cr-Commit-Position: refs/heads/main@{#80304}
This commit is contained in:
parent
d489e88cdf
commit
5c92b06ead
@ -14,6 +14,10 @@
|
||||
#include "cppgc/platform.h"
|
||||
#include "v8config.h" // NOLINT(build/include_directory)
|
||||
|
||||
#if __cpp_lib_bitopts
|
||||
#include <bit>
|
||||
#endif // __cpp_lib_bitopts
|
||||
|
||||
namespace cppgc {
|
||||
namespace internal {
|
||||
|
||||
@ -57,7 +61,15 @@ class V8_EXPORT AgeTable final {
|
||||
private:
|
||||
V8_INLINE size_t card(uintptr_t offset) const {
|
||||
constexpr size_t kGranularityBits =
|
||||
#if __cpp_lib_bitopts
|
||||
std::countr_zero(static_cast<uint32_t>(kCardSizeInBytes));
|
||||
#elif V8_HAS_BUILTIN_CTZ
|
||||
__builtin_ctz(static_cast<uint32_t>(kCardSizeInBytes));
|
||||
#else //! V8_HAS_BUILTIN_CTZ
|
||||
// Hardcode and check with assert.
|
||||
9;
|
||||
#endif // !V8_HAS_BUILTIN_CTZ
|
||||
static_assert((1 << kGranularityBits) == kCardSizeInBytes);
|
||||
const size_t entry = offset >> kGranularityBits;
|
||||
CPPGC_DCHECK(table_.size() > entry);
|
||||
return entry;
|
||||
|
@ -23,13 +23,6 @@ namespace internal {
|
||||
// static
|
||||
AtomicEntryFlag WriteBarrier::write_barrier_enabled_;
|
||||
|
||||
#if defined(CPPGC_YOUNG_GENERATION)
|
||||
// static
|
||||
size_t YoungGenerationEnabler::is_enabled_;
|
||||
// static
|
||||
v8::base::LeakyObject<v8::base::Mutex> YoungGenerationEnabler::mutex_;
|
||||
#endif // defined(CPPGC_YOUNG_GENERATION)
|
||||
|
||||
namespace {
|
||||
|
||||
template <MarkerBase::WriteBarrierType type>
|
||||
@ -207,9 +200,17 @@ bool WriteBarrierTypeForCagedHeapPolicy::IsMarking(
|
||||
#endif // CPPGC_CAGED_HEAP
|
||||
|
||||
#if defined(CPPGC_YOUNG_GENERATION)
|
||||
|
||||
// static
|
||||
YoungGenerationEnabler& YoungGenerationEnabler::Instance() {
|
||||
static v8::base::LeakyObject<YoungGenerationEnabler> instance;
|
||||
return *instance.get();
|
||||
}
|
||||
|
||||
void YoungGenerationEnabler::Enable() {
|
||||
v8::base::LockGuard _(mutex_.get());
|
||||
if (++is_enabled_ == 1) {
|
||||
auto& instance = Instance();
|
||||
v8::base::LockGuard _(&instance.mutex_);
|
||||
if (++instance.is_enabled_ == 1) {
|
||||
// Enter the flag so that the check in the write barrier will always trigger
|
||||
// when young generation is enabled.
|
||||
WriteBarrier::FlagUpdater::Enter();
|
||||
@ -217,17 +218,20 @@ void YoungGenerationEnabler::Enable() {
|
||||
}
|
||||
|
||||
void YoungGenerationEnabler::Disable() {
|
||||
v8::base::LockGuard _(mutex_.get());
|
||||
DCHECK_LT(0, is_enabled_);
|
||||
if (--is_enabled_ == 0) {
|
||||
auto& instance = Instance();
|
||||
v8::base::LockGuard _(&instance.mutex_);
|
||||
DCHECK_LT(0, instance.is_enabled_);
|
||||
if (--instance.is_enabled_ == 0) {
|
||||
WriteBarrier::FlagUpdater::Exit();
|
||||
}
|
||||
}
|
||||
|
||||
bool YoungGenerationEnabler::IsEnabled() {
|
||||
v8::base::LockGuard _(mutex_.get());
|
||||
return is_enabled_;
|
||||
auto& instance = Instance();
|
||||
v8::base::LockGuard _(&instance.mutex_);
|
||||
return instance.is_enabled_;
|
||||
}
|
||||
|
||||
#endif // defined(CPPGC_YOUNG_GENERATION)
|
||||
|
||||
} // namespace internal
|
||||
|
@ -30,10 +30,15 @@ class V8_EXPORT_PRIVATE YoungGenerationEnabler final {
|
||||
static bool IsEnabled();
|
||||
|
||||
private:
|
||||
YoungGenerationEnabler() = delete;
|
||||
template <typename T>
|
||||
friend class v8::base::LeakyObject;
|
||||
|
||||
static size_t is_enabled_;
|
||||
static v8::base::LeakyObject<v8::base::Mutex> mutex_;
|
||||
static YoungGenerationEnabler& Instance();
|
||||
|
||||
YoungGenerationEnabler() = default;
|
||||
|
||||
size_t is_enabled_;
|
||||
v8::base::Mutex mutex_;
|
||||
};
|
||||
#endif // defined(CPPGC_YOUNG_GENERATION)
|
||||
|
||||
|
@ -158,13 +158,14 @@ TEST_F(ConcurrentSweeperTest, BackgroundSweepOfNormalPage) {
|
||||
// Wait for concurrent sweeping to finish.
|
||||
WaitForConcurrentSweeping();
|
||||
|
||||
#if !defined(CPPGC_YOUNG_GENERATION)
|
||||
// Check that the marked object was unmarked.
|
||||
EXPECT_FALSE(HeapObjectHeader::FromObject(marked_object).IsMarked());
|
||||
#else
|
||||
// Check that the marked object is still marked.
|
||||
EXPECT_TRUE(HeapObjectHeader::FromObject(marked_object).IsMarked());
|
||||
#endif
|
||||
const auto& hoh = HeapObjectHeader::FromObject(marked_object);
|
||||
if (Heap::From(GetHeap())->generational_gc_supported()) {
|
||||
// Check that the marked object is still marked.
|
||||
EXPECT_TRUE(hoh.IsMarked());
|
||||
} else {
|
||||
// Check that the marked object was unmarked.
|
||||
EXPECT_FALSE(hoh.IsMarked());
|
||||
}
|
||||
|
||||
// Check that free list entries are created right away for non-finalizable
|
||||
// objects, but not immediately returned to the space's freelist.
|
||||
@ -198,13 +199,14 @@ TEST_F(ConcurrentSweeperTest, BackgroundSweepOfLargePage) {
|
||||
// Wait for concurrent sweeping to finish.
|
||||
WaitForConcurrentSweeping();
|
||||
|
||||
#if !defined(CPPGC_YOUNG_GENERATION)
|
||||
// Check that the marked object was unmarked.
|
||||
EXPECT_FALSE(HeapObjectHeader::FromObject(marked_object).IsMarked());
|
||||
#else
|
||||
// Check that the marked object is still marked.
|
||||
EXPECT_TRUE(HeapObjectHeader::FromObject(marked_object).IsMarked());
|
||||
#endif
|
||||
const auto& hoh = HeapObjectHeader::FromObject(marked_object);
|
||||
if (Heap::From(GetHeap())->generational_gc_supported()) {
|
||||
// Check that the marked object is still marked.
|
||||
EXPECT_TRUE(hoh.IsMarked());
|
||||
} else {
|
||||
// Check that the marked object was unmarked.
|
||||
EXPECT_FALSE(hoh.IsMarked());
|
||||
}
|
||||
|
||||
// The page should not have been removed on the background threads.
|
||||
EXPECT_TRUE(PageInBackend(unmarked_page));
|
||||
@ -341,13 +343,14 @@ TEST_F(ConcurrentSweeperTest, IncrementalSweeping) {
|
||||
GetPlatform().RunAllForegroundTasks();
|
||||
|
||||
EXPECT_EQ(2u, g_destructor_callcount);
|
||||
#if !defined(CPPGC_YOUNG_GENERATION)
|
||||
EXPECT_FALSE(marked_normal_header.IsMarked());
|
||||
EXPECT_FALSE(marked_large_header.IsMarked());
|
||||
#else
|
||||
EXPECT_TRUE(marked_normal_header.IsMarked());
|
||||
EXPECT_TRUE(marked_large_header.IsMarked());
|
||||
#endif
|
||||
|
||||
if (Heap::From(GetHeap())->generational_gc_supported()) {
|
||||
EXPECT_TRUE(marked_normal_header.IsMarked());
|
||||
EXPECT_TRUE(marked_large_header.IsMarked());
|
||||
} else {
|
||||
EXPECT_FALSE(marked_normal_header.IsMarked());
|
||||
EXPECT_FALSE(marked_large_header.IsMarked());
|
||||
}
|
||||
|
||||
FinishSweeping();
|
||||
}
|
||||
|
@ -47,7 +47,6 @@ class DynamicallySized final : public GarbageCollected<DynamicallySized> {
|
||||
} // namespace
|
||||
|
||||
TEST_F(ExplicitManagementTest, FreeRegularObjectToLAB) {
|
||||
#if !defined(CPPGC_YOUNG_GENERATION)
|
||||
auto* o =
|
||||
MakeGarbageCollected<DynamicallySized>(GetHeap()->GetAllocationHandle());
|
||||
const auto& space = NormalPageSpace::From(BasePage::FromPayload(o)->space());
|
||||
@ -65,11 +64,9 @@ TEST_F(ExplicitManagementTest, FreeRegularObjectToLAB) {
|
||||
// LAB is included in allocated object size, so no change is expected.
|
||||
EXPECT_EQ(allocated_size_before, AllocatedObjectSize());
|
||||
EXPECT_FALSE(space.free_list().ContainsForTesting({needle, size}));
|
||||
#endif //! defined(CPPGC_YOUNG_GENERATION)
|
||||
}
|
||||
|
||||
TEST_F(ExplicitManagementTest, FreeRegularObjectToFreeList) {
|
||||
#if !defined(CPPGC_YOUNG_GENERATION)
|
||||
auto* o =
|
||||
MakeGarbageCollected<DynamicallySized>(GetHeap()->GetAllocationHandle());
|
||||
const auto& space = NormalPageSpace::From(BasePage::FromPayload(o)->space());
|
||||
@ -85,11 +82,9 @@ TEST_F(ExplicitManagementTest, FreeRegularObjectToFreeList) {
|
||||
EXPECT_EQ(lab.start(), nullptr);
|
||||
EXPECT_EQ(allocated_size_before - size, AllocatedObjectSize());
|
||||
EXPECT_TRUE(space.free_list().ContainsForTesting({needle, size}));
|
||||
#endif //! defined(CPPGC_YOUNG_GENERATION)
|
||||
}
|
||||
|
||||
TEST_F(ExplicitManagementTest, FreeLargeObject) {
|
||||
#if !defined(CPPGC_YOUNG_GENERATION)
|
||||
auto* o = MakeGarbageCollected<DynamicallySized>(
|
||||
GetHeap()->GetAllocationHandle(),
|
||||
AdditionalBytes(kLargeObjectSizeThreshold));
|
||||
@ -103,11 +98,9 @@ TEST_F(ExplicitManagementTest, FreeLargeObject) {
|
||||
subtle::FreeUnreferencedObject(GetHeapHandle(), *o);
|
||||
EXPECT_FALSE(heap.page_backend()->Lookup(needle));
|
||||
EXPECT_EQ(allocated_size_before - size, AllocatedObjectSize());
|
||||
#endif //! defined(CPPGC_YOUNG_GENERATION)
|
||||
}
|
||||
|
||||
TEST_F(ExplicitManagementTest, FreeBailsOutDuringGC) {
|
||||
#if !defined(CPPGC_YOUNG_GENERATION)
|
||||
const size_t snapshot_before = AllocatedObjectSize();
|
||||
auto* o =
|
||||
MakeGarbageCollected<DynamicallySized>(GetHeap()->GetAllocationHandle());
|
||||
@ -120,7 +113,6 @@ TEST_F(ExplicitManagementTest, FreeBailsOutDuringGC) {
|
||||
ResetLinearAllocationBuffers();
|
||||
subtle::FreeUnreferencedObject(GetHeapHandle(), *o);
|
||||
EXPECT_EQ(snapshot_before, AllocatedObjectSize());
|
||||
#endif //! defined(CPPGC_YOUNG_GENERATION)
|
||||
}
|
||||
|
||||
TEST_F(ExplicitManagementTest, GrowAtLAB) {
|
||||
|
@ -261,13 +261,13 @@ TEST_F(SweeperTest, UnmarkObjects) {
|
||||
|
||||
Sweep();
|
||||
|
||||
#if !defined(CPPGC_YOUNG_GENERATION)
|
||||
EXPECT_FALSE(normal_object_header.IsMarked());
|
||||
EXPECT_FALSE(large_object_header.IsMarked());
|
||||
#else
|
||||
EXPECT_TRUE(normal_object_header.IsMarked());
|
||||
EXPECT_TRUE(large_object_header.IsMarked());
|
||||
#endif
|
||||
if (Heap::From(GetHeap())->generational_gc_supported()) {
|
||||
EXPECT_TRUE(normal_object_header.IsMarked());
|
||||
EXPECT_TRUE(large_object_header.IsMarked());
|
||||
} else {
|
||||
EXPECT_FALSE(normal_object_header.IsMarked());
|
||||
EXPECT_FALSE(large_object_header.IsMarked());
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(SweeperTest, LazySweepingDuringAllocation) {
|
||||
|
@ -351,11 +351,10 @@ TEST_F(NoWriteBarrierTest, WriteBarrierBailoutWhenMarkingIsOff) {
|
||||
{
|
||||
EXPECT_FALSE(object1->IsMarked());
|
||||
WriteBarrierParams params;
|
||||
#if defined(CPPGC_YOUNG_GENERATION)
|
||||
WriteBarrierType expected = WriteBarrierType::kGenerational;
|
||||
#else // !CPPGC_YOUNG_GENERATION
|
||||
WriteBarrierType expected = WriteBarrierType::kNone;
|
||||
#endif // !CPPGC_YOUNG_GENERATION
|
||||
const WriteBarrierType expected =
|
||||
Heap::From(GetHeap())->generational_gc_supported()
|
||||
? WriteBarrierType::kGenerational
|
||||
: WriteBarrierType::kNone;
|
||||
EXPECT_EQ(expected, HeapConsistency::GetWriteBarrierType(
|
||||
object2->next_ref().GetSlotForTesting(),
|
||||
object2->next_ref().Get(), params));
|
||||
|
Loading…
Reference in New Issue
Block a user