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