diff --git a/BUILD.gn b/BUILD.gn index cd28e288ae..ef5b6c1ea4 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -4107,6 +4107,7 @@ v8_source_set("cppgc_base") { "src/heap/cppgc/stack.h", "src/heap/cppgc/sweeper.cc", "src/heap/cppgc/sweeper.h", + "src/heap/cppgc/visitor.cc", "src/heap/cppgc/worklist.h", ] diff --git a/include/cppgc/visitor.h b/include/cppgc/visitor.h index a73a4abb2b..55d44c1cce 100644 --- a/include/cppgc/visitor.h +++ b/include/cppgc/visitor.h @@ -35,7 +35,7 @@ class Visitor { template void Trace(const WeakMember& weak_member) { - static_assert(sizeof(T), "T must be fully defined"); + static_assert(sizeof(T), "Pointee type must be fully defined."); static_assert(internal::IsGarbageCollectedType::value, "T must be GarabgeCollected or GarbageCollectedMixin type"); @@ -81,6 +81,18 @@ class Visitor { &HandleWeak, &p); } + template + void Trace(const T& object) { +#if V8_ENABLE_CHECKS + // This object is embedded in potentially multiple nested objects. The + // outermost object must not be in construction as such objects are (a) not + // processed immediately, and (b) only processed conservatively if not + // otherwise possible. + CheckObjectNotInConstruction(&object); +#endif // V8_ENABLE_CHECKS + TraceTrait::Trace(this, &object); + } + template void RegisterWeakCallbackMethod(const T* obj) { RegisterWeakCallback(&WeakCallbackMethodDelegate, obj); @@ -121,7 +133,7 @@ class Visitor { template void Trace(const T* t) { - static_assert(sizeof(T), "T must be fully defined"); + static_assert(sizeof(T), "Pointee type must be fully defined."); static_assert(internal::IsGarbageCollectedType::value, "T must be GarabgeCollected or GarbageCollectedMixin type"); if (!t) { @@ -130,6 +142,10 @@ class Visitor { Visit(t, TraceTrait::GetTraceDescriptor(t)); } +#if V8_ENABLE_CHECKS + V8_EXPORT void CheckObjectNotInConstruction(const void* address); +#endif // V8_ENABLE_CHECKS + friend class internal::VisitorBase; }; diff --git a/src/heap/cppgc/visitor.cc b/src/heap/cppgc/visitor.cc new file mode 100644 index 0000000000..18033ae3d8 --- /dev/null +++ b/src/heap/cppgc/visitor.cc @@ -0,0 +1,16 @@ +// 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 "src/heap/cppgc/visitor.h" + +namespace cppgc { + +#ifdef V8_ENABLE_CHECKS +void Visitor::CheckObjectNotInConstruction(const void* address) { + // TODO(chromium:1056170): |address| is an inner pointer of an object. Check + // that the object is not in construction. +} +#endif // V8_ENABLE_CHECKS + +} // namespace cppgc diff --git a/test/unittests/heap/cppgc/visitor-unittest.cc b/test/unittests/heap/cppgc/visitor-unittest.cc index d6b93dc697..ae100cb156 100644 --- a/test/unittests/heap/cppgc/visitor-unittest.cc +++ b/test/unittests/heap/cppgc/visitor-unittest.cc @@ -228,5 +228,34 @@ TEST_F(VisitorTest, DispatchRegisterWeakCallbackMethod) { EXPECT_EQ(1u, WeakCallbackDispatcher::callback_callcount); } +namespace { + +class Composite final { + public: + static size_t callback_callcount; + Composite() { callback_callcount = 0; } + void Trace(Visitor* visitor) const { callback_callcount++; } +}; + +size_t Composite::callback_callcount; + +class GCedWithComposite final : public GarbageCollected { + public: + void Trace(Visitor* visitor) const { visitor->Trace(composite); } + + Composite composite; +}; + +} // namespace + +TEST_F(VisitorTest, DispatchToCompositeObject) { + Member ref = + MakeGarbageCollected(GetHeap()); + DispatchingVisitor visitor(ref, ref); + EXPECT_EQ(0u, Composite::callback_callcount); + visitor.Trace(ref); + EXPECT_EQ(1u, Composite::callback_callcount); +} + } // namespace internal } // namespace cppgc