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