• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
23 class PersistentBase {
24  protected:
25   PersistentBase() = default;
PersistentBase(void * raw)26   explicit PersistentBase(void* raw) : raw_(raw) {}
27 
GetValue()28   void* GetValue() const { return raw_; }
SetValue(void * value)29   void SetValue(void* value) { raw_ = value; }
30 
GetNode()31   PersistentNode* GetNode() const { return node_; }
SetNode(PersistentNode * node)32   void SetNode(PersistentNode* node) { node_ = node; }
33 
34   // Performs a shallow clear which assumes that internal persistent nodes are
35   // destroyed elsewhere.
ClearFromGC()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())
LocationPolicy(loc)62       : LocationPolicy(loc) {}
63 
64   BasicPersistent(std::nullptr_t,  // NOLINT
65                   const SourceLocation& loc = SourceLocation::Current())
LocationPolicy(loc)66       : LocationPolicy(loc) {}
67 
68   BasicPersistent(  // NOLINT
69       SentinelPointer s, const SourceLocation& loc = SourceLocation::Current())
PersistentBase(s)70       : PersistentBase(s), LocationPolicy(loc) {}
71 
72   // Raw value constructors.
73   BasicPersistent(T* raw,  // NOLINT
74                   const SourceLocation& loc = SourceLocation::Current())
PersistentBase(raw)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.
87   BasicPersistent(const BasicPersistent& other,
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.
103   BasicPersistent(
104       BasicPersistent&& other,
105       const SourceLocation& loc = SourceLocation::Current()) noexcept
PersistentBase(std::move (other))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 
~BasicPersistent()124   ~BasicPersistent() { Clear(); }
125 
126   // Copy assignment.
127   BasicPersistent& operator=(const BasicPersistent& other) {
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>>
134   BasicPersistent& operator=(
135       const BasicPersistent<U, OtherWeaknessPolicy, OtherLocationPolicy,
136                             OtherCheckingPolicy>& other) {
137     return operator=(other.Get());
138   }
139 
140   // Move assignment.
141   BasicPersistent& operator=(BasicPersistent&& other) {
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>>
158   BasicPersistent& operator=(
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 
175   BasicPersistent& operator=(SentinelPointer s) {
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.
Get()188   V8_CLANG_NO_SANITIZE("cfi-unrelated-cast") T* Get() const {
189     return static_cast<T*>(GetValue());
190   }
191 
Clear()192   void Clear() { Assign(nullptr); }
193 
Release()194   T* Release() {
195     T* result = Get();
196     Clear();
197     return result;
198   }
199 
200  private:
Trace(Visitor * v,const void * ptr)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 
IsValid()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 
Assign(T * ptr)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 
ClearFromGC()231   void ClearFromGC() const {
232     if (IsValid()) {
233       WeaknessPolicy::GetPersistentRegion(GetValue()).FreeNode(GetNode());
234       PersistentBase::ClearFromGC();
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>
314 struct IsWeak<BasicPersistent<T, internal::WeakPersistentPolicy, LocationPolicy,
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 =
327     internal::BasicPersistent<T, internal::StrongPersistentPolicy>;
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 =
337     internal::BasicPersistent<T, internal::WeakPersistentPolicy>;
338 
339 }  // namespace cppgc
340 
341 #endif  // INCLUDE_CPPGC_PERSISTENT_H_
342