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/api-constants.h" 13#include "cppgc/internal/member-storage.h" 14#include "cppgc/internal/pointer-policies.h" 15#include "cppgc/sentinel-pointer.h" 16#include "cppgc/type-traits.h" 17#include "v8config.h" // NOLINT(build/include_directory) 18 19namespace cppgc { 20 21namespace subtle { 22class HeapConsistency; 23} // namespace subtle 24 25class Visitor; 26 27namespace internal { 28 29// MemberBase always refers to the object as const object and defers to 30// BasicMember on casting to the right type as needed. 31template <typename StorageType> 32class V8_TRIVIAL_ABI MemberBase { 33 public: 34 using RawStorage = StorageType; 35 36 protected: 37 struct AtomicInitializerTag {}; 38 39 V8_INLINE MemberBase() = default; 40 V8_INLINE explicit MemberBase(const void* value) : raw_(value) {} 41 V8_INLINE MemberBase(const void* value, AtomicInitializerTag) { 42 SetRawAtomic(value); 43 } 44 45 V8_INLINE explicit MemberBase(RawStorage raw) : raw_(raw) {} 46 V8_INLINE explicit MemberBase(std::nullptr_t) : raw_(nullptr) {} 47 V8_INLINE explicit MemberBase(SentinelPointer s) : raw_(s) {} 48 49 V8_INLINE const void** GetRawSlot() const { 50 return reinterpret_cast<const void**>(const_cast<MemberBase*>(this)); 51 } 52 V8_INLINE const void* GetRaw() const { return raw_.Load(); } 53 V8_INLINE void SetRaw(void* value) { raw_.Store(value); } 54 55 V8_INLINE const void* GetRawAtomic() const { return raw_.LoadAtomic(); } 56 V8_INLINE void SetRawAtomic(const void* value) { raw_.StoreAtomic(value); } 57 58 V8_INLINE RawStorage GetRawStorage() const { return raw_; } 59 V8_INLINE void SetRawStorageAtomic(RawStorage other) { 60 reinterpret_cast<std::atomic<RawStorage>&>(raw_).store( 61 other, std::memory_order_relaxed); 62 } 63 64 V8_INLINE bool IsCleared() const { return raw_.IsCleared(); } 65 66 V8_INLINE void ClearFromGC() const { raw_.Clear(); } 67 68 private: 69 friend class MemberDebugHelper; 70 71 mutable RawStorage raw_; 72}; 73 74// The basic class from which all Member classes are 'generated'. 75template <typename T, typename WeaknessTag, typename WriteBarrierPolicy, 76 typename CheckingPolicy, typename StorageType> 77class V8_TRIVIAL_ABI BasicMember final : private MemberBase<StorageType>, 78 private CheckingPolicy { 79 using Base = MemberBase<StorageType>; 80 81 public: 82 using PointeeType = T; 83 using RawStorage = typename Base::RawStorage; 84 85 V8_INLINE constexpr BasicMember() = default; 86 V8_INLINE constexpr BasicMember(std::nullptr_t) {} // NOLINT 87 V8_INLINE BasicMember(SentinelPointer s) : Base(s) {} // NOLINT 88 V8_INLINE BasicMember(T* raw) : Base(raw) { // NOLINT 89 InitializingWriteBarrier(raw); 90 this->CheckPointer(Get()); 91 } 92 V8_INLINE BasicMember(T& raw) // NOLINT 93 : BasicMember(&raw) {} 94 95 // Atomic ctor. Using the AtomicInitializerTag forces BasicMember to 96 // initialize using atomic assignments. This is required for preventing 97 // data races with concurrent marking. 98 using AtomicInitializerTag = typename Base::AtomicInitializerTag; 99 V8_INLINE BasicMember(std::nullptr_t, AtomicInitializerTag atomic) 100 : Base(nullptr, atomic) {} 101 V8_INLINE BasicMember(SentinelPointer s, AtomicInitializerTag atomic) 102 : Base(s, atomic) {} 103 V8_INLINE BasicMember(T* raw, AtomicInitializerTag atomic) 104 : Base(raw, atomic) { 105 InitializingWriteBarrier(raw); 106 this->CheckPointer(Get()); 107 } 108 V8_INLINE BasicMember(T& raw, AtomicInitializerTag atomic) 109 : BasicMember(&raw, atomic) {} 110 111 // Copy ctor. 112 V8_INLINE BasicMember(const BasicMember& other) 113 : BasicMember(other.GetRawStorage()) {} 114 115 // Heterogeneous copy constructors. When the source pointer have a different 116 // type, perform a compress-decompress round, because the source pointer may 117 // need to be adjusted. 118 template <typename U, typename OtherBarrierPolicy, typename OtherWeaknessTag, 119 typename OtherCheckingPolicy, 120 std::enable_if_t<internal::IsDecayedSameV<T, U>>* = nullptr> 121 V8_INLINE BasicMember( // NOLINT 122 const BasicMember<U, OtherWeaknessTag, OtherBarrierPolicy, 123 OtherCheckingPolicy, StorageType>& other) 124 : BasicMember(other.GetRawStorage()) {} 125 126 template <typename U, typename OtherBarrierPolicy, typename OtherWeaknessTag, 127 typename OtherCheckingPolicy, 128 std::enable_if_t<internal::IsStrictlyBaseOfV<T, U>>* = nullptr> 129 V8_INLINE BasicMember( // NOLINT 130 const BasicMember<U, OtherWeaknessTag, OtherBarrierPolicy, 131 OtherCheckingPolicy, StorageType>& other) 132 : BasicMember(other.Get()) {} 133 134 // Move ctor. 135 V8_INLINE BasicMember(BasicMember&& other) noexcept 136 : BasicMember(other.GetRawStorage()) { 137 other.Clear(); 138 } 139 140 // Heterogeneous move constructors. When the source pointer have a different 141 // type, perform a compress-decompress round, because the source pointer may 142 // need to be adjusted. 143 template <typename U, typename OtherBarrierPolicy, typename OtherWeaknessTag, 144 typename OtherCheckingPolicy, 145 std::enable_if_t<internal::IsDecayedSameV<T, U>>* = nullptr> 146 V8_INLINE BasicMember( 147 BasicMember<U, OtherWeaknessTag, OtherBarrierPolicy, OtherCheckingPolicy, 148 StorageType>&& other) noexcept 149 : BasicMember(other.GetRawStorage()) { 150 other.Clear(); 151 } 152 153 template <typename U, typename OtherBarrierPolicy, typename OtherWeaknessTag, 154 typename OtherCheckingPolicy, 155 std::enable_if_t<internal::IsStrictlyBaseOfV<T, U>>* = nullptr> 156 V8_INLINE BasicMember( 157 BasicMember<U, OtherWeaknessTag, OtherBarrierPolicy, OtherCheckingPolicy, 158 StorageType>&& other) noexcept 159 : BasicMember(other.Get()) { 160 other.Clear(); 161 } 162 163 // Construction from Persistent. 164 template <typename U, typename PersistentWeaknessPolicy, 165 typename PersistentLocationPolicy, 166 typename PersistentCheckingPolicy, 167 typename = std::enable_if_t<std::is_base_of<T, U>::value>> 168 V8_INLINE BasicMember(const BasicPersistent<U, PersistentWeaknessPolicy, 169 PersistentLocationPolicy, 170 PersistentCheckingPolicy>& p) 171 : BasicMember(p.Get()) {} 172 173 // Copy assignment. 174 V8_INLINE BasicMember& operator=(const BasicMember& other) { 175 return operator=(other.GetRawStorage()); 176 } 177 178 // Heterogeneous copy assignment. When the source pointer have a different 179 // type, perform a compress-decompress round, because the source pointer may 180 // need to be adjusted. 181 template <typename U, typename OtherWeaknessTag, typename OtherBarrierPolicy, 182 typename OtherCheckingPolicy> 183 V8_INLINE BasicMember& operator=( 184 const BasicMember<U, OtherWeaknessTag, OtherBarrierPolicy, 185 OtherCheckingPolicy, StorageType>& other) { 186 if constexpr (internal::IsDecayedSameV<T, U>) { 187 return operator=(other.GetRawStorage()); 188 } else { 189 static_assert(internal::IsStrictlyBaseOfV<T, U>); 190 return operator=(other.Get()); 191 } 192 } 193 194 // Move assignment. 195 V8_INLINE BasicMember& operator=(BasicMember&& other) noexcept { 196 operator=(other.GetRawStorage()); 197 other.Clear(); 198 return *this; 199 } 200 201 // Heterogeneous move assignment. When the source pointer have a different 202 // type, perform a compress-decompress round, because the source pointer may 203 // need to be adjusted. 204 template <typename U, typename OtherWeaknessTag, typename OtherBarrierPolicy, 205 typename OtherCheckingPolicy> 206 V8_INLINE BasicMember& operator=( 207 BasicMember<U, OtherWeaknessTag, OtherBarrierPolicy, OtherCheckingPolicy, 208 StorageType>&& other) noexcept { 209 if constexpr (internal::IsDecayedSameV<T, U>) { 210 operator=(other.GetRawStorage()); 211 } else { 212 static_assert(internal::IsStrictlyBaseOfV<T, U>); 213 operator=(other.Get()); 214 } 215 other.Clear(); 216 return *this; 217 } 218 219 // Assignment from Persistent. 220 template <typename U, typename PersistentWeaknessPolicy, 221 typename PersistentLocationPolicy, 222 typename PersistentCheckingPolicy, 223 typename = std::enable_if_t<std::is_base_of<T, U>::value>> 224 V8_INLINE BasicMember& operator=( 225 const BasicPersistent<U, PersistentWeaknessPolicy, 226 PersistentLocationPolicy, PersistentCheckingPolicy>& 227 other) { 228 return operator=(other.Get()); 229 } 230 231 V8_INLINE BasicMember& operator=(T* other) { 232 Base::SetRawAtomic(other); 233 AssigningWriteBarrier(other); 234 this->CheckPointer(Get()); 235 return *this; 236 } 237 238 V8_INLINE BasicMember& operator=(std::nullptr_t) { 239 Clear(); 240 return *this; 241 } 242 V8_INLINE BasicMember& operator=(SentinelPointer s) { 243 Base::SetRawAtomic(s); 244 return *this; 245 } 246 247 template <typename OtherWeaknessTag, typename OtherBarrierPolicy, 248 typename OtherCheckingPolicy> 249 V8_INLINE void Swap(BasicMember<T, OtherWeaknessTag, OtherBarrierPolicy, 250 OtherCheckingPolicy, StorageType>& other) { 251 auto tmp = GetRawStorage(); 252 *this = other; 253 other = tmp; 254 } 255 256 V8_INLINE explicit operator bool() const { return !Base::IsCleared(); } 257 V8_INLINE operator T*() const { return Get(); } 258 V8_INLINE T* operator->() const { return Get(); } 259 V8_INLINE T& operator*() const { return *Get(); } 260 261 // CFI cast exemption to allow passing SentinelPointer through T* and support 262 // heterogeneous assignments between different Member and Persistent handles 263 // based on their actual types. 264 V8_INLINE V8_CLANG_NO_SANITIZE("cfi-unrelated-cast") T* Get() const { 265 // Executed by the mutator, hence non atomic load. 266 // 267 // The const_cast below removes the constness from MemberBase storage. The 268 // following static_cast re-adds any constness if specified through the 269 // user-visible template parameter T. 270 return static_cast<T*>(const_cast<void*>(Base::GetRaw())); 271 } 272 273 V8_INLINE void Clear() { 274 Base::SetRawStorageAtomic(RawStorage{}); 275 } 276 277 V8_INLINE T* Release() { 278 T* result = Get(); 279 Clear(); 280 return result; 281 } 282 283 V8_INLINE const T** GetSlotForTesting() const { 284 return reinterpret_cast<const T**>(Base::GetRawSlot()); 285 } 286 287 V8_INLINE RawStorage GetRawStorage() const { 288 return Base::GetRawStorage(); 289 } 290 291 private: 292 V8_INLINE explicit BasicMember(RawStorage raw) : Base(raw) { 293 InitializingWriteBarrier(Get()); 294 this->CheckPointer(Get()); 295 } 296 297 V8_INLINE BasicMember& operator=(RawStorage other) { 298 Base::SetRawStorageAtomic(other); 299 AssigningWriteBarrier(); 300 this->CheckPointer(Get()); 301 return *this; 302 } 303 304 V8_INLINE const T* GetRawAtomic() const { 305 return static_cast<const T*>(Base::GetRawAtomic()); 306 } 307 308 V8_INLINE void InitializingWriteBarrier(T* value) const { 309 WriteBarrierPolicy::InitializingBarrier(Base::GetRawSlot(), value); 310 } 311 V8_INLINE void AssigningWriteBarrier(T* value) const { 312 WriteBarrierPolicy::template AssigningBarrier< 313 StorageType::kWriteBarrierSlotType>(Base::GetRawSlot(), value); 314 } 315 V8_INLINE void AssigningWriteBarrier() const { 316 WriteBarrierPolicy::template AssigningBarrier< 317 StorageType::kWriteBarrierSlotType>(Base::GetRawSlot(), 318 Base::GetRawStorage()); 319 } 320 321 V8_INLINE void ClearFromGC() const { Base::ClearFromGC(); } 322 323 V8_INLINE T* GetFromGC() const { return Get(); } 324 325 friend class cppgc::subtle::HeapConsistency; 326 friend class cppgc::Visitor; 327 template <typename U> 328 friend struct cppgc::TraceTrait; 329 template <typename T1, typename WeaknessTag1, typename WriteBarrierPolicy1, 330 typename CheckingPolicy1, typename StorageType1> 331 friend class BasicMember; 332}; 333 334// Member equality operators. 335template <typename T1, typename WeaknessTag1, typename WriteBarrierPolicy1, 336 typename CheckingPolicy1, typename T2, typename WeaknessTag2, 337 typename WriteBarrierPolicy2, typename CheckingPolicy2, 338 typename StorageType> 339V8_INLINE bool operator==( 340 const BasicMember<T1, WeaknessTag1, WriteBarrierPolicy1, CheckingPolicy1, 341 StorageType>& member1, 342 const BasicMember<T2, WeaknessTag2, WriteBarrierPolicy2, CheckingPolicy2, 343 StorageType>& member2) { 344 if constexpr (internal::IsDecayedSameV<T1, T2>) { 345 // Check compressed pointers if types are the same. 346 return member1.GetRawStorage() == member2.GetRawStorage(); 347 } else { 348 static_assert(internal::IsStrictlyBaseOfV<T1, T2> || 349 internal::IsStrictlyBaseOfV<T2, T1>); 350 // Otherwise, check decompressed pointers. 351 return member1.Get() == member2.Get(); 352 } 353} 354 355template <typename T1, typename WeaknessTag1, typename WriteBarrierPolicy1, 356 typename CheckingPolicy1, typename T2, typename WeaknessTag2, 357 typename WriteBarrierPolicy2, typename CheckingPolicy2, 358 typename StorageType> 359V8_INLINE bool operator!=( 360 const BasicMember<T1, WeaknessTag1, WriteBarrierPolicy1, CheckingPolicy1, 361 StorageType>& member1, 362 const BasicMember<T2, WeaknessTag2, WriteBarrierPolicy2, CheckingPolicy2, 363 StorageType>& member2) { 364 return !(member1 == member2); 365} 366 367// Equality with raw pointers. 368template <typename T, typename WeaknessTag, typename WriteBarrierPolicy, 369 typename CheckingPolicy, typename StorageType, typename U> 370V8_INLINE bool operator==( 371 const BasicMember<T, WeaknessTag, WriteBarrierPolicy, CheckingPolicy, 372 StorageType>& member, 373 U* raw) { 374 // Never allow comparison with erased pointers. 375 static_assert(!internal::IsDecayedSameV<void, U>); 376 377 if constexpr (internal::IsDecayedSameV<T, U>) { 378 // Check compressed pointers if types are the same. 379 return member.GetRawStorage() == StorageType(raw); 380 } else if constexpr (internal::IsStrictlyBaseOfV<T, U>) { 381 // Cast the raw pointer to T, which may adjust the pointer. 382 return member.GetRawStorage() == StorageType(static_cast<T*>(raw)); 383 } else { 384 // Otherwise, decompressed the member. 385 return member.Get() == raw; 386 } 387} 388 389template <typename T, typename WeaknessTag, typename WriteBarrierPolicy, 390 typename CheckingPolicy, typename StorageType, typename U> 391V8_INLINE bool operator!=( 392 const BasicMember<T, WeaknessTag, WriteBarrierPolicy, CheckingPolicy, 393 StorageType>& member, 394 U* raw) { 395 return !(member == raw); 396} 397 398template <typename T, typename U, typename WeaknessTag, 399 typename WriteBarrierPolicy, typename CheckingPolicy, 400 typename StorageType> 401V8_INLINE bool operator==( 402 T* raw, const BasicMember<U, WeaknessTag, WriteBarrierPolicy, 403 CheckingPolicy, StorageType>& member) { 404 return member == raw; 405} 406 407template <typename T, typename U, typename WeaknessTag, 408 typename WriteBarrierPolicy, typename CheckingPolicy, 409 typename StorageType> 410V8_INLINE bool operator!=( 411 T* raw, const BasicMember<U, WeaknessTag, WriteBarrierPolicy, 412 CheckingPolicy, StorageType>& member) { 413 return !(raw == member); 414} 415 416// Equality with sentinel. 417template <typename T, typename WeaknessTag, typename WriteBarrierPolicy, 418 typename CheckingPolicy, typename StorageType> 419V8_INLINE bool operator==( 420 const BasicMember<T, WeaknessTag, WriteBarrierPolicy, CheckingPolicy, 421 StorageType>& member, 422 SentinelPointer) { 423 return member.GetRawStorage().IsSentinel(); 424} 425 426template <typename T, typename WeaknessTag, typename WriteBarrierPolicy, 427 typename CheckingPolicy, typename StorageType> 428V8_INLINE bool operator!=( 429 const BasicMember<T, WeaknessTag, WriteBarrierPolicy, CheckingPolicy, 430 StorageType>& member, 431 SentinelPointer s) { 432 return !(member == s); 433} 434 435template <typename T, typename WeaknessTag, typename WriteBarrierPolicy, 436 typename CheckingPolicy, typename StorageType> 437V8_INLINE bool operator==( 438 SentinelPointer s, const BasicMember<T, WeaknessTag, WriteBarrierPolicy, 439 CheckingPolicy, StorageType>& member) { 440 return member == s; 441} 442 443template <typename T, typename WeaknessTag, typename WriteBarrierPolicy, 444 typename CheckingPolicy, typename StorageType> 445V8_INLINE bool operator!=( 446 SentinelPointer s, const BasicMember<T, WeaknessTag, WriteBarrierPolicy, 447 CheckingPolicy, StorageType>& member) { 448 return !(s == member); 449} 450 451// Equality with nullptr. 452template <typename T, typename WeaknessTag, typename WriteBarrierPolicy, 453 typename CheckingPolicy, typename StorageType> 454V8_INLINE bool operator==( 455 const BasicMember<T, WeaknessTag, WriteBarrierPolicy, CheckingPolicy, 456 StorageType>& member, 457 std::nullptr_t) { 458 return !static_cast<bool>(member); 459} 460 461template <typename T, typename WeaknessTag, typename WriteBarrierPolicy, 462 typename CheckingPolicy, typename StorageType> 463V8_INLINE bool operator!=( 464 const BasicMember<T, WeaknessTag, WriteBarrierPolicy, CheckingPolicy, 465 StorageType>& member, 466 std::nullptr_t n) { 467 return !(member == n); 468} 469 470template <typename T, typename WeaknessTag, typename WriteBarrierPolicy, 471 typename CheckingPolicy, typename StorageType> 472V8_INLINE bool operator==( 473 std::nullptr_t n, const BasicMember<T, WeaknessTag, WriteBarrierPolicy, 474 CheckingPolicy, StorageType>& member) { 475 return member == n; 476} 477 478template <typename T, typename WeaknessTag, typename WriteBarrierPolicy, 479 typename CheckingPolicy, typename StorageType> 480V8_INLINE bool operator!=( 481 std::nullptr_t n, const BasicMember<T, WeaknessTag, WriteBarrierPolicy, 482 CheckingPolicy, StorageType>& member) { 483 return !(n == member); 484} 485 486// Relational operators. 487template <typename T1, typename WeaknessTag1, typename WriteBarrierPolicy1, 488 typename CheckingPolicy1, typename T2, typename WeaknessTag2, 489 typename WriteBarrierPolicy2, typename CheckingPolicy2, 490 typename StorageType> 491V8_INLINE bool operator<( 492 const BasicMember<T1, WeaknessTag1, WriteBarrierPolicy1, CheckingPolicy1, 493 StorageType>& member1, 494 const BasicMember<T2, WeaknessTag2, WriteBarrierPolicy2, CheckingPolicy2, 495 StorageType>& member2) { 496 static_assert( 497 internal::IsDecayedSameV<T1, T2>, 498 "Comparison works only for same pointer type modulo cv-qualifiers"); 499 return member1.GetRawStorage() < member2.GetRawStorage(); 500} 501 502template <typename T1, typename WeaknessTag1, typename WriteBarrierPolicy1, 503 typename CheckingPolicy1, typename T2, typename WeaknessTag2, 504 typename WriteBarrierPolicy2, typename CheckingPolicy2, 505 typename StorageType> 506V8_INLINE bool operator<=( 507 const BasicMember<T1, WeaknessTag1, WriteBarrierPolicy1, CheckingPolicy1, 508 StorageType>& member1, 509 const BasicMember<T2, WeaknessTag2, WriteBarrierPolicy2, CheckingPolicy2, 510 StorageType>& member2) { 511 static_assert( 512 internal::IsDecayedSameV<T1, T2>, 513 "Comparison works only for same pointer type modulo cv-qualifiers"); 514 return member1.GetRawStorage() <= member2.GetRawStorage(); 515} 516 517template <typename T1, typename WeaknessTag1, typename WriteBarrierPolicy1, 518 typename CheckingPolicy1, typename T2, typename WeaknessTag2, 519 typename WriteBarrierPolicy2, typename CheckingPolicy2, 520 typename StorageType> 521V8_INLINE bool operator>( 522 const BasicMember<T1, WeaknessTag1, WriteBarrierPolicy1, CheckingPolicy1, 523 StorageType>& member1, 524 const BasicMember<T2, WeaknessTag2, WriteBarrierPolicy2, CheckingPolicy2, 525 StorageType>& member2) { 526 static_assert( 527 internal::IsDecayedSameV<T1, T2>, 528 "Comparison works only for same pointer type modulo cv-qualifiers"); 529 return member1.GetRawStorage() > member2.GetRawStorage(); 530} 531 532template <typename T1, typename WeaknessTag1, typename WriteBarrierPolicy1, 533 typename CheckingPolicy1, typename T2, typename WeaknessTag2, 534 typename WriteBarrierPolicy2, typename CheckingPolicy2, 535 typename StorageType> 536V8_INLINE bool operator>=( 537 const BasicMember<T1, WeaknessTag1, WriteBarrierPolicy1, CheckingPolicy1, 538 StorageType>& member1, 539 const BasicMember<T2, WeaknessTag2, WriteBarrierPolicy2, CheckingPolicy2, 540 StorageType>& member2) { 541 static_assert( 542 internal::IsDecayedSameV<T1, T2>, 543 "Comparison works only for same pointer type modulo cv-qualifiers"); 544 return member1.GetRawStorage() >= member2.GetRawStorage(); 545} 546 547template <typename T, typename WriteBarrierPolicy, typename CheckingPolicy, 548 typename StorageType> 549struct IsWeak<internal::BasicMember<T, WeakMemberTag, WriteBarrierPolicy, 550 CheckingPolicy, StorageType>> 551 : std::true_type {}; 552 553} // namespace internal 554 555/** 556 * Members are used in classes to contain strong pointers to other garbage 557 * collected objects. All Member fields of a class must be traced in the class' 558 * trace method. 559 */ 560template <typename T> 561using Member = internal::BasicMember< 562 T, internal::StrongMemberTag, internal::DijkstraWriteBarrierPolicy, 563 internal::DefaultMemberCheckingPolicy, internal::DefaultMemberStorage>; 564 565/** 566 * WeakMember is similar to Member in that it is used to point to other garbage 567 * collected objects. However instead of creating a strong pointer to the 568 * object, the WeakMember creates a weak pointer, which does not keep the 569 * pointee alive. Hence if all pointers to to a heap allocated object are weak 570 * the object will be garbage collected. At the time of GC the weak pointers 571 * will automatically be set to null. 572 */ 573template <typename T> 574using WeakMember = internal::BasicMember< 575 T, internal::WeakMemberTag, internal::DijkstraWriteBarrierPolicy, 576 internal::DefaultMemberCheckingPolicy, internal::DefaultMemberStorage>; 577 578/** 579 * UntracedMember is a pointer to an on-heap object that is not traced for some 580 * reason. Do not use this unless you know what you are doing. Keeping raw 581 * pointers to on-heap objects is prohibited unless used from stack. Pointee 582 * must be kept alive through other means. 583 */ 584template <typename T> 585using UntracedMember = internal::BasicMember< 586 T, internal::UntracedMemberTag, internal::NoWriteBarrierPolicy, 587 internal::DefaultMemberCheckingPolicy, internal::DefaultMemberStorage>; 588 589namespace subtle { 590 591/** 592 * UncompressedMember. Use with care in hot paths that would otherwise cause 593 * many decompression cycles. 594 */ 595template <typename T> 596using UncompressedMember = internal::BasicMember< 597 T, internal::StrongMemberTag, internal::DijkstraWriteBarrierPolicy, 598 internal::DefaultMemberCheckingPolicy, internal::RawPointer>; 599 600} // namespace subtle 601 602} // namespace cppgc 603 604#endif // INCLUDE_CPPGC_MEMBER_H_ 605