v8  8.6.395 (node 15.0.1)
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/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_