Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-08-30 08:57:00

0001 // Copyright 2020 the V8 project authors. All rights reserved.
0002 // Use of this source code is governed by a BSD-style license that can be
0003 // found in the LICENSE file.
0004 
0005 #ifndef INCLUDE_CPPGC_PERSISTENT_H_
0006 #define INCLUDE_CPPGC_PERSISTENT_H_
0007 
0008 #include <type_traits>
0009 
0010 #include "cppgc/internal/persistent-node.h"
0011 #include "cppgc/internal/pointer-policies.h"
0012 #include "cppgc/sentinel-pointer.h"
0013 #include "cppgc/source-location.h"
0014 #include "cppgc/type-traits.h"
0015 #include "cppgc/visitor.h"
0016 #include "v8config.h"  // NOLINT(build/include_directory)
0017 
0018 namespace cppgc {
0019 namespace internal {
0020 
0021 // PersistentBase always refers to the object as const object and defers to
0022 // BasicPersistent on casting to the right type as needed.
0023 class PersistentBase {
0024  protected:
0025   PersistentBase() = default;
0026   explicit PersistentBase(const void* raw) : raw_(raw) {}
0027 
0028   const void* GetValue() const { return raw_; }
0029   void SetValue(const void* value) { raw_ = value; }
0030 
0031   PersistentNode* GetNode() const { return node_; }
0032   void SetNode(PersistentNode* node) { node_ = node; }
0033 
0034   // Performs a shallow clear which assumes that internal persistent nodes are
0035   // destroyed elsewhere.
0036   void ClearFromGC() const {
0037     raw_ = nullptr;
0038     node_ = nullptr;
0039   }
0040 
0041  protected:
0042   mutable const void* raw_ = nullptr;
0043   mutable PersistentNode* node_ = nullptr;
0044 
0045   friend class PersistentRegionBase;
0046 };
0047 
0048 // The basic class from which all Persistent classes are generated.
0049 template <typename T, typename WeaknessPolicy, typename LocationPolicy,
0050           typename CheckingPolicy>
0051 class BasicPersistent final : public PersistentBase,
0052                               public LocationPolicy,
0053                               private WeaknessPolicy,
0054                               private CheckingPolicy {
0055  public:
0056   using typename WeaknessPolicy::IsStrongPersistent;
0057   using PointeeType = T;
0058 
0059   // Null-state/sentinel constructors.
0060   BasicPersistent(  // NOLINT
0061       SourceLocation loc = SourceLocation::Current())
0062       : LocationPolicy(loc) {}
0063 
0064   BasicPersistent(std::nullptr_t,  // NOLINT
0065                   SourceLocation loc = SourceLocation::Current())
0066       : LocationPolicy(loc) {}
0067 
0068   BasicPersistent(  // NOLINT
0069       SentinelPointer s, SourceLocation loc = SourceLocation::Current())
0070       : PersistentBase(s), LocationPolicy(loc) {}
0071 
0072   // Raw value constructors.
0073   BasicPersistent(T* raw,  // NOLINT
0074                   SourceLocation loc = SourceLocation::Current())
0075       : PersistentBase(raw), LocationPolicy(loc) {
0076     if (!IsValid()) return;
0077     SetNode(WeaknessPolicy::GetPersistentRegion(GetValue())
0078                 .AllocateNode(this, &TraceAsRoot));
0079     this->CheckPointer(Get());
0080   }
0081 
0082   BasicPersistent(T& raw,  // NOLINT
0083                   SourceLocation loc = SourceLocation::Current())
0084       : BasicPersistent(&raw, loc) {}
0085 
0086   // Copy ctor.
0087   BasicPersistent(const BasicPersistent& other,
0088                   SourceLocation loc = SourceLocation::Current())
0089       : BasicPersistent(other.Get(), loc) {}
0090 
0091   // Heterogeneous ctor.
0092   template <typename U, typename OtherWeaknessPolicy,
0093             typename OtherLocationPolicy, typename OtherCheckingPolicy,
0094             typename = std::enable_if_t<std::is_base_of_v<T, U>>>
0095   // NOLINTNEXTLINE
0096   BasicPersistent(
0097       const BasicPersistent<U, OtherWeaknessPolicy, OtherLocationPolicy,
0098                             OtherCheckingPolicy>& other,
0099       SourceLocation loc = SourceLocation::Current())
0100       : BasicPersistent(other.Get(), loc) {}
0101 
0102   // Move ctor. The heterogeneous move ctor is not supported since e.g.
0103   // persistent can't reuse persistent node from weak persistent.
0104   BasicPersistent(BasicPersistent&& other,
0105                   SourceLocation loc = SourceLocation::Current()) noexcept
0106       : PersistentBase(std::move(other)), LocationPolicy(std::move(other)) {
0107     if (!IsValid()) return;
0108     GetNode()->UpdateOwner(this);
0109     other.SetValue(nullptr);
0110     other.SetNode(nullptr);
0111     this->CheckPointer(Get());
0112   }
0113 
0114   // Constructor from member.
0115   template <typename U, typename MemberBarrierPolicy,
0116             typename MemberWeaknessTag, typename MemberCheckingPolicy,
0117             typename MemberStorageType,
0118             typename = std::enable_if_t<std::is_base_of_v<T, U>>>
0119   // NOLINTNEXTLINE
0120   BasicPersistent(const internal::BasicMember<
0121                       U, MemberBarrierPolicy, MemberWeaknessTag,
0122                       MemberCheckingPolicy, MemberStorageType>& member,
0123                   SourceLocation loc = SourceLocation::Current())
0124       : BasicPersistent(member.Get(), loc) {}
0125 
0126   ~BasicPersistent() { Clear(); }
0127 
0128   // Copy assignment.
0129   BasicPersistent& operator=(const BasicPersistent& other) {
0130     return operator=(other.Get());
0131   }
0132 
0133   template <typename U, typename OtherWeaknessPolicy,
0134             typename OtherLocationPolicy, typename OtherCheckingPolicy,
0135             typename = std::enable_if_t<std::is_base_of_v<T, U>>>
0136   BasicPersistent& operator=(
0137       const BasicPersistent<U, OtherWeaknessPolicy, OtherLocationPolicy,
0138                             OtherCheckingPolicy>& other) {
0139     return operator=(other.Get());
0140   }
0141 
0142   // Move assignment.
0143   BasicPersistent& operator=(BasicPersistent&& other) noexcept {
0144     if (this == &other) return *this;
0145     Clear();
0146     PersistentBase::operator=(std::move(other));
0147     LocationPolicy::operator=(std::move(other));
0148     if (!IsValid()) return *this;
0149     GetNode()->UpdateOwner(this);
0150     other.SetValue(nullptr);
0151     other.SetNode(nullptr);
0152     this->CheckPointer(Get());
0153     return *this;
0154   }
0155 
0156   // Assignment from member.
0157   template <typename U, typename MemberBarrierPolicy,
0158             typename MemberWeaknessTag, typename MemberCheckingPolicy,
0159             typename MemberStorageType,
0160             typename = std::enable_if_t<std::is_base_of_v<T, U>>>
0161   BasicPersistent& operator=(
0162       const internal::BasicMember<U, MemberBarrierPolicy, MemberWeaknessTag,
0163                                   MemberCheckingPolicy, MemberStorageType>&
0164           member) {
0165     return operator=(member.Get());
0166   }
0167 
0168   BasicPersistent& operator=(T* other) {
0169     Assign(other);
0170     return *this;
0171   }
0172 
0173   BasicPersistent& operator=(std::nullptr_t) {
0174     Clear();
0175     return *this;
0176   }
0177 
0178   BasicPersistent& operator=(SentinelPointer s) {
0179     Assign(s);
0180     return *this;
0181   }
0182 
0183   explicit operator bool() const { return Get(); }
0184   // Historically we allow implicit conversions to T*.
0185   // NOLINTNEXTLINE
0186   operator T*() const { return Get(); }
0187   T* operator->() const { return Get(); }
0188   T& operator*() const { return *Get(); }
0189 
0190   // CFI cast exemption to allow passing SentinelPointer through T* and support
0191   // heterogeneous assignments between different Member and Persistent handles
0192   // based on their actual types.
0193   V8_CLANG_NO_SANITIZE("cfi-unrelated-cast") T* Get() const {
0194     // The const_cast below removes the constness from PersistentBase storage.
0195     // The following static_cast re-adds any constness if specified through the
0196     // user-visible template parameter T.
0197     return static_cast<T*>(const_cast<void*>(GetValue()));
0198   }
0199 
0200   void Clear() {
0201     // Simplified version of `Assign()` to allow calling without a complete type
0202     // `T`.
0203     if (IsValid()) {
0204       WeaknessPolicy::GetPersistentRegion(GetValue()).FreeNode(GetNode());
0205       SetNode(nullptr);
0206     }
0207     SetValue(nullptr);
0208   }
0209 
0210   T* Release() {
0211     T* result = Get();
0212     Clear();
0213     return result;
0214   }
0215 
0216   template <typename U, typename OtherWeaknessPolicy = WeaknessPolicy,
0217             typename OtherLocationPolicy = LocationPolicy,
0218             typename OtherCheckingPolicy = CheckingPolicy>
0219   BasicPersistent<U, OtherWeaknessPolicy, OtherLocationPolicy,
0220                   OtherCheckingPolicy>
0221   To() const {
0222     return BasicPersistent<U, OtherWeaknessPolicy, OtherLocationPolicy,
0223                            OtherCheckingPolicy>(static_cast<U*>(Get()));
0224   }
0225 
0226  private:
0227   static void TraceAsRoot(RootVisitor& root_visitor, const void* ptr) {
0228     root_visitor.Trace(*static_cast<const BasicPersistent*>(ptr));
0229   }
0230 
0231   bool IsValid() const {
0232     // Ideally, handling kSentinelPointer would be done by the embedder. On the
0233     // other hand, having Persistent aware of it is beneficial since no node
0234     // gets wasted.
0235     return GetValue() != nullptr && GetValue() != kSentinelPointer;
0236   }
0237 
0238   void Assign(T* ptr) {
0239     if (IsValid()) {
0240       if (ptr && ptr != kSentinelPointer) {
0241         // Simply assign the pointer reusing the existing node.
0242         SetValue(ptr);
0243         this->CheckPointer(ptr);
0244         return;
0245       }
0246       WeaknessPolicy::GetPersistentRegion(GetValue()).FreeNode(GetNode());
0247       SetNode(nullptr);
0248     }
0249     SetValue(ptr);
0250     if (!IsValid()) return;
0251     SetNode(WeaknessPolicy::GetPersistentRegion(GetValue())
0252                 .AllocateNode(this, &TraceAsRoot));
0253     this->CheckPointer(Get());
0254   }
0255 
0256   void ClearFromGC() const {
0257     if (IsValid()) {
0258       WeaknessPolicy::GetPersistentRegion(GetValue()).FreeNode(GetNode());
0259       PersistentBase::ClearFromGC();
0260     }
0261   }
0262 
0263   // Set Get() for details.
0264   V8_CLANG_NO_SANITIZE("cfi-unrelated-cast")
0265   T* GetFromGC() const {
0266     return static_cast<T*>(const_cast<void*>(GetValue()));
0267   }
0268 
0269   friend class internal::RootVisitor;
0270 };
0271 
0272 template <typename T1, typename WeaknessPolicy1, typename LocationPolicy1,
0273           typename CheckingPolicy1, typename T2, typename WeaknessPolicy2,
0274           typename LocationPolicy2, typename CheckingPolicy2>
0275 bool operator==(const BasicPersistent<T1, WeaknessPolicy1, LocationPolicy1,
0276                                       CheckingPolicy1>& p1,
0277                 const BasicPersistent<T2, WeaknessPolicy2, LocationPolicy2,
0278                                       CheckingPolicy2>& p2) {
0279   return p1.Get() == p2.Get();
0280 }
0281 
0282 template <typename T1, typename WeaknessPolicy1, typename LocationPolicy1,
0283           typename CheckingPolicy1, typename T2, typename WeaknessPolicy2,
0284           typename LocationPolicy2, typename CheckingPolicy2>
0285 bool operator!=(const BasicPersistent<T1, WeaknessPolicy1, LocationPolicy1,
0286                                       CheckingPolicy1>& p1,
0287                 const BasicPersistent<T2, WeaknessPolicy2, LocationPolicy2,
0288                                       CheckingPolicy2>& p2) {
0289   return !(p1 == p2);
0290 }
0291 
0292 template <typename T1, typename PersistentWeaknessPolicy,
0293           typename PersistentLocationPolicy, typename PersistentCheckingPolicy,
0294           typename T2, typename MemberWriteBarrierPolicy,
0295           typename MemberWeaknessTag, typename MemberCheckingPolicy,
0296           typename MemberStorageType>
0297 bool operator==(
0298     const BasicPersistent<T1, PersistentWeaknessPolicy,
0299                           PersistentLocationPolicy, PersistentCheckingPolicy>&
0300         p,
0301     const BasicMember<T2, MemberWeaknessTag, MemberWriteBarrierPolicy,
0302                       MemberCheckingPolicy, MemberStorageType>& m) {
0303   return p.Get() == m.Get();
0304 }
0305 
0306 template <typename T1, typename PersistentWeaknessPolicy,
0307           typename PersistentLocationPolicy, typename PersistentCheckingPolicy,
0308           typename T2, typename MemberWriteBarrierPolicy,
0309           typename MemberWeaknessTag, typename MemberCheckingPolicy,
0310           typename MemberStorageType>
0311 bool operator!=(
0312     const BasicPersistent<T1, PersistentWeaknessPolicy,
0313                           PersistentLocationPolicy, PersistentCheckingPolicy>&
0314         p,
0315     const BasicMember<T2, MemberWeaknessTag, MemberWriteBarrierPolicy,
0316                       MemberCheckingPolicy, MemberStorageType>& m) {
0317   return !(p == m);
0318 }
0319 
0320 template <typename T1, typename MemberWriteBarrierPolicy,
0321           typename MemberWeaknessTag, typename MemberCheckingPolicy,
0322           typename MemberStorageType, typename T2,
0323           typename PersistentWeaknessPolicy, typename PersistentLocationPolicy,
0324           typename PersistentCheckingPolicy>
0325 bool operator==(
0326     const BasicMember<T2, MemberWeaknessTag, MemberWriteBarrierPolicy,
0327                       MemberCheckingPolicy, MemberStorageType>& m,
0328     const BasicPersistent<T1, PersistentWeaknessPolicy,
0329                           PersistentLocationPolicy, PersistentCheckingPolicy>&
0330         p) {
0331   return m.Get() == p.Get();
0332 }
0333 
0334 template <typename T1, typename MemberWriteBarrierPolicy,
0335           typename MemberWeaknessTag, typename MemberCheckingPolicy,
0336           typename MemberStorageType, typename T2,
0337           typename PersistentWeaknessPolicy, typename PersistentLocationPolicy,
0338           typename PersistentCheckingPolicy>
0339 bool operator!=(
0340     const BasicMember<T2, MemberWeaknessTag, MemberWriteBarrierPolicy,
0341                       MemberCheckingPolicy, MemberStorageType>& m,
0342     const BasicPersistent<T1, PersistentWeaknessPolicy,
0343                           PersistentLocationPolicy, PersistentCheckingPolicy>&
0344         p) {
0345   return !(m == p);
0346 }
0347 
0348 template <typename T, typename LocationPolicy, typename CheckingPolicy>
0349 struct IsWeak<BasicPersistent<T, internal::WeakPersistentPolicy, LocationPolicy,
0350                               CheckingPolicy>> : std::true_type {};
0351 }  // namespace internal
0352 
0353 /**
0354  * Persistent is a way to create a strong pointer from an off-heap object to
0355  * another on-heap object. As long as the Persistent handle is alive the GC will
0356  * keep the object pointed to alive. The Persistent handle is always a GC root
0357  * from the point of view of the GC. Persistent must be constructed and
0358  * destructed in the same thread.
0359  */
0360 template <typename T>
0361 using Persistent =
0362     internal::BasicPersistent<T, internal::StrongPersistentPolicy>;
0363 
0364 /**
0365  * WeakPersistent is a way to create a weak pointer from an off-heap object to
0366  * an on-heap object. The pointer is automatically cleared when the pointee gets
0367  * collected. WeakPersistent must be constructed and destructed in the same
0368  * thread.
0369  */
0370 template <typename T>
0371 using WeakPersistent =
0372     internal::BasicPersistent<T, internal::WeakPersistentPolicy>;
0373 
0374 }  // namespace cppgc
0375 
0376 #endif  // INCLUDE_CPPGC_PERSISTENT_H_