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