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