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 @@
#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 "testing/gtest/include/gtest/gtest.h"
......@@ -69,5 +71,24 @@ TEST_F(CppgcAllocationTest, ReuseMemoryFromFreelist) {
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 cppgc
......@@ -376,55 +376,72 @@ namespace {
class MemberHeapTest : public testing::TestWithHeap {};
class GCedWithMember final : public GarbageCollected<GCedWithMember> {
class GCedWithMembers final : public GarbageCollected<GCedWithMembers> {
public:
static size_t live_count_;
GCedWithMember() : GCedWithMember(nullptr) {}
explicit GCedWithMember(GCedWithMember* nested)
: nested_(nested), weak_nested_(nested) {
GCedWithMembers() : GCedWithMembers(nullptr, nullptr) {}
explicit GCedWithMembers(GCedWithMembers* strong, GCedWithMembers* weak)
: strong_nested_(strong), weak_nested_(weak) {
++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_; }
private:
Member<GCedWithMember> nested_;
WeakMember<GCedWithMember> weak_nested_;
Member<GCedWithMembers> strong_nested_;
WeakMember<GCedWithMembers> weak_nested_;
};
size_t GCedWithMember::live_count_ = 0;
size_t GCedWithMembers::live_count_ = 0;
} // namespace
TEST_F(MemberHeapTest, MemberRetainsObject) {
EXPECT_EQ(0u, GCedWithMember::live_count_);
EXPECT_EQ(0u, GCedWithMembers::live_count_);
{
Persistent<GCedWithMember> gced_with_member =
MakeGarbageCollected<GCedWithMember>(
GetAllocationHandle(),
MakeGarbageCollected<GCedWithMember>(GetAllocationHandle()));
EXPECT_EQ(2u, GCedWithMember::live_count_);
GCedWithMembers* nested_object =
MakeGarbageCollected<GCedWithMembers>(GetAllocationHandle());
Persistent<GCedWithMembers> gced_with_members =
MakeGarbageCollected<GCedWithMembers>(GetAllocationHandle(),
nested_object, nested_object);
EXPECT_EQ(2u, GCedWithMembers::live_count_);
PreciseGC();
EXPECT_EQ(2u, GCedWithMember::live_count_);
EXPECT_FALSE(gced_with_member->WasNestedCleared());
EXPECT_EQ(2u, GCedWithMembers::live_count_);
EXPECT_FALSE(gced_with_members->WasNestedCleared());
}
PreciseGC();
EXPECT_EQ(0u, GCedWithMember::live_count_);
EXPECT_EQ(0u, GCedWithMembers::live_count_);
{
GCedWithMember* gced_with_member = MakeGarbageCollected<GCedWithMember>(
GetAllocationHandle(),
MakeGarbageCollected<GCedWithMember>(GetAllocationHandle()));
EXPECT_EQ(2u, GCedWithMember::live_count_);
GCedWithMembers* nested_object =
MakeGarbageCollected<GCedWithMembers>(GetAllocationHandle());
GCedWithMembers* gced_with_members = MakeGarbageCollected<GCedWithMembers>(
GetAllocationHandle(), nested_object, nested_object);
EXPECT_EQ(2u, GCedWithMembers::live_count_);
ConservativeGC();
EXPECT_EQ(2u, GCedWithMember::live_count_);
EXPECT_FALSE(gced_with_member->WasNestedCleared());
EXPECT_EQ(2u, GCedWithMembers::live_count_);
EXPECT_FALSE(gced_with_members->WasNestedCleared());
}
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
......
......@@ -684,6 +684,55 @@ TEST_F(PersistentTest, ExplicitDowncast) {
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) {
auto* heap = GetHeap();
static constexpr size_t kItems = 512;
......@@ -968,18 +1017,29 @@ TEST_F(PersistentTest, PersistentRetainsObject) {
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) {
WeakPersistent<DestructionCounter> weak_finalized;
{
DestructionCounter::destructor_calls_ = 0;
Persistent<DestructionCounter> finalized =
MakeGarbageCollected<DestructionCounter>(GetAllocationHandle());
weak_finalized = finalized.Get();
EXPECT_EQ(0u, DestructionCounter::destructor_calls_);
PreciseGC();
EXPECT_EQ(0u, DestructionCounter::destructor_calls_);
USE(finalized);
EXPECT_TRUE(weak_finalized);
}
PreciseGC();
EXPECT_EQ(1u, DestructionCounter::destructor_calls_);
EXPECT_FALSE(weak_finalized);
}
} // namespace internal
......
......@@ -345,5 +345,33 @@ TEST_F(SweeperTest, LazySweepingNormalPages) {
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 cppgc
......@@ -29,10 +29,17 @@ class GCed : public GarbageCollected<GCed> {
virtual void Trace(cppgc::Visitor* visitor) const { 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 {
public:
......@@ -100,6 +107,33 @@ TEST_F(TraceTraitTest, TraceGCedMixinThroughTraceDescriptor) {
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 {
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