v8  9.4.146 (node 16.13.0)
V8 is Google's open source JavaScript engine
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
persistent.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_PERSISTENT_H_
6 #define INCLUDE_CPPGC_PERSISTENT_H_
7 
8 #include <type_traits>
9 
10 #include "cppgc/internal/persistent-node.h"
11 #include "cppgc/internal/pointer-policies.h"
12 #include "cppgc/sentinel-pointer.h"
13 #include "cppgc/source-location.h"
14 #include "cppgc/type-traits.h"
15 #include "cppgc/visitor.h"
16 #include "v8config.h" // NOLINT(build/include_directory)
17 
18 namespace cppgc {
19 
20 class Visitor;
21 
22 namespace internal {
23 
24 // PersistentBase always refers to the object as const object and defers to
25 // BasicPersistent on casting to the right type as needed.
27  protected:
28  PersistentBase() = default;
29  explicit PersistentBase(const void* raw) : raw_(raw) {}
30 
31  const void* GetValue() const { return raw_; }
32  void SetValue(const void* value) { raw_ = value; }
33 
34  PersistentNode* GetNode() const { return node_; }
35  void SetNode(PersistentNode* node) { node_ = node; }
36 
37  // Performs a shallow clear which assumes that internal persistent nodes are
38  // destroyed elsewhere.
39  void ClearFromGC() const {
40  raw_ = nullptr;
41  node_ = nullptr;
42  }
43 
44  protected:
45  mutable const void* raw_ = nullptr;
46  mutable PersistentNode* node_ = nullptr;
47 
48  friend class PersistentRegion;
49 };
50 
51 // The basic class from which all Persistent classes are generated.
52 template <typename T, typename WeaknessPolicy, typename LocationPolicy,
53  typename CheckingPolicy>
54 class BasicPersistent final : public PersistentBase,
55  public LocationPolicy,
56  private WeaknessPolicy,
57  private CheckingPolicy {
58  public:
59  using typename WeaknessPolicy::IsStrongPersistent;
60  using PointeeType = T;
61 
62  // Null-state/sentinel constructors.
63  BasicPersistent( // NOLINT
64  const SourceLocation& loc = SourceLocation::Current())
65  : LocationPolicy(loc) {}
66 
67  BasicPersistent(std::nullptr_t, // NOLINT
68  const SourceLocation& loc = SourceLocation::Current())
69  : LocationPolicy(loc) {}
70 
71  BasicPersistent( // NOLINT
72  SentinelPointer s, const SourceLocation& loc = SourceLocation::Current())
73  : PersistentBase(s), LocationPolicy(loc) {}
74 
75  // Raw value constructors.
76  BasicPersistent(T* raw, // NOLINT
77  const SourceLocation& loc = SourceLocation::Current())
78  : PersistentBase(raw), LocationPolicy(loc) {
79  if (!IsValid()) return;
80  SetNode(WeaknessPolicy::GetPersistentRegion(GetValue())
81  .AllocateNode(this, &BasicPersistent::Trace));
82  this->CheckPointer(Get());
83  }
84 
85  BasicPersistent(T& raw, // NOLINT
86  const SourceLocation& loc = SourceLocation::Current())
87  : BasicPersistent(&raw, loc) {}
88 
89  // Copy ctor.
91  const SourceLocation& loc = SourceLocation::Current())
92  : BasicPersistent(other.Get(), loc) {}
93 
94  // Heterogeneous ctor.
95  template <typename U, typename OtherWeaknessPolicy,
96  typename OtherLocationPolicy, typename OtherCheckingPolicy,
97  typename = std::enable_if_t<std::is_base_of<T, U>::value>>
99  const BasicPersistent<U, OtherWeaknessPolicy, OtherLocationPolicy,
100  OtherCheckingPolicy>& other,
101  const SourceLocation& loc = SourceLocation::Current())
102  : BasicPersistent(other.Get(), loc) {}
103 
104  // Move ctor. The heterogeneous move ctor is not supported since e.g.
105  // persistent can't reuse persistent node from weak persistent.
107  BasicPersistent&& other,
108  const SourceLocation& loc = SourceLocation::Current()) noexcept
109  : PersistentBase(std::move(other)), LocationPolicy(std::move(other)) {
110  if (!IsValid()) return;
111  GetNode()->UpdateOwner(this);
112  other.SetValue(nullptr);
113  other.SetNode(nullptr);
114  this->CheckPointer(Get());
115  }
116 
117  // Constructor from member.
118  template <typename U, typename MemberBarrierPolicy,
119  typename MemberWeaknessTag, typename MemberCheckingPolicy,
120  typename = std::enable_if_t<std::is_base_of<T, U>::value>>
121  BasicPersistent(internal::BasicMember<U, MemberBarrierPolicy,
122  MemberWeaknessTag, MemberCheckingPolicy>
123  member,
124  const SourceLocation& loc = SourceLocation::Current())
125  : BasicPersistent(member.Get(), loc) {}
126 
128 
129  // Copy assignment.
131  return operator=(other.Get());
132  }
133 
134  template <typename U, typename OtherWeaknessPolicy,
135  typename OtherLocationPolicy, typename OtherCheckingPolicy,
136  typename = std::enable_if_t<std::is_base_of<T, U>::value>>
138  const BasicPersistent<U, OtherWeaknessPolicy, OtherLocationPolicy,
139  OtherCheckingPolicy>& other) {
140  return operator=(other.Get());
141  }
142 
143  // Move assignment.
145  if (this == &other) return *this;
146  Clear();
147  PersistentBase::operator=(std::move(other));
148  LocationPolicy::operator=(std::move(other));
149  if (!IsValid()) return *this;
150  GetNode()->UpdateOwner(this);
151  other.SetValue(nullptr);
152  other.SetNode(nullptr);
153  this->CheckPointer(Get());
154  return *this;
155  }
156 
157  // Assignment from member.
158  template <typename U, typename MemberBarrierPolicy,
159  typename MemberWeaknessTag, typename MemberCheckingPolicy,
160  typename = std::enable_if_t<std::is_base_of<T, U>::value>>
162  internal::BasicMember<U, MemberBarrierPolicy, MemberWeaknessTag,
163  MemberCheckingPolicy>
164  member) {
165  return operator=(member.Get());
166  }
167 
168  BasicPersistent& operator=(T* other) {
169  Assign(other);
170  return *this;
171  }
172 
173  BasicPersistent& operator=(std::nullptr_t) {
174  Clear();
175  return *this;
176  }
177 
179  Assign(s);
180  return *this;
181  }
182 
183  explicit operator bool() const { return Get(); }
184  operator T*() const { return Get(); }
185  T* operator->() const { return Get(); }
186  T& operator*() const { return *Get(); }
187 
188  // CFI cast exemption to allow passing SentinelPointer through T* and support
189  // heterogeneous assignments between different Member and Persistent handles
190  // based on their actual types.
191  V8_CLANG_NO_SANITIZE("cfi-unrelated-cast") T* Get() const {
192  // The const_cast below removes the constness from PersistentBase storage.
193  // The 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*>(GetValue()));
196  }
197 
198  void Clear() {
199  // Simplified version of `Assign()` to allow calling without a complete type
200  // `T`.
201  if (IsValid()) {
202  WeaknessPolicy::GetPersistentRegion(GetValue()).FreeNode(GetNode());
203  SetNode(nullptr);
204  }
205  SetValue(nullptr);
206  }
207 
208  T* Release() {
209  T* result = Get();
210  Clear();
211  return result;
212  }
213 
214  template <typename U, typename OtherWeaknessPolicy = WeaknessPolicy,
215  typename OtherLocationPolicy = LocationPolicy,
216  typename OtherCheckingPolicy = CheckingPolicy>
217  BasicPersistent<U, OtherWeaknessPolicy, OtherLocationPolicy,
218  OtherCheckingPolicy>
219  To() const {
220  return BasicPersistent<U, OtherWeaknessPolicy, OtherLocationPolicy,
221  OtherCheckingPolicy>(static_cast<U*>(Get()));
222  }
223 
224  private:
225  static void Trace(Visitor* v, const void* ptr) {
226  const auto* persistent = static_cast<const BasicPersistent*>(ptr);
227  v->TraceRoot(*persistent, persistent->Location());
228  }
229 
230  bool IsValid() const {
231  // Ideally, handling kSentinelPointer would be done by the embedder. On the
232  // other hand, having Persistent aware of it is beneficial since no node
233  // gets wasted.
234  return GetValue() != nullptr && GetValue() != kSentinelPointer;
235  }
236 
237  void Assign(T* ptr) {
238  if (IsValid()) {
239  if (ptr && ptr != kSentinelPointer) {
240  // Simply assign the pointer reusing the existing node.
241  SetValue(ptr);
242  this->CheckPointer(ptr);
243  return;
244  }
245  WeaknessPolicy::GetPersistentRegion(GetValue()).FreeNode(GetNode());
246  SetNode(nullptr);
247  }
248  SetValue(ptr);
249  if (!IsValid()) return;
250  SetNode(WeaknessPolicy::GetPersistentRegion(GetValue())
251  .AllocateNode(this, &BasicPersistent::Trace));
252  this->CheckPointer(Get());
253  }
254 
255  void ClearFromGC() const {
256  if (IsValid()) {
257  WeaknessPolicy::GetPersistentRegion(GetValue()).FreeNode(GetNode());
259  }
260  }
261 
262  // Set Get() for details.
263  V8_CLANG_NO_SANITIZE("cfi-unrelated-cast")
264  T* GetFromGC() const {
265  return static_cast<T*>(const_cast<void*>(GetValue()));
266  }
267 
268  friend class cppgc::Visitor;
269 };
270 
271 template <typename T1, typename WeaknessPolicy1, typename LocationPolicy1,
272  typename CheckingPolicy1, typename T2, typename WeaknessPolicy2,
273  typename LocationPolicy2, typename CheckingPolicy2>
274 bool operator==(const BasicPersistent<T1, WeaknessPolicy1, LocationPolicy1,
275  CheckingPolicy1>& p1,
276  const BasicPersistent<T2, WeaknessPolicy2, LocationPolicy2,
277  CheckingPolicy2>& p2) {
278  return p1.Get() == p2.Get();
279 }
280 
281 template <typename T1, typename WeaknessPolicy1, typename LocationPolicy1,
282  typename CheckingPolicy1, typename T2, typename WeaknessPolicy2,
283  typename LocationPolicy2, typename CheckingPolicy2>
284 bool operator!=(const BasicPersistent<T1, WeaknessPolicy1, LocationPolicy1,
285  CheckingPolicy1>& p1,
286  const BasicPersistent<T2, WeaknessPolicy2, LocationPolicy2,
287  CheckingPolicy2>& p2) {
288  return !(p1 == p2);
289 }
290 
291 template <typename T1, typename PersistentWeaknessPolicy,
292  typename PersistentLocationPolicy, typename PersistentCheckingPolicy,
293  typename T2, typename MemberWriteBarrierPolicy,
294  typename MemberWeaknessTag, typename MemberCheckingPolicy>
295 bool operator==(const BasicPersistent<T1, PersistentWeaknessPolicy,
296  PersistentLocationPolicy,
297  PersistentCheckingPolicy>& p,
298  BasicMember<T2, MemberWeaknessTag, MemberWriteBarrierPolicy,
299  MemberCheckingPolicy>
300  m) {
301  return p.Get() == m.Get();
302 }
303 
304 template <typename T1, typename PersistentWeaknessPolicy,
305  typename PersistentLocationPolicy, typename PersistentCheckingPolicy,
306  typename T2, typename MemberWriteBarrierPolicy,
307  typename MemberWeaknessTag, typename MemberCheckingPolicy>
308 bool operator!=(const BasicPersistent<T1, PersistentWeaknessPolicy,
309  PersistentLocationPolicy,
310  PersistentCheckingPolicy>& p,
311  BasicMember<T2, MemberWeaknessTag, MemberWriteBarrierPolicy,
312  MemberCheckingPolicy>
313  m) {
314  return !(p == m);
315 }
316 
317 template <typename T1, typename MemberWriteBarrierPolicy,
318  typename MemberWeaknessTag, typename MemberCheckingPolicy,
319  typename T2, typename PersistentWeaknessPolicy,
320  typename PersistentLocationPolicy, typename PersistentCheckingPolicy>
321 bool operator==(BasicMember<T2, MemberWeaknessTag, MemberWriteBarrierPolicy,
322  MemberCheckingPolicy>
323  m,
324  const BasicPersistent<T1, PersistentWeaknessPolicy,
325  PersistentLocationPolicy,
326  PersistentCheckingPolicy>& p) {
327  return m.Get() == p.Get();
328 }
329 
330 template <typename T1, typename MemberWriteBarrierPolicy,
331  typename MemberWeaknessTag, typename MemberCheckingPolicy,
332  typename T2, typename PersistentWeaknessPolicy,
333  typename PersistentLocationPolicy, typename PersistentCheckingPolicy>
334 bool operator!=(BasicMember<T2, MemberWeaknessTag, MemberWriteBarrierPolicy,
335  MemberCheckingPolicy>
336  m,
337  const BasicPersistent<T1, PersistentWeaknessPolicy,
338  PersistentLocationPolicy,
339  PersistentCheckingPolicy>& p) {
340  return !(m == p);
341 }
342 
343 template <typename T, typename LocationPolicy, typename CheckingPolicy>
345  CheckingPolicy>> : std::true_type {};
346 } // namespace internal
347 
348 /**
349  * Persistent is a way to create a strong pointer from an off-heap object to
350  * another on-heap object. As long as the Persistent handle is alive the GC will
351  * keep the object pointed to alive. The Persistent handle is always a GC root
352  * from the point of view of the GC. Persistent must be constructed and
353  * destructed in the same thread.
354  */
355 template <typename T>
356 using Persistent =
358 
359 /**
360  * WeakPersistent is a way to create a weak pointer from an off-heap object to
361  * an on-heap object. The pointer is automatically cleared when the pointee gets
362  * collected. WeakPersistent must be constructed and destructed in the same
363  * thread.
364  */
365 template <typename T>
366 using WeakPersistent =
368 
369 } // namespace cppgc
370 
371 #endif // INCLUDE_CPPGC_PERSISTENT_H_