diff --git a/BUILD.gn b/BUILD.gn index 6963a23637..db509ce7dc 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -3951,6 +3951,7 @@ v8_source_set("cppgc_base") { "include/cppgc/internal/api-contants.h", "include/cppgc/internal/finalizer-traits.h", "include/cppgc/internal/gc-info.h", + "include/cppgc/internal/pointer-policies.h", "include/cppgc/member.h", "include/cppgc/platform.h", "include/cppgc/source-location.h", @@ -3968,8 +3969,8 @@ v8_source_set("cppgc_base") { "src/heap/cppgc/heap-object-header.h", "src/heap/cppgc/heap.cc", "src/heap/cppgc/heap.h", - "src/heap/cppgc/member.cc", "src/heap/cppgc/platform.cc", + "src/heap/cppgc/pointer-policies.cc", "src/heap/cppgc/sanitizers.h", "src/heap/cppgc/source-location.cc", "src/heap/cppgc/stack.cc", diff --git a/include/cppgc/internal/pointer-policies.h b/include/cppgc/internal/pointer-policies.h new file mode 100644 index 0000000000..e685dfef0e --- /dev/null +++ b/include/cppgc/internal/pointer-policies.h @@ -0,0 +1,74 @@ +// 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. + +#ifndef INCLUDE_CPPGC_INTERNAL_POINTER_POLICIES_H_ +#define INCLUDE_CPPGC_INTERNAL_POINTER_POLICIES_H_ + +#include + +#include "include/v8config.h" + +namespace cppgc { +namespace internal { + +// Tags to distinguish between strong and weak member types. +class StrongMemberTag; +class WeakMemberTag; +class UntracedMemberTag; + +struct DijkstraWriteBarrierPolicy { + static void InitializingBarrier(const void*, const void*) { + // Since in initializing writes the source object is always white, having no + // barrier doesn't break the tri-color invariant. + } + static void AssigningBarrier(const void*, const void*) { + // TODO(chromium:1056170): Add actual implementation. + } +}; + +struct NoWriteBarrierPolicy { + static void InitializingBarrier(const void*, const void*) {} + static void AssigningBarrier(const void*, const void*) {} +}; + +class V8_EXPORT EnabledCheckingPolicy { + protected: + EnabledCheckingPolicy(); + void CheckPointer(const void* ptr); + + private: + void* impl_; +}; + +class DisabledCheckingPolicy { + protected: + void CheckPointer(const void* raw) {} +}; + +#if V8_ENABLE_CHECKS +using DefaultCheckingPolicy = EnabledCheckingPolicy; +#else +using DefaultCheckingPolicy = DisabledCheckingPolicy; +#endif + +// Special tag type used to denote some sentinel member. The semantics of the +// sentinel is defined by the embedder. +struct SentinelPointer { + template + operator T*() const { // NOLINT + static constexpr intptr_t kSentinelValue = -1; + return reinterpret_cast(kSentinelValue); + } + // Hidden friends. + friend bool operator==(SentinelPointer, SentinelPointer) { return true; } + friend bool operator!=(SentinelPointer, SentinelPointer) { return false; } +}; + +} // namespace internal + +constexpr internal::SentinelPointer kSentinelPointer; + +} // namespace cppgc + +#endif // INCLUDE_CPPGC_INTERNAL_POINTER_POLICIES_H_ diff --git a/include/cppgc/member.h b/include/cppgc/member.h index f4524ace68..45ea86847b 100644 --- a/include/cppgc/member.h +++ b/include/cppgc/member.h @@ -7,7 +7,10 @@ #include #include +#include +#include "include/cppgc/internal/pointer-policies.h" +#include "include/cppgc/type-traits.h" #include "include/v8config.h" namespace cppgc { @@ -16,66 +19,24 @@ class Visitor; namespace internal { -struct DijkstraWriteBarrierPolicy { - static void InitializingBarrier(const void*, const void*) { - // Since in initializing writes the source object is always white, having no - // barrier doesn't break the tri-color invariant. - } - static void AssigningBarrier(const void*, const void*) { - // TODO(chromium:1056170): Add actual implementation. - } -}; - -struct NoWriteBarrierPolicy { - static void InitializingBarrier(const void*, const void*) {} - static void AssigningBarrier(const void*, const void*) {} -}; - -class V8_EXPORT EnabledCheckingPolicy { - public: - EnabledCheckingPolicy(); - void CheckPointer(const void* ptr); - - private: - void* impl_; -}; - -class DisabledCheckingPolicy { - public: - void CheckPointer(const void* raw) {} -}; - -#if V8_ENABLE_CHECKS -using DefaultCheckingPolicy = EnabledCheckingPolicy; -#else -using DefaultCheckingPolicy = DisabledCheckingPolicy; -#endif - -// Special tag type used to denote some sentinel member. The semantics of the -// sentinel is defined by the embedder. -struct MemberSentinel {}; -constexpr MemberSentinel kMemberSentinel; - // The basic class from which all Member classes are 'generated'. -template +template class BasicMember : private CheckingPolicy { public: constexpr BasicMember() = default; constexpr BasicMember(std::nullptr_t) {} // NOLINT - constexpr BasicMember(MemberSentinel) // NOLINT - : raw_(reinterpret_cast(kSentinelValue)) {} + BasicMember(SentinelPointer s) : raw_(s) {} // NOLINT BasicMember(T* raw) : raw_(raw) { // NOLINT InitializingWriteBarrier(); this->CheckPointer(raw_); } - // TODO(chromium:1056170): Unfortunately, this overload is used ubiquitously - // in Blink. Reeavalute the possibility to remove it. BasicMember(T& raw) : BasicMember(&raw) {} // NOLINT BasicMember(const BasicMember& other) : BasicMember(other.Get()) {} // Allow heterogeneous construction. template + typename OtherCheckingPolicy, + typename = std::enable_if_t::value>> BasicMember(const BasicMember& other) : BasicMember(other.Get()) {} @@ -85,7 +46,8 @@ class BasicMember : private CheckingPolicy { } // Allow heterogeneous assignment. template + typename OtherCheckingPolicy, + typename = std::enable_if_t::value>> BasicMember& operator=( const BasicMember& other) { @@ -101,14 +63,14 @@ class BasicMember : private CheckingPolicy { Clear(); return *this; } - BasicMember& operator=(MemberSentinel) { - SetRawAtomic(reinterpret_cast(kSentinelValue)); + BasicMember& operator=(SentinelPointer s) { + SetRawAtomic(s); return *this; } - template - void Swap(BasicMember& other) { T* tmp = Get(); *this = other; @@ -134,9 +96,6 @@ class BasicMember : private CheckingPolicy { } private: - // Must not be odr-used. - static constexpr intptr_t kSentinelValue = -1; - void SetRawAtomic(T* raw) { reinterpret_cast*>(&raw_)->store(raw, std::memory_order_relaxed); @@ -180,12 +139,10 @@ bool operator!=( return !(member1 == member2); } -template -using BasicStrongMember = - BasicMember; - -template -using BasicWeakMember = BasicMember; +template +struct IsWeak< + internal::BasicMember> + : std::true_type {}; } // namespace internal @@ -193,8 +150,8 @@ using BasicWeakMember = BasicMember; // collected objects. All Member fields of a class must be traced in the class' // trace method. template -using Member = - internal::BasicStrongMember; +using Member = internal::BasicMember; // WeakMember is similar to Member in that it is used to point to other garbage // collected objects. However instead of creating a strong pointer to the @@ -203,15 +160,15 @@ using Member = // the object will be garbage collected. At the time of GC the weak pointers // will automatically be set to null. template -using WeakMember = - internal::BasicWeakMember; +using WeakMember = internal::BasicMember; // UntracedMember is a pointer to an on-heap object that is not traced for some // reason. Do not use this unless you know what you are doing. Keeping raw // pointers to on-heap objects is prohibited unless used from stack. Pointee // must be kept alive through other means. template -using UntracedMember = internal::BasicMember; } // namespace cppgc diff --git a/include/cppgc/type-traits.h b/include/cppgc/type-traits.h index a8a27a66eb..000e863543 100644 --- a/include/cppgc/type-traits.h +++ b/include/cppgc/type-traits.h @@ -7,8 +7,6 @@ #include -#include "include/cppgc/member.h" - namespace cppgc { class Visitor; @@ -27,10 +25,6 @@ using void_t = typename make_void::type; template struct IsWeak : std::false_type {}; -template -struct IsWeak> - : std::true_type {}; - template class U> struct IsSubclassOfTemplate { private: diff --git a/src/heap/cppgc/member.cc b/src/heap/cppgc/pointer-policies.cc similarity index 90% rename from src/heap/cppgc/member.cc rename to src/heap/cppgc/pointer-policies.cc index 34c474c1a5..2601ca2fdb 100644 --- a/src/heap/cppgc/member.cc +++ b/src/heap/cppgc/pointer-policies.cc @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "include/cppgc/member.h" +#include "include/cppgc/internal/pointer-policies.h" #include "src/base/macros.h" diff --git a/test/unittests/heap/cppgc/member_unittests.cc b/test/unittests/heap/cppgc/member_unittests.cc index 841ff3d23c..fc048aad5b 100644 --- a/test/unittests/heap/cppgc/member_unittests.cc +++ b/test/unittests/heap/cppgc/member_unittests.cc @@ -39,7 +39,7 @@ size_t CustomWriteBarrierPolicy::InitializingWriteBarriersTriggered = 0; size_t CustomWriteBarrierPolicy::AssigningWriteBarriersTriggered = 0; using MemberWithCustomBarrier = - BasicStrongMember; + BasicMember; struct CustomCheckingPolicy { static std::vector Cached; @@ -53,8 +53,8 @@ std::vector CustomCheckingPolicy::Cached; size_t CustomCheckingPolicy::ChecksTriggered = 0; using MemberWithCustomChecking = - internal::BasicMember; + BasicMember; class MemberTest : public testing::TestSupportingAllocationOnly {}; @@ -227,8 +227,9 @@ TEST_F(MemberTest, WriteBarrierTriggered) { // No initializing barriers for std::nullptr_t. EXPECT_EQ(1u, CustomWriteBarrierPolicy::InitializingWriteBarriersTriggered); EXPECT_EQ(1u, CustomWriteBarrierPolicy::AssigningWriteBarriersTriggered); - member2 = kMemberSentinel; - // No initializing barriers for member sentinel. + member2 = kSentinelPointer; + EXPECT_EQ(kSentinelPointer, member2.Get()); + // No initializing barriers for pointer sentinel. EXPECT_EQ(1u, CustomWriteBarrierPolicy::InitializingWriteBarriersTriggered); EXPECT_EQ(1u, CustomWriteBarrierPolicy::AssigningWriteBarriersTriggered); member2.Swap(member1);