/src/node/deps/v8/include/cppgc/persistent.h
Line | Count | Source |
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/sentinel-pointer.h" |
13 | | #include "cppgc/source-location.h" |
14 | | #include "cppgc/type-traits.h" |
15 | | #include "cppgc/visitor.h" |
16 | | #include "v8config.h" // NOLINT(build/include_directory) |
17 | | |
18 | | namespace cppgc { |
19 | | namespace internal { |
20 | | |
21 | | // PersistentBase always refers to the object as const object and defers to |
22 | | // BasicPersistent on casting to the right type as needed. |
23 | | class PersistentBase { |
24 | | protected: |
25 | | PersistentBase() = default; |
26 | 0 | explicit PersistentBase(const void* raw) : raw_(raw) {} |
27 | | |
28 | 0 | const void* GetValue() const { return raw_; } |
29 | 0 | void SetValue(const void* value) { raw_ = value; } |
30 | | |
31 | 0 | PersistentNode* GetNode() const { return node_; } |
32 | 0 | void SetNode(PersistentNode* node) { node_ = node; } |
33 | | |
34 | | // Performs a shallow clear which assumes that internal persistent nodes are |
35 | | // destroyed elsewhere. |
36 | 0 | void ClearFromGC() const { |
37 | 0 | raw_ = nullptr; |
38 | 0 | node_ = nullptr; |
39 | 0 | } |
40 | | |
41 | | protected: |
42 | | mutable const void* raw_ = nullptr; |
43 | | mutable PersistentNode* node_ = nullptr; |
44 | | |
45 | | friend class PersistentRegionBase; |
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 | | SourceLocation loc = SourceLocation::Current()) |
62 | | : LocationPolicy(loc) {} |
63 | | |
64 | | BasicPersistent(std::nullptr_t, // NOLINT |
65 | | SourceLocation loc = SourceLocation::Current()) |
66 | | : LocationPolicy(loc) {} |
67 | | |
68 | | BasicPersistent( // NOLINT |
69 | | SentinelPointer s, SourceLocation loc = SourceLocation::Current()) |
70 | | : PersistentBase(s), LocationPolicy(loc) {} |
71 | | |
72 | | // Raw value constructors. |
73 | | BasicPersistent(T* raw, // NOLINT |
74 | | SourceLocation loc = SourceLocation::Current()) |
75 | 0 | : PersistentBase(raw), LocationPolicy(loc) { |
76 | 0 | if (!IsValid()) return; |
77 | 0 | SetNode(WeaknessPolicy::GetPersistentRegion(GetValue()) |
78 | 0 | .AllocateNode(this, &TraceAsRoot)); |
79 | 0 | this->CheckPointer(Get()); |
80 | 0 | } |
81 | | |
82 | | BasicPersistent(T& raw, // NOLINT |
83 | | SourceLocation loc = SourceLocation::Current()) |
84 | | : BasicPersistent(&raw, loc) {} |
85 | | |
86 | | // Copy ctor. |
87 | | BasicPersistent(const BasicPersistent& other, |
88 | | 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_v<T, U>>> |
95 | | // NOLINTNEXTLINE |
96 | | BasicPersistent( |
97 | | const BasicPersistent<U, OtherWeaknessPolicy, OtherLocationPolicy, |
98 | | OtherCheckingPolicy>& other, |
99 | | SourceLocation loc = SourceLocation::Current()) |
100 | | : BasicPersistent(other.Get(), loc) {} |
101 | | |
102 | | // Move ctor. The heterogeneous move ctor is not supported since e.g. |
103 | | // persistent can't reuse persistent node from weak persistent. |
104 | | BasicPersistent(BasicPersistent&& other, |
105 | | 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 MemberStorageType, |
118 | | typename = std::enable_if_t<std::is_base_of_v<T, U>>> |
119 | | // NOLINTNEXTLINE |
120 | | BasicPersistent(const internal::BasicMember< |
121 | | U, MemberBarrierPolicy, MemberWeaknessTag, |
122 | | MemberCheckingPolicy, MemberStorageType>& member, |
123 | | SourceLocation loc = SourceLocation::Current()) |
124 | | : BasicPersistent(member.Get(), loc) {} |
125 | | |
126 | 0 | ~BasicPersistent() { Clear(); } |
127 | | |
128 | | // Copy assignment. |
129 | | BasicPersistent& operator=(const BasicPersistent& other) { |
130 | | return operator=(other.Get()); |
131 | | } |
132 | | |
133 | | template <typename U, typename OtherWeaknessPolicy, |
134 | | typename OtherLocationPolicy, typename OtherCheckingPolicy, |
135 | | typename = std::enable_if_t<std::is_base_of_v<T, U>>> |
136 | | BasicPersistent& operator=( |
137 | | const BasicPersistent<U, OtherWeaknessPolicy, OtherLocationPolicy, |
138 | | OtherCheckingPolicy>& other) { |
139 | | return operator=(other.Get()); |
140 | | } |
141 | | |
142 | | // Move assignment. |
143 | | BasicPersistent& operator=(BasicPersistent&& other) noexcept { |
144 | | if (this == &other) return *this; |
145 | | Clear(); |
146 | | PersistentBase::operator=(std::move(other)); |
147 | | LocationPolicy::operator=(std::move(other)); |
148 | | if (!IsValid()) return *this; |
149 | | GetNode()->UpdateOwner(this); |
150 | | other.SetValue(nullptr); |
151 | | other.SetNode(nullptr); |
152 | | this->CheckPointer(Get()); |
153 | | return *this; |
154 | | } |
155 | | |
156 | | // Assignment from member. |
157 | | template <typename U, typename MemberBarrierPolicy, |
158 | | typename MemberWeaknessTag, typename MemberCheckingPolicy, |
159 | | typename MemberStorageType, |
160 | | typename = std::enable_if_t<std::is_base_of_v<T, U>>> |
161 | | BasicPersistent& operator=( |
162 | | const internal::BasicMember<U, MemberBarrierPolicy, MemberWeaknessTag, |
163 | | MemberCheckingPolicy, MemberStorageType>& |
164 | | member) { |
165 | | return operator=(member.Get()); |
166 | | } |
167 | | |
168 | | BasicPersistent& operator=(T* other) { |
169 | | Assign(other); |
170 | | return *this; |
171 | | } |
172 | | |
173 | | BasicPersistent& operator=(std::nullptr_t) { |
174 | | Clear(); |
175 | | return *this; |
176 | | } |
177 | | |
178 | | BasicPersistent& operator=(SentinelPointer s) { |
179 | | Assign(s); |
180 | | return *this; |
181 | | } |
182 | | |
183 | 0 | explicit operator bool() const { return Get(); } |
184 | | // Historically we allow implicit conversions to T*. |
185 | | // NOLINTNEXTLINE |
186 | | operator T*() const { return Get(); } |
187 | | T* operator->() const { return Get(); } |
188 | | T& operator*() const { return *Get(); } |
189 | | |
190 | | // CFI cast exemption to allow passing SentinelPointer through T* and support |
191 | | // heterogeneous assignments between different Member and Persistent handles |
192 | | // based on their actual types. |
193 | 0 | V8_CLANG_NO_SANITIZE("cfi-unrelated-cast") T* Get() const { |
194 | | // The const_cast below removes the constness from PersistentBase storage. |
195 | | // The following static_cast re-adds any constness if specified through the |
196 | | // user-visible template parameter T. |
197 | 0 | return static_cast<T*>(const_cast<void*>(GetValue())); |
198 | 0 | } |
199 | | |
200 | 0 | void Clear() { |
201 | | // Simplified version of `Assign()` to allow calling without a complete type |
202 | | // `T`. |
203 | 0 | if (IsValid()) { |
204 | 0 | WeaknessPolicy::GetPersistentRegion(GetValue()).FreeNode(GetNode()); |
205 | 0 | SetNode(nullptr); |
206 | 0 | } |
207 | 0 | SetValue(nullptr); |
208 | 0 | } |
209 | | |
210 | | T* Release() { |
211 | | T* result = Get(); |
212 | | Clear(); |
213 | | return result; |
214 | | } |
215 | | |
216 | | template <typename U, typename OtherWeaknessPolicy = WeaknessPolicy, |
217 | | typename OtherLocationPolicy = LocationPolicy, |
218 | | typename OtherCheckingPolicy = CheckingPolicy> |
219 | | BasicPersistent<U, OtherWeaknessPolicy, OtherLocationPolicy, |
220 | | OtherCheckingPolicy> |
221 | | To() const { |
222 | | return BasicPersistent<U, OtherWeaknessPolicy, OtherLocationPolicy, |
223 | | OtherCheckingPolicy>(static_cast<U*>(Get())); |
224 | | } |
225 | | |
226 | | private: |
227 | 0 | static void TraceAsRoot(RootVisitor& root_visitor, const void* ptr) { |
228 | 0 | root_visitor.Trace(*static_cast<const BasicPersistent*>(ptr)); |
229 | 0 | } |
230 | | |
231 | 0 | bool IsValid() const { |
232 | | // Ideally, handling kSentinelPointer would be done by the embedder. On the |
233 | | // other hand, having Persistent aware of it is beneficial since no node |
234 | | // gets wasted. |
235 | 0 | return GetValue() != nullptr && GetValue() != kSentinelPointer; |
236 | 0 | } |
237 | | |
238 | | void Assign(T* ptr) { |
239 | | if (IsValid()) { |
240 | | if (ptr && ptr != kSentinelPointer) { |
241 | | // Simply assign the pointer reusing the existing node. |
242 | | SetValue(ptr); |
243 | | this->CheckPointer(ptr); |
244 | | return; |
245 | | } |
246 | | WeaknessPolicy::GetPersistentRegion(GetValue()).FreeNode(GetNode()); |
247 | | SetNode(nullptr); |
248 | | } |
249 | | SetValue(ptr); |
250 | | if (!IsValid()) return; |
251 | | SetNode(WeaknessPolicy::GetPersistentRegion(GetValue()) |
252 | | .AllocateNode(this, &TraceAsRoot)); |
253 | | this->CheckPointer(Get()); |
254 | | } |
255 | | |
256 | 0 | void ClearFromGC() const { |
257 | 0 | if (IsValid()) { |
258 | 0 | WeaknessPolicy::GetPersistentRegion(GetValue()).FreeNode(GetNode()); |
259 | 0 | PersistentBase::ClearFromGC(); |
260 | 0 | } |
261 | 0 | } |
262 | | |
263 | | // Set Get() for details. |
264 | | V8_CLANG_NO_SANITIZE("cfi-unrelated-cast") |
265 | 0 | T* GetFromGC() const { |
266 | 0 | return static_cast<T*>(const_cast<void*>(GetValue())); |
267 | 0 | } |
268 | | |
269 | | friend class internal::RootVisitor; |
270 | | }; |
271 | | |
272 | | template <typename T1, typename WeaknessPolicy1, typename LocationPolicy1, |
273 | | typename CheckingPolicy1, typename T2, typename WeaknessPolicy2, |
274 | | typename LocationPolicy2, typename CheckingPolicy2> |
275 | | bool operator==(const BasicPersistent<T1, WeaknessPolicy1, LocationPolicy1, |
276 | | CheckingPolicy1>& p1, |
277 | | const BasicPersistent<T2, WeaknessPolicy2, LocationPolicy2, |
278 | | CheckingPolicy2>& p2) { |
279 | | return p1.Get() == p2.Get(); |
280 | | } |
281 | | |
282 | | template <typename T1, typename WeaknessPolicy1, typename LocationPolicy1, |
283 | | typename CheckingPolicy1, typename T2, typename WeaknessPolicy2, |
284 | | typename LocationPolicy2, typename CheckingPolicy2> |
285 | | bool operator!=(const BasicPersistent<T1, WeaknessPolicy1, LocationPolicy1, |
286 | | CheckingPolicy1>& p1, |
287 | | const BasicPersistent<T2, WeaknessPolicy2, LocationPolicy2, |
288 | | CheckingPolicy2>& p2) { |
289 | | return !(p1 == p2); |
290 | | } |
291 | | |
292 | | template <typename T1, typename PersistentWeaknessPolicy, |
293 | | typename PersistentLocationPolicy, typename PersistentCheckingPolicy, |
294 | | typename T2, typename MemberWriteBarrierPolicy, |
295 | | typename MemberWeaknessTag, typename MemberCheckingPolicy, |
296 | | typename MemberStorageType> |
297 | | bool operator==( |
298 | | const BasicPersistent<T1, PersistentWeaknessPolicy, |
299 | | PersistentLocationPolicy, PersistentCheckingPolicy>& |
300 | | p, |
301 | | const BasicMember<T2, MemberWeaknessTag, MemberWriteBarrierPolicy, |
302 | | MemberCheckingPolicy, MemberStorageType>& m) { |
303 | | return p.Get() == m.Get(); |
304 | | } |
305 | | |
306 | | template <typename T1, typename PersistentWeaknessPolicy, |
307 | | typename PersistentLocationPolicy, typename PersistentCheckingPolicy, |
308 | | typename T2, typename MemberWriteBarrierPolicy, |
309 | | typename MemberWeaknessTag, typename MemberCheckingPolicy, |
310 | | typename MemberStorageType> |
311 | | bool operator!=( |
312 | | const BasicPersistent<T1, PersistentWeaknessPolicy, |
313 | | PersistentLocationPolicy, PersistentCheckingPolicy>& |
314 | | p, |
315 | | const BasicMember<T2, MemberWeaknessTag, MemberWriteBarrierPolicy, |
316 | | MemberCheckingPolicy, MemberStorageType>& m) { |
317 | | return !(p == m); |
318 | | } |
319 | | |
320 | | template <typename T1, typename MemberWriteBarrierPolicy, |
321 | | typename MemberWeaknessTag, typename MemberCheckingPolicy, |
322 | | typename MemberStorageType, typename T2, |
323 | | typename PersistentWeaknessPolicy, typename PersistentLocationPolicy, |
324 | | typename PersistentCheckingPolicy> |
325 | | bool operator==( |
326 | | const BasicMember<T2, MemberWeaknessTag, MemberWriteBarrierPolicy, |
327 | | MemberCheckingPolicy, MemberStorageType>& m, |
328 | | const BasicPersistent<T1, PersistentWeaknessPolicy, |
329 | | PersistentLocationPolicy, PersistentCheckingPolicy>& |
330 | | p) { |
331 | | return m.Get() == p.Get(); |
332 | | } |
333 | | |
334 | | template <typename T1, typename MemberWriteBarrierPolicy, |
335 | | typename MemberWeaknessTag, typename MemberCheckingPolicy, |
336 | | typename MemberStorageType, typename T2, |
337 | | typename PersistentWeaknessPolicy, typename PersistentLocationPolicy, |
338 | | typename PersistentCheckingPolicy> |
339 | | bool operator!=( |
340 | | const BasicMember<T2, MemberWeaknessTag, MemberWriteBarrierPolicy, |
341 | | MemberCheckingPolicy, MemberStorageType>& m, |
342 | | const BasicPersistent<T1, PersistentWeaknessPolicy, |
343 | | PersistentLocationPolicy, PersistentCheckingPolicy>& |
344 | | p) { |
345 | | return !(m == p); |
346 | | } |
347 | | |
348 | | template <typename T, typename LocationPolicy, typename CheckingPolicy> |
349 | | struct IsWeak<BasicPersistent<T, internal::WeakPersistentPolicy, LocationPolicy, |
350 | | CheckingPolicy>> : std::true_type {}; |
351 | | } // namespace internal |
352 | | |
353 | | /** |
354 | | * Persistent is a way to create a strong pointer from an off-heap object to |
355 | | * another on-heap object. As long as the Persistent handle is alive the GC will |
356 | | * keep the object pointed to alive. The Persistent handle is always a GC root |
357 | | * from the point of view of the GC. Persistent must be constructed and |
358 | | * destructed in the same thread. |
359 | | */ |
360 | | template <typename T> |
361 | | using Persistent = |
362 | | internal::BasicPersistent<T, internal::StrongPersistentPolicy>; |
363 | | |
364 | | /** |
365 | | * WeakPersistent is a way to create a weak pointer from an off-heap object to |
366 | | * an on-heap object. The pointer is automatically cleared when the pointee gets |
367 | | * collected. WeakPersistent must be constructed and destructed in the same |
368 | | * thread. |
369 | | */ |
370 | | template <typename T> |
371 | | using WeakPersistent = |
372 | | internal::BasicPersistent<T, internal::WeakPersistentPolicy>; |
373 | | |
374 | | } // namespace cppgc |
375 | | |
376 | | #endif // INCLUDE_CPPGC_PERSISTENT_H_ |