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