v8  8.4.371 (node 14.15.5)
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 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_