v8  10.1.124 (node 18.2.0)
V8 is Google's open source JavaScript engine
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_