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
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 PersistentRegionBase;
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>>
122  const internal::BasicMember<U, MemberBarrierPolicy, MemberWeaknessTag,
123  MemberCheckingPolicy>& 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  const internal::BasicMember<U, MemberBarrierPolicy, MemberWeaknessTag,
163  MemberCheckingPolicy>& member) {
164  return operator=(member.Get());
165  }
166 
167  BasicPersistent& operator=(T* other) {
168  Assign(other);
169  return *this;
170  }
171 
172  BasicPersistent& operator=(std::nullptr_t) {
173  Clear();
174  return *this;
175  }
176 
178  Assign(s);
179  return *this;
180  }
181 
182  explicit operator bool() const { return Get(); }
183  operator T*() const { return Get(); }
184  T* operator->() const { return Get(); }
185  T& operator*() const { return *Get(); }
186 
187  // CFI cast exemption to allow passing SentinelPointer through T* and support
188  // heterogeneous assignments between different Member and Persistent handles
189  // based on their actual types.
190  V8_CLANG_NO_SANITIZE("cfi-unrelated-cast") T* Get() const {
191  // The const_cast below removes the constness from PersistentBase storage.
192  // The following static_cast re-adds any constness if specified through the
193  // user-visible template parameter T.
194  return static_cast<T*>(const_cast<void*>(GetValue()));
195  }
196 
197  void Clear() {
198  // Simplified version of `Assign()` to allow calling without a complete type
199  // `T`.
200  if (IsValid()) {
201  WeaknessPolicy::GetPersistentRegion(GetValue()).FreeNode(GetNode());
202  SetNode(nullptr);
203  }
204  SetValue(nullptr);
205  }
206 
207  T* Release() {
208  T* result = Get();
209  Clear();
210  return result;
211  }
212 
213  template <typename U, typename OtherWeaknessPolicy = WeaknessPolicy,
214  typename OtherLocationPolicy = LocationPolicy,
215  typename OtherCheckingPolicy = CheckingPolicy>
216  BasicPersistent<U, OtherWeaknessPolicy, OtherLocationPolicy,
217  OtherCheckingPolicy>
218  To() const {
219  return BasicPersistent<U, OtherWeaknessPolicy, OtherLocationPolicy,
220  OtherCheckingPolicy>(static_cast<U*>(Get()));
221  }
222 
223  private:
224  static void Trace(Visitor* v, const void* ptr) {
225  const auto* persistent = static_cast<const BasicPersistent*>(ptr);
226  v->TraceRoot(*persistent, persistent->Location());
227  }
228 
229  bool IsValid() const {
230  // Ideally, handling kSentinelPointer would be done by the embedder. On the
231  // other hand, having Persistent aware of it is beneficial since no node
232  // gets wasted.
233  return GetValue() != nullptr && GetValue() != kSentinelPointer;
234  }
235 
236  void Assign(T* ptr) {
237  if (IsValid()) {
238  if (ptr && ptr != kSentinelPointer) {
239  // Simply assign the pointer reusing the existing node.
240  SetValue(ptr);
241  this->CheckPointer(ptr);
242  return;
243  }
244  WeaknessPolicy::GetPersistentRegion(GetValue()).FreeNode(GetNode());
245  SetNode(nullptr);
246  }
247  SetValue(ptr);
248  if (!IsValid()) return;
249  SetNode(WeaknessPolicy::GetPersistentRegion(GetValue())
250  .AllocateNode(this, &BasicPersistent::Trace));
251  this->CheckPointer(Get());
252  }
253 
254  void ClearFromGC() const {
255  if (IsValid()) {
256  WeaknessPolicy::GetPersistentRegion(GetValue()).FreeNode(GetNode());
258  }
259  }
260 
261  // Set Get() for details.
262  V8_CLANG_NO_SANITIZE("cfi-unrelated-cast")
263  T* GetFromGC() const {
264  return static_cast<T*>(const_cast<void*>(GetValue()));
265  }
266 
267  friend class cppgc::Visitor;
268 };
269 
270 template <typename T1, typename WeaknessPolicy1, typename LocationPolicy1,
271  typename CheckingPolicy1, typename T2, typename WeaknessPolicy2,
272  typename LocationPolicy2, typename CheckingPolicy2>
273 bool operator==(const BasicPersistent<T1, WeaknessPolicy1, LocationPolicy1,
274  CheckingPolicy1>& p1,
275  const BasicPersistent<T2, WeaknessPolicy2, LocationPolicy2,
276  CheckingPolicy2>& p2) {
277  return p1.Get() == p2.Get();
278 }
279 
280 template <typename T1, typename WeaknessPolicy1, typename LocationPolicy1,
281  typename CheckingPolicy1, typename T2, typename WeaknessPolicy2,
282  typename LocationPolicy2, typename CheckingPolicy2>
283 bool operator!=(const BasicPersistent<T1, WeaknessPolicy1, LocationPolicy1,
284  CheckingPolicy1>& p1,
285  const BasicPersistent<T2, WeaknessPolicy2, LocationPolicy2,
286  CheckingPolicy2>& p2) {
287  return !(p1 == p2);
288 }
289 
290 template <typename T1, typename PersistentWeaknessPolicy,
291  typename PersistentLocationPolicy, typename PersistentCheckingPolicy,
292  typename T2, typename MemberWriteBarrierPolicy,
293  typename MemberWeaknessTag, typename MemberCheckingPolicy>
294 bool operator==(
295  const BasicPersistent<T1, PersistentWeaknessPolicy,
296  PersistentLocationPolicy, PersistentCheckingPolicy>&
297  p,
298  const BasicMember<T2, MemberWeaknessTag, MemberWriteBarrierPolicy,
299  MemberCheckingPolicy>& m) {
300  return p.Get() == m.Get();
301 }
302 
303 template <typename T1, typename PersistentWeaknessPolicy,
304  typename PersistentLocationPolicy, typename PersistentCheckingPolicy,
305  typename T2, typename MemberWriteBarrierPolicy,
306  typename MemberWeaknessTag, typename MemberCheckingPolicy>
307 bool operator!=(
308  const BasicPersistent<T1, PersistentWeaknessPolicy,
309  PersistentLocationPolicy, PersistentCheckingPolicy>&
310  p,
311  const BasicMember<T2, MemberWeaknessTag, MemberWriteBarrierPolicy,
312  MemberCheckingPolicy>& m) {
313  return !(p == m);
314 }
315 
316 template <typename T1, typename MemberWriteBarrierPolicy,
317  typename MemberWeaknessTag, typename MemberCheckingPolicy,
318  typename T2, typename PersistentWeaknessPolicy,
319  typename PersistentLocationPolicy, typename PersistentCheckingPolicy>
320 bool operator==(
321  const BasicMember<T2, MemberWeaknessTag, MemberWriteBarrierPolicy,
322  MemberCheckingPolicy>& m,
323  const BasicPersistent<T1, PersistentWeaknessPolicy,
324  PersistentLocationPolicy, PersistentCheckingPolicy>&
325  p) {
326  return m.Get() == p.Get();
327 }
328 
329 template <typename T1, typename MemberWriteBarrierPolicy,
330  typename MemberWeaknessTag, typename MemberCheckingPolicy,
331  typename T2, typename PersistentWeaknessPolicy,
332  typename PersistentLocationPolicy, typename PersistentCheckingPolicy>
333 bool operator!=(
334  const BasicMember<T2, MemberWeaknessTag, MemberWriteBarrierPolicy,
335  MemberCheckingPolicy>& m,
336  const BasicPersistent<T1, PersistentWeaknessPolicy,
337  PersistentLocationPolicy, PersistentCheckingPolicy>&
338  p) {
339  return !(m == p);
340 }
341 
342 template <typename T, typename LocationPolicy, typename CheckingPolicy>
344  CheckingPolicy>> : std::true_type {};
345 } // namespace internal
346 
347 /**
348  * Persistent is a way to create a strong pointer from an off-heap object to
349  * another on-heap object. As long as the Persistent handle is alive the GC will
350  * keep the object pointed to alive. The Persistent handle is always a GC root
351  * from the point of view of the GC. Persistent must be constructed and
352  * destructed in the same thread.
353  */
354 template <typename T>
355 using Persistent =
357 
358 /**
359  * WeakPersistent is a way to create a weak pointer from an off-heap object to
360  * an on-heap object. The pointer is automatically cleared when the pointee gets
361  * collected. WeakPersistent must be constructed and destructed in the same
362  * thread.
363  */
364 template <typename T>
365 using WeakPersistent =
367 
368 } // namespace cppgc
369 
370 #endif // INCLUDE_CPPGC_PERSISTENT_H_