// Copyright 2020 the V8 project authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "include/cppgc/garbage-collected.h" #include "include/cppgc/allocation.h" #include "include/cppgc/type-traits.h" #include "src/heap/cppgc/heap-object-header-inl.h" #include "src/heap/cppgc/heap.h" #include "test/unittests/heap/cppgc/tests.h" #include "testing/gtest/include/gtest/gtest.h" namespace cppgc { namespace internal { namespace { class GCed : public GarbageCollected {}; class NotGCed {}; class Mixin : public GarbageCollectedMixin {}; class GCedWithMixin : public GarbageCollected, public Mixin { USING_GARBAGE_COLLECTED_MIXIN(); }; class OtherMixin : public GarbageCollectedMixin {}; class MergedMixins : public Mixin, public OtherMixin { MERGE_GARBAGE_COLLECTED_MIXINS(); public: void Trace(cppgc::Visitor* visitor) const override { Mixin::Trace(visitor); OtherMixin::Trace(visitor); } }; class GCWithMergedMixins : public GCed, public MergedMixins { USING_GARBAGE_COLLECTED_MIXIN(); public: void Trace(cppgc::Visitor* visitor) const override { MergedMixins::Trace(visitor); } }; class GarbageCollectedTestWithHeap : public testing::TestSupportingAllocationOnly {}; } // namespace TEST(GarbageCollectedTest, GarbageCollectedTrait) { STATIC_ASSERT(!IsGarbageCollectedType::value); STATIC_ASSERT(!IsGarbageCollectedType::value); STATIC_ASSERT(IsGarbageCollectedType::value); STATIC_ASSERT(IsGarbageCollectedType::value); STATIC_ASSERT(IsGarbageCollectedType::value); STATIC_ASSERT(IsGarbageCollectedType::value); STATIC_ASSERT(IsGarbageCollectedType::value); } TEST(GarbageCollectedTest, GarbageCollectedMixinTrait) { STATIC_ASSERT(!IsGarbageCollectedMixinType::value); STATIC_ASSERT(!IsGarbageCollectedMixinType::value); STATIC_ASSERT(!IsGarbageCollectedMixinType::value); STATIC_ASSERT(IsGarbageCollectedMixinType::value); STATIC_ASSERT(IsGarbageCollectedMixinType::value); STATIC_ASSERT(IsGarbageCollectedMixinType::value); STATIC_ASSERT(IsGarbageCollectedMixinType::value); } TEST_F(GarbageCollectedTestWithHeap, GetObjectStartReturnsCurrentAddress) { GCed* gced = MakeGarbageCollected(GetHeap()); GCedWithMixin* gced_with_mixin = MakeGarbageCollected(GetHeap()); EXPECT_EQ(gced_with_mixin, static_cast(gced_with_mixin) ->GetTraceDescriptor() .base_object_payload); EXPECT_NE(gced, static_cast(gced_with_mixin) ->GetTraceDescriptor() .base_object_payload); } namespace { class GCedWithPostConstructionCallback final : public GCed { public: static size_t cb_callcount; GCedWithPostConstructionCallback() { cb_callcount = 0; } }; size_t GCedWithPostConstructionCallback::cb_callcount; class MixinWithPostConstructionCallback { public: static size_t cb_callcount; MixinWithPostConstructionCallback() { cb_callcount = 0; } using MarkerForMixinWithPostConstructionCallback = int; }; size_t MixinWithPostConstructionCallback::cb_callcount; class GCedWithMixinWithPostConstructionCallback final : public GCed, public MixinWithPostConstructionCallback {}; } // namespace } // namespace internal template <> struct PostConstructionCallbackTrait< internal::GCedWithPostConstructionCallback> { static void Call(internal::GCedWithPostConstructionCallback* object) { EXPECT_FALSE( internal::HeapObjectHeader::FromPayload(object).IsInConstruction()); internal::GCedWithPostConstructionCallback::cb_callcount++; } }; template struct PostConstructionCallbackTrait< T, internal::void_t> { // The parameter could just be T*. static void Call( internal::GCedWithMixinWithPostConstructionCallback* object) { EXPECT_FALSE( internal::HeapObjectHeader::FromPayload(object).IsInConstruction()); internal::GCedWithMixinWithPostConstructionCallback::cb_callcount++; } }; namespace internal { TEST_F(GarbageCollectedTestWithHeap, PostConstructionCallback) { EXPECT_EQ(0u, GCedWithPostConstructionCallback::cb_callcount); MakeGarbageCollected(GetHeap()); EXPECT_EQ(1u, GCedWithPostConstructionCallback::cb_callcount); } TEST_F(GarbageCollectedTestWithHeap, PostConstructionCallbackForMixin) { EXPECT_EQ(0u, MixinWithPostConstructionCallback::cb_callcount); MakeGarbageCollected(GetHeap()); EXPECT_EQ(1u, MixinWithPostConstructionCallback::cb_callcount); } } // namespace internal } // namespace cppgc