From 69110a77581c7a1db26316bb8194174f6ad00fbb Mon Sep 17 00:00:00 2001 From: Michael Lippautz Date: Tue, 5 May 2020 09:12:03 +0200 Subject: [PATCH] cppgc: Add PostConstructionCallbackTrait This adds PostConstructionCallbackTrait which can be used to get a callback that is executed right after an object instance is created. This can be useful for hooks that require to be able to call into virtual methods. Bug: chromium:1074061 Change-Id: Idd5ef677fed291bcba81b9a47f2932c9bb5832b4 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2179385 Commit-Queue: Michael Lippautz Reviewed-by: Anton Bikineev Reviewed-by: Omer Katz Cr-Commit-Position: refs/heads/master@{#67557} --- include/cppgc/allocation.h | 16 ++++- .../heap/cppgc/garbage-collected_unittest.cc | 63 +++++++++++++++++++ 2 files changed, 78 insertions(+), 1 deletion(-) diff --git a/include/cppgc/allocation.h b/include/cppgc/allocation.h index cfbcd38b37..17cd37b855 100644 --- a/include/cppgc/allocation.h +++ b/include/cppgc/allocation.h @@ -106,6 +106,17 @@ class MakeGarbageCollectedTrait : public MakeGarbageCollectedTraitBase { } }; +/** + * Allows users to specify a post-construction callback for specific types. The + * callback is invoked on the instance of type T right after it has been + * constructed. This can be useful when the callback requires a + * fully-constructed object to be able to dispatch to virtual methods. + */ +template +struct PostConstructionCallbackTrait { + static void Call(T*) {} +}; + /** * Constructs a managed object of type T where T transitively inherits from * GarbageCollected. @@ -116,7 +127,10 @@ class MakeGarbageCollectedTrait : public MakeGarbageCollectedTraitBase { */ template T* MakeGarbageCollected(Heap* heap, Args&&... args) { - return MakeGarbageCollectedTrait::Call(heap, std::forward(args)...); + T* object = + MakeGarbageCollectedTrait::Call(heap, std::forward(args)...); + PostConstructionCallbackTrait::Call(object); + return object; } } // namespace cppgc diff --git a/test/unittests/heap/cppgc/garbage-collected_unittest.cc b/test/unittests/heap/cppgc/garbage-collected_unittest.cc index 7d2c84d7f7..272acae0a9 100644 --- a/test/unittests/heap/cppgc/garbage-collected_unittest.cc +++ b/test/unittests/heap/cppgc/garbage-collected_unittest.cc @@ -5,6 +5,8 @@ #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" @@ -76,5 +78,66 @@ TEST_F(GarbageCollectedTestWithHeap, GetObjectStartReturnsCorrentAddress) { .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