v8  10.1.124 (node 18.2.0)
V8 is Google's open source JavaScript engine
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
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_