Commit 164a040a authored by Michael Lippautz's avatar Michael Lippautz Committed by V8 LUCI CQ

cppgc: Add regression test and check for object start bitmap

Access to the object start bitmap is only safe during marking until
sweeping is started as the concurrent sweeper may clear and rebuild
the bitmap at any time during sweeping.

Adds a DCHECK and an additional test for a previously broken
pre-finalizer scenario.

Bug: chromium:1307471
Change-Id: If67ade43f7cdad6de4720c0efeac11bfe8c22b3c
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3535782Reviewed-by: 's avatarNikolaos Papaspyrou <nikolaos@chromium.org>
Reviewed-by: 's avatarOmer Katz <omerkatz@chromium.org>
Commit-Queue: Michael Lippautz <mlippautz@chromium.org>
Cr-Commit-Position: refs/heads/main@{#79550}
parent b426c2d3
...@@ -192,6 +192,15 @@ void HeapBase::Terminate() { ...@@ -192,6 +192,15 @@ void HeapBase::Terminate() {
CHECK_EQ(0u, weak_cross_thread_persistent_region_.NodesInUse()); CHECK_EQ(0u, weak_cross_thread_persistent_region_.NodesInUse());
} }
bool HeapBase::CanLookupObjectStartInBitmap() const {
// Object start bitmap access is only safe during marking and until the
// sweeper has been started. User code cannot distinguish between sweeping or
// not sweeping, which is why it's only valid to use the bitmap during
// marking.
return marker() || (in_atomic_pause() && !sweeper().IsSweepingInProgress()) ||
allow_lookup_of_object_start_in_bitmap_;
}
HeapStatistics HeapBase::CollectStatistics( HeapStatistics HeapBase::CollectStatistics(
HeapStatistics::DetailLevel detail_level) { HeapStatistics::DetailLevel detail_level) {
if (detail_level == HeapStatistics::DetailLevel::kBrief) { if (detail_level == HeapStatistics::DetailLevel::kBrief) {
......
...@@ -214,6 +214,11 @@ class V8_EXPORT_PRIVATE HeapBase : public cppgc::HeapHandle { ...@@ -214,6 +214,11 @@ class V8_EXPORT_PRIVATE HeapBase : public cppgc::HeapHandle {
MarkingType marking_support() const { return marking_support_; } MarkingType marking_support() const { return marking_support_; }
SweepingType sweeping_support() const { return sweeping_support_; } SweepingType sweeping_support() const { return sweeping_support_; }
bool CanLookupObjectStartInBitmap() const;
void set_allow_lookup_of_object_start_in_bitmap(bool value) {
allow_lookup_of_object_start_in_bitmap_ = value;
}
protected: protected:
// Used by the incremental scheduler to finalize a GC if supported. // Used by the incremental scheduler to finalize a GC if supported.
virtual void FinalizeIncrementalGarbageCollectionIfNeeded( virtual void FinalizeIncrementalGarbageCollectionIfNeeded(
...@@ -284,6 +289,10 @@ class V8_EXPORT_PRIVATE HeapBase : public cppgc::HeapHandle { ...@@ -284,6 +289,10 @@ class V8_EXPORT_PRIVATE HeapBase : public cppgc::HeapHandle {
int creation_thread_id_ = v8::base::OS::GetCurrentThreadId(); int creation_thread_id_ = v8::base::OS::GetCurrentThreadId();
// Used to explicitly allow lookups to the object start bitmap for testing
// code or internal code that otherwise verifies that access is safe.
bool allow_lookup_of_object_start_in_bitmap_ = false;
const MarkingType marking_support_; const MarkingType marking_support_;
const SweepingType sweeping_support_; const SweepingType sweeping_support_;
......
...@@ -106,8 +106,7 @@ const HeapObjectHeader* BasePage::TryObjectHeaderFromInnerAddress( ...@@ -106,8 +106,7 @@ const HeapObjectHeader* BasePage::TryObjectHeaderFromInnerAddress(
} }
// |address| is on the heap, so we FromInnerAddress can get the header. // |address| is on the heap, so we FromInnerAddress can get the header.
const HeapObjectHeader* header = const HeapObjectHeader* header = ObjectHeaderFromInnerAddressImpl(address);
ObjectHeaderFromInnerAddressImpl(this, address);
if (header->IsFree()) return nullptr; if (header->IsFree()) return nullptr;
DCHECK_NE(kFreeListGCInfoIndex, header->GetGCInfoIndex()); DCHECK_NE(kFreeListGCInfoIndex, header->GetGCInfoIndex());
return header; return header;
......
...@@ -90,6 +90,10 @@ class V8_EXPORT_PRIVATE BasePage { ...@@ -90,6 +90,10 @@ class V8_EXPORT_PRIVATE BasePage {
BasePage(HeapBase&, BaseSpace&, PageType); BasePage(HeapBase&, BaseSpace&, PageType);
private: private:
template <AccessMode mode = AccessMode::kNonAtomic>
const HeapObjectHeader* ObjectHeaderFromInnerAddressImpl(
const void* address) const;
HeapBase& heap_; HeapBase& heap_;
BaseSpace& space_; BaseSpace& space_;
PageType type_; PageType type_;
...@@ -271,14 +275,14 @@ const BasePage* BasePage::FromPayload(const void* payload) { ...@@ -271,14 +275,14 @@ const BasePage* BasePage::FromPayload(const void* payload) {
kGuardPageSize); kGuardPageSize);
} }
template <AccessMode mode = AccessMode::kNonAtomic> template <AccessMode mode>
const HeapObjectHeader* ObjectHeaderFromInnerAddressImpl(const BasePage* page, const HeapObjectHeader* BasePage::ObjectHeaderFromInnerAddressImpl(
const void* address) { const void* address) const {
if (page->is_large()) { if (is_large()) {
return LargePage::From(page)->ObjectHeader(); return LargePage::From(this)->ObjectHeader();
} }
const PlatformAwareObjectStartBitmap& bitmap = const PlatformAwareObjectStartBitmap& bitmap =
NormalPage::From(page)->object_start_bitmap(); NormalPage::From(this)->object_start_bitmap();
const HeapObjectHeader* header = const HeapObjectHeader* header =
bitmap.FindHeader<mode>(static_cast<ConstAddress>(address)); bitmap.FindHeader<mode>(static_cast<ConstAddress>(address));
DCHECK_LT(address, reinterpret_cast<ConstAddress>(header) + DCHECK_LT(address, reinterpret_cast<ConstAddress>(header) +
...@@ -303,7 +307,7 @@ const HeapObjectHeader& BasePage::ObjectHeaderFromInnerAddress( ...@@ -303,7 +307,7 @@ const HeapObjectHeader& BasePage::ObjectHeaderFromInnerAddress(
// reference to a mixin type // reference to a mixin type
SynchronizedLoad(); SynchronizedLoad();
const HeapObjectHeader* header = const HeapObjectHeader* header =
ObjectHeaderFromInnerAddressImpl<mode>(this, address); ObjectHeaderFromInnerAddressImpl<mode>(address);
DCHECK_NE(kFreeListGCInfoIndex, header->GetGCInfoIndex<mode>()); DCHECK_NE(kFreeListGCInfoIndex, header->GetGCInfoIndex<mode>());
return *header; return *header;
} }
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
#include "include/cppgc/trace-trait.h" #include "include/cppgc/trace-trait.h"
#include "src/heap/cppgc/gc-info-table.h" #include "src/heap/cppgc/gc-info-table.h"
#include "src/heap/cppgc/heap-base.h"
#include "src/heap/cppgc/heap-page.h" #include "src/heap/cppgc/heap-page.h"
namespace cppgc { namespace cppgc {
...@@ -15,6 +16,7 @@ TraceDescriptor TraceTraitFromInnerAddressImpl::GetTraceDescriptor( ...@@ -15,6 +16,7 @@ TraceDescriptor TraceTraitFromInnerAddressImpl::GetTraceDescriptor(
// address is guaranteed to be on a normal page because this is used only for // address is guaranteed to be on a normal page because this is used only for
// mixins. // mixins.
const BasePage* page = BasePage::FromPayload(address); const BasePage* page = BasePage::FromPayload(address);
DCHECK(page->heap().CanLookupObjectStartInBitmap());
page->SynchronizedLoad(); page->SynchronizedLoad();
const HeapObjectHeader& header = const HeapObjectHeader& header =
page->ObjectHeaderFromInnerAddress<AccessMode::kAtomic>(address); page->ObjectHeaderFromInnerAddress<AccessMode::kAtomic>(address);
......
...@@ -222,6 +222,7 @@ TEST_F(EphemeronPairTest, EphemeronPairWithMixinKey) { ...@@ -222,6 +222,7 @@ TEST_F(EphemeronPairTest, EphemeronPairWithMixinKey) {
key, value); key, value);
EXPECT_NE(static_cast<void*>(key), holder->ephemeron_pair().key.Get()); EXPECT_NE(static_cast<void*>(key), holder->ephemeron_pair().key.Get());
EXPECT_NE(static_cast<void*>(value), holder->ephemeron_pair().value.Get()); EXPECT_NE(static_cast<void*>(value), holder->ephemeron_pair().value.Get());
testing::AllowLookupOfObjectStartInBitmap allow_access(*GetHeap());
InitializeMarker(*Heap::From(GetHeap()), GetPlatformHandle().get()); InitializeMarker(*Heap::From(GetHeap()), GetPlatformHandle().get());
FinishSteps(); FinishSteps();
EXPECT_FALSE(HeapObjectHeader::FromObject(value).IsMarked()); EXPECT_FALSE(HeapObjectHeader::FromObject(value).IsMarked());
...@@ -238,6 +239,7 @@ TEST_F(EphemeronPairTest, EphemeronPairWithEmptyMixinValue) { ...@@ -238,6 +239,7 @@ TEST_F(EphemeronPairTest, EphemeronPairWithEmptyMixinValue) {
key, nullptr); key, nullptr);
EXPECT_NE(static_cast<void*>(key), holder->ephemeron_pair().key.Get()); EXPECT_NE(static_cast<void*>(key), holder->ephemeron_pair().key.Get());
EXPECT_TRUE(HeapObjectHeader::FromObject(key).TryMarkAtomic()); EXPECT_TRUE(HeapObjectHeader::FromObject(key).TryMarkAtomic());
testing::AllowLookupOfObjectStartInBitmap allow_access(*GetHeap());
InitializeMarker(*Heap::From(GetHeap()), GetPlatformHandle().get()); InitializeMarker(*Heap::From(GetHeap()), GetPlatformHandle().get());
FinishSteps(); FinishSteps();
FinishMarking(); FinishMarking();
......
...@@ -99,6 +99,7 @@ TEST_F(GarbageCollectedTestWithHeap, GetObjectStartReturnsCurrentAddress) { ...@@ -99,6 +99,7 @@ TEST_F(GarbageCollectedTestWithHeap, GetObjectStartReturnsCurrentAddress) {
GCed* gced = MakeGarbageCollected<GCed>(GetAllocationHandle()); GCed* gced = MakeGarbageCollected<GCed>(GetAllocationHandle());
GCedWithMixin* gced_with_mixin = GCedWithMixin* gced_with_mixin =
MakeGarbageCollected<GCedWithMixin>(GetAllocationHandle()); MakeGarbageCollected<GCedWithMixin>(GetAllocationHandle());
testing::AllowLookupOfObjectStartInBitmap allow_access(*GetHeap());
const void* base_object_payload = TraceTrait<Mixin>::GetTraceDescriptor( const void* base_object_payload = TraceTrait<Mixin>::GetTraceDescriptor(
static_cast<Mixin*>(gced_with_mixin)) static_cast<Mixin*>(gced_with_mixin))
.base_object_payload; .base_object_payload;
......
...@@ -50,10 +50,14 @@ class TestMarkingVisitor : public MutatorMarkingVisitor { ...@@ -50,10 +50,14 @@ class TestMarkingVisitor : public MutatorMarkingVisitor {
public: public:
explicit TestMarkingVisitor(Marker* marker) explicit TestMarkingVisitor(Marker* marker)
: MutatorMarkingVisitor(marker->heap(), : MutatorMarkingVisitor(marker->heap(),
marker->MutatorMarkingStateForTesting()) {} marker->MutatorMarkingStateForTesting()),
allow_access_(marker->heap()) {}
~TestMarkingVisitor() { marking_state_.Publish(); } ~TestMarkingVisitor() { marking_state_.Publish(); }
BasicMarkingState& marking_state() { return marking_state_; } BasicMarkingState& marking_state() { return marking_state_; }
private:
testing::AllowLookupOfObjectStartInBitmap allow_access_;
}; };
} // namespace } // namespace
......
...@@ -369,5 +369,56 @@ TEST_F(PrefinalizerTest, VirtualPrefinalizer) { ...@@ -369,5 +369,56 @@ TEST_F(PrefinalizerTest, VirtualPrefinalizer) {
EXPECT_LT(0u, GCedInherited::prefinalizer_count_); EXPECT_LT(0u, GCedInherited::prefinalizer_count_);
} }
namespace {
class MixinCallingGC : public GarbageCollectedMixin {
public:
template <typename GCFunction>
explicit MixinCallingGC(GCFunction gc) {
gc();
}
void Trace(Visitor*) const override {}
};
class MixinWithPrefinalizer : public GarbageCollectedMixin {
CPPGC_USING_PRE_FINALIZER(MixinWithPrefinalizer, PreFinalize);
public:
MixinWithPrefinalizer() = default;
void PreFinalize() {}
void Trace(Visitor*) const override {}
};
class BaseWithMixins : public GarbageCollected<BaseWithMixins>,
public MixinCallingGC,
public MixinWithPrefinalizer {
public:
template <typename GCFunction>
explicit BaseWithMixins(GCFunction gc) : MixinCallingGC(gc) {}
void Trace(Visitor* v) const override {
MixinCallingGC::Trace(v);
MixinWithPrefinalizer::Trace(v);
}
};
} // namespace
TEST_F(PrefinalizerTest, GCBeforePrefinalizerRegistration) {
// Regression test: https://crbug.com/1307471
MakeGarbageCollected<BaseWithMixins>(GetAllocationHandle(), [this]() {
internal::Heap::From(GetHeap())->CollectGarbage(
{internal::GarbageCollector::Config::CollectionType::kMajor,
cppgc::Heap::StackState::kMayContainHeapPointers,
Heap::MarkingType::kAtomic,
Heap::SweepingType::kIncrementalAndConcurrent,
internal::GarbageCollector::Config::FreeMemoryHandling::
kDiscardWherePossible,
internal::GarbageCollector::Config::IsForcedGC::kForced});
});
}
} // namespace internal } // namespace internal
} // namespace cppgc } // namespace cppgc
...@@ -38,6 +38,21 @@ void TestWithHeap::ResetLinearAllocationBuffers() { ...@@ -38,6 +38,21 @@ void TestWithHeap::ResetLinearAllocationBuffers() {
TestSupportingAllocationOnly::TestSupportingAllocationOnly() TestSupportingAllocationOnly::TestSupportingAllocationOnly()
: no_gc_scope_(GetHeap()->GetHeapHandle()) {} : no_gc_scope_(GetHeap()->GetHeapHandle()) {}
AllowLookupOfObjectStartInBitmap::AllowLookupOfObjectStartInBitmap(
cppgc::Heap& heap)
: AllowLookupOfObjectStartInBitmap(
*static_cast<HeapBase*>(Heap::From(&heap))) {}
AllowLookupOfObjectStartInBitmap::AllowLookupOfObjectStartInBitmap(
HeapBase& heap)
: heap_(heap) {
heap_.set_allow_lookup_of_object_start_in_bitmap(true);
}
AllowLookupOfObjectStartInBitmap::~AllowLookupOfObjectStartInBitmap() {
heap_.set_allow_lookup_of_object_start_in_bitmap(false);
}
} // namespace testing } // namespace testing
} // namespace internal } // namespace internal
} // namespace cppgc } // namespace cppgc
...@@ -125,6 +125,16 @@ class TestSupportingAllocationOnly : public TestWithHeap { ...@@ -125,6 +125,16 @@ class TestSupportingAllocationOnly : public TestWithHeap {
subtle::NoGarbageCollectionScope no_gc_scope_; subtle::NoGarbageCollectionScope no_gc_scope_;
}; };
class AllowLookupOfObjectStartInBitmap final {
public:
explicit AllowLookupOfObjectStartInBitmap(cppgc::Heap&);
explicit AllowLookupOfObjectStartInBitmap(HeapBase&);
~AllowLookupOfObjectStartInBitmap();
private:
HeapBase& heap_;
};
} // namespace testing } // namespace testing
} // namespace internal } // namespace internal
} // namespace cppgc } // namespace cppgc
......
...@@ -68,6 +68,7 @@ TEST_F(TraceTraitTest, GetObjectStartGCedMixin) { ...@@ -68,6 +68,7 @@ TEST_F(TraceTraitTest, GetObjectStartGCedMixin) {
auto* gced_mixin_app = auto* gced_mixin_app =
MakeGarbageCollected<GCedMixinApplication>(GetAllocationHandle()); MakeGarbageCollected<GCedMixinApplication>(GetAllocationHandle());
auto* gced_mixin = static_cast<GCedMixin*>(gced_mixin_app); auto* gced_mixin = static_cast<GCedMixin*>(gced_mixin_app);
testing::AllowLookupOfObjectStartInBitmap allow_access(*GetHeap());
EXPECT_EQ(gced_mixin_app, EXPECT_EQ(gced_mixin_app,
TraceTrait<GCedMixin>::GetTraceDescriptor(gced_mixin) TraceTrait<GCedMixin>::GetTraceDescriptor(gced_mixin)
.base_object_payload); .base_object_payload);
...@@ -102,6 +103,7 @@ TEST_F(TraceTraitTest, TraceGCedMixinThroughTraceDescriptor) { ...@@ -102,6 +103,7 @@ TEST_F(TraceTraitTest, TraceGCedMixinThroughTraceDescriptor) {
MakeGarbageCollected<GCedMixinApplication>(GetAllocationHandle()); MakeGarbageCollected<GCedMixinApplication>(GetAllocationHandle());
auto* gced_mixin = static_cast<GCedMixin*>(gced_mixin_app); auto* gced_mixin = static_cast<GCedMixin*>(gced_mixin_app);
EXPECT_EQ(0u, GCed::trace_callcount); EXPECT_EQ(0u, GCed::trace_callcount);
testing::AllowLookupOfObjectStartInBitmap allow_access(*GetHeap());
TraceDescriptor desc = TraceTrait<GCedMixin>::GetTraceDescriptor(gced_mixin); TraceDescriptor desc = TraceTrait<GCedMixin>::GetTraceDescriptor(gced_mixin);
desc.callback(nullptr, desc.base_object_payload); desc.callback(nullptr, desc.base_object_payload);
EXPECT_EQ(1u, GCed::trace_callcount); EXPECT_EQ(1u, GCed::trace_callcount);
...@@ -119,6 +121,7 @@ TEST_F(TraceTraitTest, MixinInstanceWithoutTrace) { ...@@ -119,6 +121,7 @@ TEST_F(TraceTraitTest, MixinInstanceWithoutTrace) {
auto* mixin_without_trace = auto* mixin_without_trace =
MakeGarbageCollected<MixinInstanceWithoutTrace>(GetAllocationHandle()); MakeGarbageCollected<MixinInstanceWithoutTrace>(GetAllocationHandle());
auto* mixin = static_cast<GCedMixin*>(mixin_without_trace); auto* mixin = static_cast<GCedMixin*>(mixin_without_trace);
testing::AllowLookupOfObjectStartInBitmap allow_access(*GetHeap());
EXPECT_EQ(0u, GCedMixin::trace_callcount); EXPECT_EQ(0u, GCedMixin::trace_callcount);
TraceDescriptor mixin_without_trace_desc = TraceDescriptor mixin_without_trace_desc =
TraceTrait<MixinInstanceWithoutTrace>::GetTraceDescriptor( TraceTrait<MixinInstanceWithoutTrace>::GetTraceDescriptor(
...@@ -138,8 +141,8 @@ namespace { ...@@ -138,8 +141,8 @@ namespace {
class DispatchingVisitor final : public VisitorBase { class DispatchingVisitor final : public VisitorBase {
public: public:
DispatchingVisitor(const void* object, const void* payload) DispatchingVisitor(cppgc::Heap& heap, const void* object, const void* payload)
: object_(object), payload_(payload) {} : allow_access_(heap), object_(object), payload_(payload) {}
protected: protected:
void Visit(const void* t, TraceDescriptor desc) final { void Visit(const void* t, TraceDescriptor desc) final {
...@@ -157,6 +160,7 @@ class DispatchingVisitor final : public VisitorBase { ...@@ -157,6 +160,7 @@ class DispatchingVisitor final : public VisitorBase {
} }
private: private:
testing::AllowLookupOfObjectStartInBitmap allow_access_;
const void* object_; const void* object_;
const void* payload_; const void* payload_;
}; };
...@@ -165,7 +169,7 @@ class DispatchingVisitor final : public VisitorBase { ...@@ -165,7 +169,7 @@ class DispatchingVisitor final : public VisitorBase {
TEST_F(VisitorTest, DispatchTraceGCed) { TEST_F(VisitorTest, DispatchTraceGCed) {
Member<GCed> ref = MakeGarbageCollected<GCed>(GetAllocationHandle()); Member<GCed> ref = MakeGarbageCollected<GCed>(GetAllocationHandle());
DispatchingVisitor visitor(ref, ref); DispatchingVisitor visitor(*GetHeap(), ref, ref);
EXPECT_EQ(0u, GCed::trace_callcount); EXPECT_EQ(0u, GCed::trace_callcount);
visitor.Trace(ref); visitor.Trace(ref);
EXPECT_EQ(1u, GCed::trace_callcount); EXPECT_EQ(1u, GCed::trace_callcount);
...@@ -178,7 +182,7 @@ TEST_F(VisitorTest, DispatchTraceGCedMixin) { ...@@ -178,7 +182,7 @@ TEST_F(VisitorTest, DispatchTraceGCedMixin) {
// Ensure that we indeed test dispatching an inner object. // Ensure that we indeed test dispatching an inner object.
EXPECT_NE(static_cast<void*>(gced_mixin_app), static_cast<void*>(gced_mixin)); EXPECT_NE(static_cast<void*>(gced_mixin_app), static_cast<void*>(gced_mixin));
Member<GCedMixin> ref = gced_mixin; Member<GCedMixin> ref = gced_mixin;
DispatchingVisitor visitor(gced_mixin, gced_mixin_app); DispatchingVisitor visitor(*GetHeap(), gced_mixin, gced_mixin_app);
EXPECT_EQ(0u, GCed::trace_callcount); EXPECT_EQ(0u, GCed::trace_callcount);
visitor.Trace(ref); visitor.Trace(ref);
EXPECT_EQ(1u, GCed::trace_callcount); EXPECT_EQ(1u, GCed::trace_callcount);
...@@ -186,7 +190,7 @@ TEST_F(VisitorTest, DispatchTraceGCedMixin) { ...@@ -186,7 +190,7 @@ TEST_F(VisitorTest, DispatchTraceGCedMixin) {
TEST_F(VisitorTest, DispatchTraceWeakGCed) { TEST_F(VisitorTest, DispatchTraceWeakGCed) {
WeakMember<GCed> ref = MakeGarbageCollected<GCed>(GetAllocationHandle()); WeakMember<GCed> ref = MakeGarbageCollected<GCed>(GetAllocationHandle());
DispatchingVisitor visitor(ref, ref); DispatchingVisitor visitor(*GetHeap(), ref, ref);
visitor.Trace(ref); visitor.Trace(ref);
// No marking, so reference should be cleared. // No marking, so reference should be cleared.
EXPECT_EQ(nullptr, ref.Get()); EXPECT_EQ(nullptr, ref.Get());
...@@ -199,7 +203,7 @@ TEST_F(VisitorTest, DispatchTraceWeakGCedMixin) { ...@@ -199,7 +203,7 @@ TEST_F(VisitorTest, DispatchTraceWeakGCedMixin) {
// Ensure that we indeed test dispatching an inner object. // Ensure that we indeed test dispatching an inner object.
EXPECT_NE(static_cast<void*>(gced_mixin_app), static_cast<void*>(gced_mixin)); EXPECT_NE(static_cast<void*>(gced_mixin_app), static_cast<void*>(gced_mixin));
WeakMember<GCedMixin> ref = gced_mixin; WeakMember<GCedMixin> ref = gced_mixin;
DispatchingVisitor visitor(gced_mixin, gced_mixin_app); DispatchingVisitor visitor(*GetHeap(), gced_mixin, gced_mixin_app);
visitor.Trace(ref); visitor.Trace(ref);
// No marking, so reference should be cleared. // No marking, so reference should be cleared.
EXPECT_EQ(nullptr, ref.Get()); EXPECT_EQ(nullptr, ref.Get());
...@@ -290,7 +294,7 @@ class GCedWithComposite final : public GarbageCollected<GCedWithComposite> { ...@@ -290,7 +294,7 @@ class GCedWithComposite final : public GarbageCollected<GCedWithComposite> {
TEST_F(VisitorTest, DispatchToCompositeObject) { TEST_F(VisitorTest, DispatchToCompositeObject) {
Member<GCedWithComposite> ref = Member<GCedWithComposite> ref =
MakeGarbageCollected<GCedWithComposite>(GetAllocationHandle()); MakeGarbageCollected<GCedWithComposite>(GetAllocationHandle());
DispatchingVisitor visitor(ref, ref); DispatchingVisitor visitor(*GetHeap(), ref, ref);
EXPECT_EQ(0u, Composite::callback_callcount); EXPECT_EQ(0u, Composite::callback_callcount);
visitor.Trace(ref); visitor.Trace(ref);
EXPECT_EQ(1u, Composite::callback_callcount); EXPECT_EQ(1u, Composite::callback_callcount);
......
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