Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-04-02 08:54:42

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       const SourceLocation& loc = SourceLocation::Current())
0062       : LocationPolicy(loc) {}
0063 
0064   BasicPersistent(std::nullptr_t,  // NOLINT
0065                   const SourceLocation& loc = SourceLocation::Current())
0066       : LocationPolicy(loc) {}
0067 
0068   BasicPersistent(  // NOLINT
0069       SentinelPointer s, const SourceLocation& loc = SourceLocation::Current())
0070       : PersistentBase(s), LocationPolicy(loc) {}
0071 
0072   // Raw value constructors.
0073   BasicPersistent(T* raw,  // NOLINT
0074                   const 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                   const SourceLocation& loc = SourceLocation::Current())
0084       : BasicPersistent(&raw, loc) {}
0085 
0086   // Copy ctor.
0087   BasicPersistent(const BasicPersistent& other,
0088                   const 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<T, U>::value>>
0095   // NOLINTNEXTLINE
0096   BasicPersistent(
0097       const BasicPersistent<U, OtherWeaknessPolicy, OtherLocationPolicy,
0098                             OtherCheckingPolicy>& other,
0099       const 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(
0105       BasicPersistent&& other,
0106       const SourceLocation& loc = SourceLocation::Current()) noexcept
0107       : PersistentBase(std::move(other)), LocationPolicy(std::move(other)) {
0108     if (!IsValid()) return;
0109     GetNode()->UpdateOwner(this);
0110     other.SetValue(nullptr);
0111     other.SetNode(nullptr);
0112     this->CheckPointer(Get());
0113   }
0114 
0115   // Constructor from member.
0116   template <typename U, typename MemberBarrierPolicy,
0117             typename MemberWeaknessTag, typename MemberCheckingPolicy,
0118             typename MemberStorageType,
0119             typename = std::enable_if_t<std::is_base_of<T, U>::value>>
0120   // NOLINTNEXTLINE
0121   BasicPersistent(const internal::BasicMember<
0122                       U, MemberBarrierPolicy, MemberWeaknessTag,
0123                       MemberCheckingPolicy, MemberStorageType>& member,
0124                   const SourceLocation& loc = SourceLocation::Current())
0125       : BasicPersistent(member.Get(), loc) {}
0126 
0127   ~BasicPersistent() { Clear(); }
0128 
0129   // Copy assignment.
0130   BasicPersistent& operator=(const BasicPersistent& other) {
0131     return operator=(other.Get());
0132   }
0133 
0134   template <typename U, typename OtherWeaknessPolicy,
0135             typename OtherLocationPolicy, typename OtherCheckingPolicy,
0136             typename = std::enable_if_t<std::is_base_of<T, U>::value>>
0137   BasicPersistent& operator=(
0138       const BasicPersistent<U, OtherWeaknessPolicy, OtherLocationPolicy,
0139                             OtherCheckingPolicy>& other) {
0140     return operator=(other.Get());
0141   }
0142 
0143   // Move assignment.
0144   BasicPersistent& operator=(BasicPersistent&& other) noexcept {
0145     if (this == &other) return *this;
0146     Clear();
0147     PersistentBase::operator=(std::move(other));
0148     LocationPolicy::operator=(std::move(other));
0149     if (!IsValid()) return *this;
0150     GetNode()->UpdateOwner(this);
0151     other.SetValue(nullptr);
0152     other.SetNode(nullptr);
0153     this->CheckPointer(Get());
0154     return *this;
0155   }
0156 
0157   // Assignment from member.
0158   template <typename U, typename MemberBarrierPolicy,
0159             typename MemberWeaknessTag, typename MemberCheckingPolicy,
0160             typename MemberStorageType,
0161             typename = std::enable_if_t<std::is_base_of<T, U>::value>>
0162   BasicPersistent& operator=(
0163       const internal::BasicMember<U, MemberBarrierPolicy, MemberWeaknessTag,
0164                                   MemberCheckingPolicy, MemberStorageType>&
0165           member) {
0166     return operator=(member.Get());
0167   }
0168 
0169   BasicPersistent& operator=(T* other) {
0170     Assign(other);
0171     return *this;
0172   }
0173 
0174   BasicPersistent& operator=(std::nullptr_t) {
0175     Clear();
0176     return *this;
0177   }
0178 
0179   BasicPersistent& operator=(SentinelPointer s) {
0180     Assign(s);
0181     return *this;
0182   }
0183 
0184   explicit operator bool() const { return Get(); }
0185   // Historically we allow implicit conversions to T*.
0186   // NOLINTNEXTLINE
0187   operator T*() const { return Get(); }
0188   T* operator->() const { return Get(); }
0189   T& operator*() const { return *Get(); }
0190 
0191   // CFI cast exemption to allow passing SentinelPointer through T* and support
0192   // heterogeneous assignments between different Member and Persistent handles
0193   // based on their actual types.
0194   V8_CLANG_NO_SANITIZE("cfi-unrelated-cast") T* Get() const {
0195     // The const_cast below removes the constness from PersistentBase storage.
0196     // The following static_cast re-adds any constness if specified through the
0197     // user-visible template parameter T.
0198     return static_cast<T*>(const_cast<void*>(GetValue()));
0199   }
0200 
0201   void Clear() {
0202     // Simplified version of `Assign()` to allow calling without a complete type
0203     // `T`.
0204     if (IsValid()) {
0205       WeaknessPolicy::GetPersistentRegion(GetValue()).FreeNode(GetNode());
0206       SetNode(nullptr);
0207     }
0208     SetValue(nullptr);
0209   }
0210 
0211   T* Release() {
0212     T* result = Get();
0213     Clear();
0214     return result;
0215   }
0216 
0217   template <typename U, typename OtherWeaknessPolicy = WeaknessPolicy,
0218             typename OtherLocationPolicy = LocationPolicy,
0219             typename OtherCheckingPolicy = CheckingPolicy>
0220   BasicPersistent<U, OtherWeaknessPolicy, OtherLocationPolicy,
0221                   OtherCheckingPolicy>
0222   To() const {
0223     return BasicPersistent<U, OtherWeaknessPolicy, OtherLocationPolicy,
0224                            OtherCheckingPolicy>(static_cast<U*>(Get()));
0225   }
0226 
0227  private:
0228   static void TraceAsRoot(RootVisitor& root_visitor, const void* ptr) {
0229     root_visitor.Trace(*static_cast<const BasicPersistent*>(ptr));
0230   }
0231 
0232   bool IsValid() const {
0233     // Ideally, handling kSentinelPointer would be done by the embedder. On the
0234     // other hand, having Persistent aware of it is beneficial since no node
0235     // gets wasted.
0236     return GetValue() != nullptr && GetValue() != kSentinelPointer;
0237   }
0238 
0239   void Assign(T* ptr) {
0240     if (IsValid()) {
0241       if (ptr && ptr != kSentinelPointer) {
0242         // Simply assign the pointer reusing the existing node.
0243         SetValue(ptr);
0244         this->CheckPointer(ptr);
0245         return;
0246       }
0247       WeaknessPolicy::GetPersistentRegion(GetValue()).FreeNode(GetNode());
0248       SetNode(nullptr);
0249     }
0250     SetValue(ptr);
0251     if (!IsValid()) return;
0252     SetNode(WeaknessPolicy::GetPersistentRegion(GetValue())
0253                 .AllocateNode(this, &TraceAsRoot));
0254     this->CheckPointer(Get());
0255   }
0256 
0257   void ClearFromGC() const {
0258     if (IsValid()) {
0259       WeaknessPolicy::GetPersistentRegion(GetValue()).FreeNode(GetNode());
0260       PersistentBase::ClearFromGC();
0261     }
0262   }
0263 
0264   // Set Get() for details.
0265   V8_CLANG_NO_SANITIZE("cfi-unrelated-cast")
0266   T* GetFromGC() const {
0267     return static_cast<T*>(const_cast<void*>(GetValue()));
0268   }
0269 
0270   friend class internal::RootVisitor;
0271 };
0272 
0273 template <typename T1, typename WeaknessPolicy1, typename LocationPolicy1,
0274           typename CheckingPolicy1, typename T2, typename WeaknessPolicy2,
0275           typename LocationPolicy2, typename CheckingPolicy2>
0276 bool operator==(const BasicPersistent<T1, WeaknessPolicy1, LocationPolicy1,
0277                                       CheckingPolicy1>& p1,
0278                 const BasicPersistent<T2, WeaknessPolicy2, LocationPolicy2,
0279                                       CheckingPolicy2>& p2) {
0280   return p1.Get() == p2.Get();
0281 }
0282 
0283 template <typename T1, typename WeaknessPolicy1, typename LocationPolicy1,
0284           typename CheckingPolicy1, typename T2, typename WeaknessPolicy2,
0285           typename LocationPolicy2, typename CheckingPolicy2>
0286 bool operator!=(const BasicPersistent<T1, WeaknessPolicy1, LocationPolicy1,
0287                                       CheckingPolicy1>& p1,
0288                 const BasicPersistent<T2, WeaknessPolicy2, LocationPolicy2,
0289                                       CheckingPolicy2>& p2) {
0290   return !(p1 == p2);
0291 }
0292 
0293 template <typename T1, typename PersistentWeaknessPolicy,
0294           typename PersistentLocationPolicy, typename PersistentCheckingPolicy,
0295           typename T2, typename MemberWriteBarrierPolicy,
0296           typename MemberWeaknessTag, typename MemberCheckingPolicy,
0297           typename MemberStorageType>
0298 bool operator==(
0299     const BasicPersistent<T1, PersistentWeaknessPolicy,
0300                           PersistentLocationPolicy, PersistentCheckingPolicy>&
0301         p,
0302     const BasicMember<T2, MemberWeaknessTag, MemberWriteBarrierPolicy,
0303                       MemberCheckingPolicy, MemberStorageType>& m) {
0304   return p.Get() == m.Get();
0305 }
0306 
0307 template <typename T1, typename PersistentWeaknessPolicy,
0308           typename PersistentLocationPolicy, typename PersistentCheckingPolicy,
0309           typename T2, typename MemberWriteBarrierPolicy,
0310           typename MemberWeaknessTag, typename MemberCheckingPolicy,
0311           typename MemberStorageType>
0312 bool operator!=(
0313     const BasicPersistent<T1, PersistentWeaknessPolicy,
0314                           PersistentLocationPolicy, PersistentCheckingPolicy>&
0315         p,
0316     const BasicMember<T2, MemberWeaknessTag, MemberWriteBarrierPolicy,
0317                       MemberCheckingPolicy, MemberStorageType>& m) {
0318   return !(p == m);
0319 }
0320 
0321 template <typename T1, typename MemberWriteBarrierPolicy,
0322           typename MemberWeaknessTag, typename MemberCheckingPolicy,
0323           typename MemberStorageType, typename T2,
0324           typename PersistentWeaknessPolicy, typename PersistentLocationPolicy,
0325           typename PersistentCheckingPolicy>
0326 bool operator==(
0327     const BasicMember<T2, MemberWeaknessTag, MemberWriteBarrierPolicy,
0328                       MemberCheckingPolicy, MemberStorageType>& m,
0329     const BasicPersistent<T1, PersistentWeaknessPolicy,
0330                           PersistentLocationPolicy, PersistentCheckingPolicy>&
0331         p) {
0332   return m.Get() == p.Get();
0333 }
0334 
0335 template <typename T1, typename MemberWriteBarrierPolicy,
0336           typename MemberWeaknessTag, typename MemberCheckingPolicy,
0337           typename MemberStorageType, typename T2,
0338           typename PersistentWeaknessPolicy, typename PersistentLocationPolicy,
0339           typename PersistentCheckingPolicy>
0340 bool operator!=(
0341     const BasicMember<T2, MemberWeaknessTag, MemberWriteBarrierPolicy,
0342                       MemberCheckingPolicy, MemberStorageType>& m,
0343     const BasicPersistent<T1, PersistentWeaknessPolicy,
0344                           PersistentLocationPolicy, PersistentCheckingPolicy>&
0345         p) {
0346   return !(m == p);
0347 }
0348 
0349 template <typename T, typename LocationPolicy, typename CheckingPolicy>
0350 struct IsWeak<BasicPersistent<T, internal::WeakPersistentPolicy, LocationPolicy,
0351                               CheckingPolicy>> : std::true_type {};
0352 }  // namespace internal
0353 
0354 /**
0355  * Persistent is a way to create a strong pointer from an off-heap object to
0356  * another on-heap object. As long as the Persistent handle is alive the GC will
0357  * keep the object pointed to alive. The Persistent handle is always a GC root
0358  * from the point of view of the GC. Persistent must be constructed and
0359  * destructed in the same thread.
0360  */
0361 template <typename T>
0362 using Persistent =
0363     internal::BasicPersistent<T, internal::StrongPersistentPolicy>;
0364 
0365 /**
0366  * WeakPersistent is a way to create a weak pointer from an off-heap object to
0367  * an on-heap object. The pointer is automatically cleared when the pointee gets
0368  * collected. WeakPersistent must be constructed and destructed in the same
0369  * thread.
0370  */
0371 template <typename T>
0372 using WeakPersistent =
0373     internal::BasicPersistent<T, internal::WeakPersistentPolicy>;
0374 
0375 }  // namespace cppgc
0376 
0377 #endif  // INCLUDE_CPPGC_PERSISTENT_H_