Commit 73607264 authored by Omer Katz's avatar Omer Katz Committed by Commit Bot

cppgc: Another batch of tests

Bug: chromium:1056170
Change-Id: I0ccb8d3a67a21467e9145ddbff8514a6054d57fe
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2843821
Commit-Queue: Omer Katz <omerkatz@chromium.org>
Reviewed-by: 's avatarMichael Lippautz <mlippautz@chromium.org>
Cr-Commit-Position: refs/heads/master@{#74128}
parent 01c670e4
...@@ -4,6 +4,8 @@ ...@@ -4,6 +4,8 @@
#include "include/cppgc/allocation.h" #include "include/cppgc/allocation.h"
#include "include/cppgc/visitor.h"
#include "src/heap/cppgc/heap-object-header.h"
#include "test/unittests/heap/cppgc/tests.h" #include "test/unittests/heap/cppgc/tests.h"
#include "testing/gtest/include/gtest/gtest.h" #include "testing/gtest/include/gtest/gtest.h"
...@@ -69,5 +71,24 @@ TEST_F(CppgcAllocationTest, ReuseMemoryFromFreelist) { ...@@ -69,5 +71,24 @@ TEST_F(CppgcAllocationTest, ReuseMemoryFromFreelist) {
EXPECT_TRUE(reused_memory_found); EXPECT_TRUE(reused_memory_found);
} }
namespace {
class CallbackInCtor final : public GarbageCollected<CallbackInCtor> {
public:
template <typename Callback>
explicit CallbackInCtor(Callback callback) {
callback();
}
void Trace(Visitor*) const {}
};
} // namespace
TEST_F(CppgcAllocationTest,
ConservativeGCDuringAllocationDoesNotReclaimObject) {
CallbackInCtor* obj = MakeGarbageCollected<CallbackInCtor>(
GetAllocationHandle(), [this]() { ConservativeGC(); });
EXPECT_FALSE(HeapObjectHeader::FromPayload(obj).IsFree());
}
} // namespace internal } // namespace internal
} // namespace cppgc } // namespace cppgc
...@@ -376,55 +376,72 @@ namespace { ...@@ -376,55 +376,72 @@ namespace {
class MemberHeapTest : public testing::TestWithHeap {}; class MemberHeapTest : public testing::TestWithHeap {};
class GCedWithMember final : public GarbageCollected<GCedWithMember> { class GCedWithMembers final : public GarbageCollected<GCedWithMembers> {
public: public:
static size_t live_count_; static size_t live_count_;
GCedWithMember() : GCedWithMember(nullptr) {} GCedWithMembers() : GCedWithMembers(nullptr, nullptr) {}
explicit GCedWithMember(GCedWithMember* nested) explicit GCedWithMembers(GCedWithMembers* strong, GCedWithMembers* weak)
: nested_(nested), weak_nested_(nested) { : strong_nested_(strong), weak_nested_(weak) {
++live_count_; ++live_count_;
} }
~GCedWithMember() { --live_count_; } ~GCedWithMembers() { --live_count_; }
void Trace(cppgc::Visitor* visitor) const { visitor->Trace(nested_); } void Trace(cppgc::Visitor* visitor) const {
visitor->Trace(strong_nested_);
visitor->Trace(weak_nested_);
}
bool WasNestedCleared() const { return !weak_nested_; } bool WasNestedCleared() const { return !weak_nested_; }
private: private:
Member<GCedWithMember> nested_; Member<GCedWithMembers> strong_nested_;
WeakMember<GCedWithMember> weak_nested_; WeakMember<GCedWithMembers> weak_nested_;
}; };
size_t GCedWithMember::live_count_ = 0; size_t GCedWithMembers::live_count_ = 0;
} // namespace } // namespace
TEST_F(MemberHeapTest, MemberRetainsObject) { TEST_F(MemberHeapTest, MemberRetainsObject) {
EXPECT_EQ(0u, GCedWithMember::live_count_); EXPECT_EQ(0u, GCedWithMembers::live_count_);
{ {
Persistent<GCedWithMember> gced_with_member = GCedWithMembers* nested_object =
MakeGarbageCollected<GCedWithMember>( MakeGarbageCollected<GCedWithMembers>(GetAllocationHandle());
GetAllocationHandle(), Persistent<GCedWithMembers> gced_with_members =
MakeGarbageCollected<GCedWithMember>(GetAllocationHandle())); MakeGarbageCollected<GCedWithMembers>(GetAllocationHandle(),
EXPECT_EQ(2u, GCedWithMember::live_count_); nested_object, nested_object);
EXPECT_EQ(2u, GCedWithMembers::live_count_);
PreciseGC(); PreciseGC();
EXPECT_EQ(2u, GCedWithMember::live_count_); EXPECT_EQ(2u, GCedWithMembers::live_count_);
EXPECT_FALSE(gced_with_member->WasNestedCleared()); EXPECT_FALSE(gced_with_members->WasNestedCleared());
} }
PreciseGC(); PreciseGC();
EXPECT_EQ(0u, GCedWithMember::live_count_); EXPECT_EQ(0u, GCedWithMembers::live_count_);
{ {
GCedWithMember* gced_with_member = MakeGarbageCollected<GCedWithMember>( GCedWithMembers* nested_object =
GetAllocationHandle(), MakeGarbageCollected<GCedWithMembers>(GetAllocationHandle());
MakeGarbageCollected<GCedWithMember>(GetAllocationHandle())); GCedWithMembers* gced_with_members = MakeGarbageCollected<GCedWithMembers>(
EXPECT_EQ(2u, GCedWithMember::live_count_); GetAllocationHandle(), nested_object, nested_object);
EXPECT_EQ(2u, GCedWithMembers::live_count_);
ConservativeGC(); ConservativeGC();
EXPECT_EQ(2u, GCedWithMember::live_count_); EXPECT_EQ(2u, GCedWithMembers::live_count_);
EXPECT_FALSE(gced_with_member->WasNestedCleared()); EXPECT_FALSE(gced_with_members->WasNestedCleared());
} }
PreciseGC(); PreciseGC();
EXPECT_EQ(0u, GCedWithMember::live_count_); EXPECT_EQ(0u, GCedWithMembers::live_count_);
}
TEST_F(MemberHeapTest, WeakMemberDoesNotRetainObject) {
EXPECT_EQ(0u, GCedWithMembers::live_count_);
auto* weak_nested =
MakeGarbageCollected<GCedWithMembers>(GetAllocationHandle());
Persistent<GCedWithMembers> gced_with_members(
MakeGarbageCollected<GCedWithMembers>(GetAllocationHandle(), nullptr,
weak_nested));
PreciseGC();
EXPECT_EQ(1u, GCedWithMembers::live_count_);
EXPECT_TRUE(gced_with_members->WasNestedCleared());
} }
} // namespace internal } // namespace internal
......
...@@ -684,6 +684,55 @@ TEST_F(PersistentTest, ExplicitDowncast) { ...@@ -684,6 +684,55 @@ TEST_F(PersistentTest, ExplicitDowncast) {
ExplicitDowncast<subtle::WeakCrossThreadPersistent>(heap); ExplicitDowncast<subtle::WeakCrossThreadPersistent>(heap);
} }
namespace {
template <template <typename> class PersistentType1,
template <typename> class PersistentType2>
void EqualityTest(cppgc::Heap* heap) {
{
GCed* gced = MakeGarbageCollected<GCed>(heap->GetAllocationHandle());
PersistentType1<GCed> persistent1 = gced;
PersistentType2<GCed> persistent2 = gced;
EXPECT_TRUE(persistent1 == persistent2);
EXPECT_FALSE(persistent1 != persistent2);
persistent2 = persistent1;
EXPECT_TRUE(persistent1 == persistent2);
EXPECT_FALSE(persistent1 != persistent2);
}
{
PersistentType1<GCed> persistent1 =
MakeGarbageCollected<GCed>(heap->GetAllocationHandle());
PersistentType2<GCed> persistent2 =
MakeGarbageCollected<GCed>(heap->GetAllocationHandle());
EXPECT_TRUE(persistent1 != persistent2);
EXPECT_FALSE(persistent1 == persistent2);
}
}
} // namespace
TEST_F(PersistentTest, EqualityTest) {
cppgc::Heap* heap = GetHeap();
EqualityTest<Persistent, Persistent>(heap);
EqualityTest<Persistent, WeakPersistent>(heap);
EqualityTest<Persistent, subtle::CrossThreadPersistent>(heap);
EqualityTest<Persistent, subtle::WeakCrossThreadPersistent>(heap);
EqualityTest<WeakPersistent, Persistent>(heap);
EqualityTest<WeakPersistent, WeakPersistent>(heap);
EqualityTest<WeakPersistent, subtle::CrossThreadPersistent>(heap);
EqualityTest<WeakPersistent, subtle::WeakCrossThreadPersistent>(heap);
EqualityTest<subtle::CrossThreadPersistent, Persistent>(heap);
EqualityTest<subtle::CrossThreadPersistent, WeakPersistent>(heap);
EqualityTest<subtle::CrossThreadPersistent, subtle::CrossThreadPersistent>(
heap);
EqualityTest<subtle::CrossThreadPersistent,
subtle::WeakCrossThreadPersistent>(heap);
EqualityTest<subtle::WeakCrossThreadPersistent, Persistent>(heap);
EqualityTest<subtle::WeakCrossThreadPersistent, WeakPersistent>(heap);
EqualityTest<subtle::WeakCrossThreadPersistent,
subtle::CrossThreadPersistent>(heap);
EqualityTest<subtle::WeakCrossThreadPersistent,
subtle::WeakCrossThreadPersistent>(heap);
}
TEST_F(PersistentTest, TraceStrong) { TEST_F(PersistentTest, TraceStrong) {
auto* heap = GetHeap(); auto* heap = GetHeap();
static constexpr size_t kItems = 512; static constexpr size_t kItems = 512;
...@@ -968,18 +1017,29 @@ TEST_F(PersistentTest, PersistentRetainsObject) { ...@@ -968,18 +1017,29 @@ TEST_F(PersistentTest, PersistentRetainsObject) {
EXPECT_TRUE(weak_trace_counter); EXPECT_TRUE(weak_trace_counter);
} }
TEST_F(PersistentTest, WeakPersistentDoesNotRetainObject) {
WeakPersistent<TraceCounter> weak_trace_counter =
MakeGarbageCollected<TraceCounter>(GetAllocationHandle());
PreciseGC();
EXPECT_FALSE(weak_trace_counter);
}
TEST_F(PersistentTest, ObjectReclaimedAfterClearedPersistent) { TEST_F(PersistentTest, ObjectReclaimedAfterClearedPersistent) {
WeakPersistent<DestructionCounter> weak_finalized;
{ {
DestructionCounter::destructor_calls_ = 0; DestructionCounter::destructor_calls_ = 0;
Persistent<DestructionCounter> finalized = Persistent<DestructionCounter> finalized =
MakeGarbageCollected<DestructionCounter>(GetAllocationHandle()); MakeGarbageCollected<DestructionCounter>(GetAllocationHandle());
weak_finalized = finalized.Get();
EXPECT_EQ(0u, DestructionCounter::destructor_calls_); EXPECT_EQ(0u, DestructionCounter::destructor_calls_);
PreciseGC(); PreciseGC();
EXPECT_EQ(0u, DestructionCounter::destructor_calls_); EXPECT_EQ(0u, DestructionCounter::destructor_calls_);
USE(finalized); USE(finalized);
EXPECT_TRUE(weak_finalized);
} }
PreciseGC(); PreciseGC();
EXPECT_EQ(1u, DestructionCounter::destructor_calls_); EXPECT_EQ(1u, DestructionCounter::destructor_calls_);
EXPECT_FALSE(weak_finalized);
} }
} // namespace internal } // namespace internal
......
...@@ -345,5 +345,33 @@ TEST_F(SweeperTest, LazySweepingNormalPages) { ...@@ -345,5 +345,33 @@ TEST_F(SweeperTest, LazySweepingNormalPages) {
EXPECT_EQ(2u, g_destructor_callcount); EXPECT_EQ(2u, g_destructor_callcount);
} }
namespace {
class AllocatingFinalizer : public GarbageCollected<AllocatingFinalizer> {
public:
static size_t destructor_callcount_;
explicit AllocatingFinalizer(AllocationHandle& allocation_handle)
: allocation_handle_(allocation_handle) {}
~AllocatingFinalizer() {
MakeGarbageCollected<GCed<sizeof(size_t)>>(allocation_handle_);
++destructor_callcount_;
}
void Trace(Visitor*) const {}
private:
AllocationHandle& allocation_handle_;
};
size_t AllocatingFinalizer::destructor_callcount_ = 0;
} // namespace
TEST_F(SweeperTest, AllocationDuringFinalizationIsNotSwept) {
AllocatingFinalizer::destructor_callcount_ = 0;
g_destructor_callcount = 0;
MakeGarbageCollected<AllocatingFinalizer>(GetAllocationHandle(),
GetAllocationHandle());
PreciseGC();
EXPECT_LT(0u, AllocatingFinalizer::destructor_callcount_);
EXPECT_EQ(0u, g_destructor_callcount);
}
} // namespace internal } // namespace internal
} // namespace cppgc } // namespace cppgc
...@@ -29,10 +29,17 @@ class GCed : public GarbageCollected<GCed> { ...@@ -29,10 +29,17 @@ class GCed : public GarbageCollected<GCed> {
virtual void Trace(cppgc::Visitor* visitor) const { trace_callcount++; } virtual void Trace(cppgc::Visitor* visitor) const { trace_callcount++; }
}; };
size_t GCed::trace_callcount; size_t GCed::trace_callcount;
class GCedMixin : public GarbageCollectedMixin {}; class GCedMixin : public GarbageCollectedMixin {
public:
static size_t trace_callcount;
GCedMixin() { trace_callcount = 0; }
virtual void Trace(cppgc::Visitor* visitor) const { trace_callcount++; }
};
size_t GCedMixin::trace_callcount;
class OtherPayload { class OtherPayload {
public: public:
...@@ -100,6 +107,33 @@ TEST_F(TraceTraitTest, TraceGCedMixinThroughTraceDescriptor) { ...@@ -100,6 +107,33 @@ TEST_F(TraceTraitTest, TraceGCedMixinThroughTraceDescriptor) {
EXPECT_EQ(1u, GCed::trace_callcount); EXPECT_EQ(1u, GCed::trace_callcount);
} }
namespace {
class MixinInstanceWithoutTrace
: public GarbageCollected<MixinInstanceWithoutTrace>,
public GCedMixin {};
} // namespace
TEST_F(TraceTraitTest, MixinInstanceWithoutTrace) {
// Verify that a mixin instance without any traceable
// references inherits the mixin's trace implementation.
auto* mixin_without_trace =
MakeGarbageCollected<MixinInstanceWithoutTrace>(GetAllocationHandle());
auto* mixin = static_cast<GCedMixin*>(mixin_without_trace);
EXPECT_EQ(0u, GCedMixin::trace_callcount);
TraceDescriptor mixin_without_trace_desc =
TraceTrait<MixinInstanceWithoutTrace>::GetTraceDescriptor(
mixin_without_trace);
TraceDescriptor mixin_desc = TraceTrait<GCedMixin>::GetTraceDescriptor(mixin);
EXPECT_EQ(mixin_without_trace_desc.callback, mixin_desc.callback);
EXPECT_EQ(mixin_without_trace_desc.base_object_payload,
mixin_desc.base_object_payload);
TraceDescriptor desc =
TraceTrait<MixinInstanceWithoutTrace>::GetTraceDescriptor(
mixin_without_trace);
desc.callback(nullptr, desc.base_object_payload);
EXPECT_EQ(1u, GCedMixin::trace_callcount);
}
namespace { namespace {
class DispatchingVisitor final : public VisitorBase { class DispatchingVisitor final : public VisitorBase {
......
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