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