1 // Copyright 2020 the V8 project authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef INCLUDE_CPPGC_MEMBER_H_ 6 #define INCLUDE_CPPGC_MEMBER_H_ 7 8 #include <atomic> 9 #include <cstddef> 10 #include <type_traits> 11 12 #include "cppgc/internal/pointer-policies.h" 13 #include "cppgc/type-traits.h" 14 #include "v8config.h" // NOLINT(build/include_directory) 15 16 namespace cppgc { 17 18 class Visitor; 19 20 namespace internal { 21 22 class MemberBase { 23 protected: 24 MemberBase() = default; MemberBase(void * value)25 explicit MemberBase(void* value) : raw_(value) {} 26 GetRawSlot()27 void** GetRawSlot() const { return &raw_; } GetRaw()28 void* GetRaw() const { return raw_; } SetRaw(void * value)29 void SetRaw(void* value) { raw_ = value; } 30 GetRawAtomic()31 void* GetRawAtomic() const { 32 return reinterpret_cast<const std::atomic<void*>*>(&raw_)->load( 33 std::memory_order_relaxed); 34 } SetRawAtomic(void * value)35 void SetRawAtomic(void* value) { 36 reinterpret_cast<std::atomic<void*>*>(&raw_)->store( 37 value, std::memory_order_relaxed); 38 } 39 ClearFromGC()40 void ClearFromGC() const { raw_ = nullptr; } 41 42 private: 43 mutable void* raw_ = nullptr; 44 }; 45 46 // The basic class from which all Member classes are 'generated'. 47 template <typename T, typename WeaknessTag, typename WriteBarrierPolicy, 48 typename CheckingPolicy> 49 class BasicMember final : private MemberBase, private CheckingPolicy { 50 public: 51 using PointeeType = T; 52 53 constexpr BasicMember() = default; BasicMember(std::nullptr_t)54 constexpr BasicMember(std::nullptr_t) {} // NOLINT BasicMember(SentinelPointer s)55 BasicMember(SentinelPointer s) : MemberBase(s) {} // NOLINT BasicMember(T * raw)56 BasicMember(T* raw) : MemberBase(raw) { // NOLINT 57 InitializingWriteBarrier(); 58 this->CheckPointer(Get()); 59 } BasicMember(T & raw)60 BasicMember(T& raw) : BasicMember(&raw) {} // NOLINT 61 // Copy ctor. BasicMember(const BasicMember & other)62 BasicMember(const BasicMember& other) : BasicMember(other.Get()) {} 63 // Allow heterogeneous construction. 64 template <typename U, typename OtherBarrierPolicy, typename OtherWeaknessTag, 65 typename OtherCheckingPolicy, 66 typename = std::enable_if_t<std::is_base_of<T, U>::value>> BasicMember(const BasicMember<U,OtherWeaknessTag,OtherBarrierPolicy,OtherCheckingPolicy> & other)67 BasicMember( // NOLINT 68 const BasicMember<U, OtherWeaknessTag, OtherBarrierPolicy, 69 OtherCheckingPolicy>& other) 70 : BasicMember(other.Get()) {} 71 // Move ctor. BasicMember(BasicMember && other)72 BasicMember(BasicMember&& other) noexcept : BasicMember(other.Get()) { 73 other.Clear(); 74 } 75 // Allow heterogeneous move construction. 76 template <typename U, typename OtherBarrierPolicy, typename OtherWeaknessTag, 77 typename OtherCheckingPolicy, 78 typename = std::enable_if_t<std::is_base_of<T, U>::value>> BasicMember(BasicMember<U,OtherWeaknessTag,OtherBarrierPolicy,OtherCheckingPolicy> && other)79 BasicMember( // NOLINT 80 BasicMember<U, OtherWeaknessTag, OtherBarrierPolicy, 81 OtherCheckingPolicy>&& other) noexcept 82 : BasicMember(other.Get()) { 83 other.Clear(); 84 } 85 // Construction from Persistent. 86 template <typename U, typename PersistentWeaknessPolicy, 87 typename PersistentLocationPolicy, 88 typename PersistentCheckingPolicy, 89 typename = std::enable_if_t<std::is_base_of<T, U>::value>> BasicMember(const BasicPersistent<U,PersistentWeaknessPolicy,PersistentLocationPolicy,PersistentCheckingPolicy> & p)90 BasicMember( // NOLINT 91 const BasicPersistent<U, PersistentWeaknessPolicy, 92 PersistentLocationPolicy, PersistentCheckingPolicy>& 93 p) 94 : BasicMember(p.Get()) {} 95 96 // Copy assignment. 97 BasicMember& operator=(const BasicMember& other) { 98 return operator=(other.Get()); 99 } 100 // Allow heterogeneous copy assignment. 101 template <typename U, typename OtherWeaknessTag, typename OtherBarrierPolicy, 102 typename OtherCheckingPolicy, 103 typename = std::enable_if_t<std::is_base_of<T, U>::value>> 104 BasicMember& operator=( 105 const BasicMember<U, OtherWeaknessTag, OtherBarrierPolicy, 106 OtherCheckingPolicy>& other) { 107 return operator=(other.Get()); 108 } 109 // Move assignment. 110 BasicMember& operator=(BasicMember&& other) noexcept { 111 operator=(other.Get()); 112 other.Clear(); 113 return *this; 114 } 115 // Heterogeneous move assignment. 116 template <typename U, typename OtherWeaknessTag, typename OtherBarrierPolicy, 117 typename OtherCheckingPolicy, 118 typename = std::enable_if_t<std::is_base_of<T, U>::value>> 119 BasicMember& operator=(BasicMember<U, OtherWeaknessTag, OtherBarrierPolicy, 120 OtherCheckingPolicy>&& other) noexcept { 121 operator=(other.Get()); 122 other.Clear(); 123 return *this; 124 } 125 // Assignment from Persistent. 126 template <typename U, typename PersistentWeaknessPolicy, 127 typename PersistentLocationPolicy, 128 typename PersistentCheckingPolicy, 129 typename = std::enable_if_t<std::is_base_of<T, U>::value>> 130 BasicMember& operator=( 131 const BasicPersistent<U, PersistentWeaknessPolicy, 132 PersistentLocationPolicy, PersistentCheckingPolicy>& 133 other) { 134 return operator=(other.Get()); 135 } 136 BasicMember& operator=(T* other) { 137 SetRawAtomic(other); 138 AssigningWriteBarrier(); 139 this->CheckPointer(Get()); 140 return *this; 141 } 142 BasicMember& operator=(std::nullptr_t) { 143 Clear(); 144 return *this; 145 } 146 BasicMember& operator=(SentinelPointer s) { 147 SetRawAtomic(s); 148 return *this; 149 } 150 151 template <typename OtherWeaknessTag, typename OtherBarrierPolicy, 152 typename OtherCheckingPolicy> Swap(BasicMember<T,OtherWeaknessTag,OtherBarrierPolicy,OtherCheckingPolicy> & other)153 void Swap(BasicMember<T, OtherWeaknessTag, OtherBarrierPolicy, 154 OtherCheckingPolicy>& other) { 155 T* tmp = Get(); 156 *this = other; 157 other = tmp; 158 } 159 160 explicit operator bool() const { return Get(); } 161 operator T*() const { return Get(); } // NOLINT 162 T* operator->() const { return Get(); } 163 T& operator*() const { return *Get(); } 164 165 // CFI cast exemption to allow passing SentinelPointer through T* and support 166 // heterogeneous assignments between different Member and Persistent handles 167 // based on their actual types. Get()168 V8_CLANG_NO_SANITIZE("cfi-unrelated-cast") T* Get() const { 169 // Executed by the mutator, hence non atomic load. 170 return static_cast<T*>(MemberBase::GetRaw()); 171 } 172 Clear()173 void Clear() { SetRawAtomic(nullptr); } 174 Release()175 T* Release() { 176 T* result = Get(); 177 Clear(); 178 return result; 179 } 180 GetSlotForTesting()181 const T** GetSlotForTesting() const { 182 return reinterpret_cast<const T**>(const_cast<const void**>(GetRawSlot())); 183 } 184 185 private: GetRawAtomic()186 T* GetRawAtomic() const { 187 return static_cast<T*>(MemberBase::GetRawAtomic()); 188 } 189 InitializingWriteBarrier()190 void InitializingWriteBarrier() const { 191 WriteBarrierPolicy::InitializingBarrier(GetRawSlot(), GetRaw()); 192 } AssigningWriteBarrier()193 void AssigningWriteBarrier() const { 194 WriteBarrierPolicy::AssigningBarrier(GetRawSlot(), GetRaw()); 195 } 196 ClearFromGC()197 void ClearFromGC() const { MemberBase::ClearFromGC(); } 198 199 friend class cppgc::Visitor; 200 }; 201 202 template <typename T1, typename WeaknessTag1, typename WriteBarrierPolicy1, 203 typename CheckingPolicy1, typename T2, typename WeaknessTag2, 204 typename WriteBarrierPolicy2, typename CheckingPolicy2> 205 bool operator==( 206 BasicMember<T1, WeaknessTag1, WriteBarrierPolicy1, CheckingPolicy1> member1, 207 BasicMember<T2, WeaknessTag2, WriteBarrierPolicy2, CheckingPolicy2> 208 member2) { 209 return member1.Get() == member2.Get(); 210 } 211 212 template <typename T1, typename WeaknessTag1, typename WriteBarrierPolicy1, 213 typename CheckingPolicy1, typename T2, typename WeaknessTag2, 214 typename WriteBarrierPolicy2, typename CheckingPolicy2> 215 bool operator!=( 216 BasicMember<T1, WeaknessTag1, WriteBarrierPolicy1, CheckingPolicy1> member1, 217 BasicMember<T2, WeaknessTag2, WriteBarrierPolicy2, CheckingPolicy2> 218 member2) { 219 return !(member1 == member2); 220 } 221 222 template <typename T, typename WriteBarrierPolicy, typename CheckingPolicy> 223 struct IsWeak< 224 internal::BasicMember<T, WeakMemberTag, WriteBarrierPolicy, CheckingPolicy>> 225 : std::true_type {}; 226 227 } // namespace internal 228 229 /** 230 * Members are used in classes to contain strong pointers to other garbage 231 * collected objects. All Member fields of a class must be traced in the class' 232 * trace method. 233 */ 234 template <typename T> 235 using Member = internal::BasicMember<T, internal::StrongMemberTag, 236 internal::DijkstraWriteBarrierPolicy>; 237 238 /** 239 * WeakMember is similar to Member in that it is used to point to other garbage 240 * collected objects. However instead of creating a strong pointer to the 241 * object, the WeakMember creates a weak pointer, which does not keep the 242 * pointee alive. Hence if all pointers to to a heap allocated object are weak 243 * the object will be garbage collected. At the time of GC the weak pointers 244 * will automatically be set to null. 245 */ 246 template <typename T> 247 using WeakMember = internal::BasicMember<T, internal::WeakMemberTag, 248 internal::DijkstraWriteBarrierPolicy>; 249 250 /** 251 * UntracedMember is a pointer to an on-heap object that is not traced for some 252 * reason. Do not use this unless you know what you are doing. Keeping raw 253 * pointers to on-heap objects is prohibited unless used from stack. Pointee 254 * must be kept alive through other means. 255 */ 256 template <typename T> 257 using UntracedMember = internal::BasicMember<T, internal::UntracedMemberTag, 258 internal::NoWriteBarrierPolicy>; 259 260 } // namespace cppgc 261 262 #endif // INCLUDE_CPPGC_MEMBER_H_ 263