????
Current Path : /opt/cpanel/ea-nodejs22/include/node/cppgc/ |
Current File : //opt/cpanel/ea-nodejs22/include/node/cppgc/member.h |
// Copyright 2020 the V8 project authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef INCLUDE_CPPGC_MEMBER_H_ #define INCLUDE_CPPGC_MEMBER_H_ #include <atomic> #include <cstddef> #include <type_traits> #include "cppgc/internal/api-constants.h" #include "cppgc/internal/member-storage.h" #include "cppgc/internal/pointer-policies.h" #include "cppgc/sentinel-pointer.h" #include "cppgc/type-traits.h" #include "v8config.h" // NOLINT(build/include_directory) namespace cppgc { namespace subtle { class HeapConsistency; } // namespace subtle class Visitor; namespace internal { // MemberBase always refers to the object as const object and defers to // BasicMember on casting to the right type as needed. template <typename StorageType> class V8_TRIVIAL_ABI MemberBase { public: using RawStorage = StorageType; protected: struct AtomicInitializerTag {}; V8_INLINE MemberBase() = default; V8_INLINE explicit MemberBase(const void* value) : raw_(value) {} V8_INLINE MemberBase(const void* value, AtomicInitializerTag) { SetRawAtomic(value); } V8_INLINE explicit MemberBase(RawStorage raw) : raw_(raw) {} V8_INLINE explicit MemberBase(std::nullptr_t) : raw_(nullptr) {} V8_INLINE explicit MemberBase(SentinelPointer s) : raw_(s) {} V8_INLINE const void** GetRawSlot() const { return reinterpret_cast<const void**>(const_cast<MemberBase*>(this)); } V8_INLINE const void* GetRaw() const { return raw_.Load(); } V8_INLINE void SetRaw(void* value) { raw_.Store(value); } V8_INLINE const void* GetRawAtomic() const { return raw_.LoadAtomic(); } V8_INLINE void SetRawAtomic(const void* value) { raw_.StoreAtomic(value); } V8_INLINE RawStorage GetRawStorage() const { return raw_; } V8_INLINE void SetRawStorageAtomic(RawStorage other) { reinterpret_cast<std::atomic<RawStorage>&>(raw_).store( other, std::memory_order_relaxed); } V8_INLINE bool IsCleared() const { return raw_.IsCleared(); } V8_INLINE void ClearFromGC() const { raw_.Clear(); } private: friend class MemberDebugHelper; mutable RawStorage raw_; }; // The basic class from which all Member classes are 'generated'. template <typename T, typename WeaknessTag, typename WriteBarrierPolicy, typename CheckingPolicy, typename StorageType> class V8_TRIVIAL_ABI BasicMember final : private MemberBase<StorageType>, private CheckingPolicy { using Base = MemberBase<StorageType>; public: using PointeeType = T; using RawStorage = typename Base::RawStorage; V8_INLINE constexpr BasicMember() = default; V8_INLINE constexpr BasicMember(std::nullptr_t) {} // NOLINT V8_INLINE BasicMember(SentinelPointer s) : Base(s) {} // NOLINT V8_INLINE BasicMember(T* raw) : Base(raw) { // NOLINT InitializingWriteBarrier(raw); this->CheckPointer(Get()); } V8_INLINE BasicMember(T& raw) // NOLINT : BasicMember(&raw) {} // Atomic ctor. Using the AtomicInitializerTag forces BasicMember to // initialize using atomic assignments. This is required for preventing // data races with concurrent marking. using AtomicInitializerTag = typename Base::AtomicInitializerTag; V8_INLINE BasicMember(std::nullptr_t, AtomicInitializerTag atomic) : Base(nullptr, atomic) {} V8_INLINE BasicMember(SentinelPointer s, AtomicInitializerTag atomic) : Base(s, atomic) {} V8_INLINE BasicMember(T* raw, AtomicInitializerTag atomic) : Base(raw, atomic) { InitializingWriteBarrier(raw); this->CheckPointer(Get()); } V8_INLINE BasicMember(T& raw, AtomicInitializerTag atomic) : BasicMember(&raw, atomic) {} // Copy ctor. V8_INLINE BasicMember(const BasicMember& other) : BasicMember(other.GetRawStorage()) {} // Heterogeneous copy constructors. When the source pointer have a different // type, perform a compress-decompress round, because the source pointer may // need to be adjusted. template <typename U, typename OtherBarrierPolicy, typename OtherWeaknessTag, typename OtherCheckingPolicy, std::enable_if_t<internal::IsDecayedSameV<T, U>>* = nullptr> V8_INLINE BasicMember( // NOLINT const BasicMember<U, OtherWeaknessTag, OtherBarrierPolicy, OtherCheckingPolicy, StorageType>& other) : BasicMember(other.GetRawStorage()) {} template <typename U, typename OtherBarrierPolicy, typename OtherWeaknessTag, typename OtherCheckingPolicy, std::enable_if_t<internal::IsStrictlyBaseOfV<T, U>>* = nullptr> V8_INLINE BasicMember( // NOLINT const BasicMember<U, OtherWeaknessTag, OtherBarrierPolicy, OtherCheckingPolicy, StorageType>& other) : BasicMember(other.Get()) {} // Move ctor. V8_INLINE BasicMember(BasicMember&& other) noexcept : BasicMember(other.GetRawStorage()) { other.Clear(); } // Heterogeneous move constructors. When the source pointer have a different // type, perform a compress-decompress round, because the source pointer may // need to be adjusted. template <typename U, typename OtherBarrierPolicy, typename OtherWeaknessTag, typename OtherCheckingPolicy, std::enable_if_t<internal::IsDecayedSameV<T, U>>* = nullptr> V8_INLINE BasicMember( BasicMember<U, OtherWeaknessTag, OtherBarrierPolicy, OtherCheckingPolicy, StorageType>&& other) noexcept : BasicMember(other.GetRawStorage()) { other.Clear(); } template <typename U, typename OtherBarrierPolicy, typename OtherWeaknessTag, typename OtherCheckingPolicy, std::enable_if_t<internal::IsStrictlyBaseOfV<T, U>>* = nullptr> V8_INLINE BasicMember( BasicMember<U, OtherWeaknessTag, OtherBarrierPolicy, OtherCheckingPolicy, StorageType>&& other) noexcept : BasicMember(other.Get()) { other.Clear(); } // Construction from Persistent. template <typename U, typename PersistentWeaknessPolicy, typename PersistentLocationPolicy, typename PersistentCheckingPolicy, typename = std::enable_if_t<std::is_base_of<T, U>::value>> V8_INLINE BasicMember(const BasicPersistent<U, PersistentWeaknessPolicy, PersistentLocationPolicy, PersistentCheckingPolicy>& p) : BasicMember(p.Get()) {} // Copy assignment. V8_INLINE BasicMember& operator=(const BasicMember& other) { return operator=(other.GetRawStorage()); } // Heterogeneous copy assignment. When the source pointer have a different // type, perform a compress-decompress round, because the source pointer may // need to be adjusted. template <typename U, typename OtherWeaknessTag, typename OtherBarrierPolicy, typename OtherCheckingPolicy> V8_INLINE BasicMember& operator=( const BasicMember<U, OtherWeaknessTag, OtherBarrierPolicy, OtherCheckingPolicy, StorageType>& other) { if constexpr (internal::IsDecayedSameV<T, U>) { return operator=(other.GetRawStorage()); } else { static_assert(internal::IsStrictlyBaseOfV<T, U>); return operator=(other.Get()); } } // Move assignment. V8_INLINE BasicMember& operator=(BasicMember&& other) noexcept { operator=(other.GetRawStorage()); other.Clear(); return *this; } // Heterogeneous move assignment. When the source pointer have a different // type, perform a compress-decompress round, because the source pointer may // need to be adjusted. template <typename U, typename OtherWeaknessTag, typename OtherBarrierPolicy, typename OtherCheckingPolicy> V8_INLINE BasicMember& operator=( BasicMember<U, OtherWeaknessTag, OtherBarrierPolicy, OtherCheckingPolicy, StorageType>&& other) noexcept { if constexpr (internal::IsDecayedSameV<T, U>) { operator=(other.GetRawStorage()); } else { static_assert(internal::IsStrictlyBaseOfV<T, U>); operator=(other.Get()); } other.Clear(); return *this; } // Assignment from Persistent. template <typename U, typename PersistentWeaknessPolicy, typename PersistentLocationPolicy, typename PersistentCheckingPolicy, typename = std::enable_if_t<std::is_base_of<T, U>::value>> V8_INLINE BasicMember& operator=( const BasicPersistent<U, PersistentWeaknessPolicy, PersistentLocationPolicy, PersistentCheckingPolicy>& other) { return operator=(other.Get()); } V8_INLINE BasicMember& operator=(T* other) { Base::SetRawAtomic(other); AssigningWriteBarrier(other); this->CheckPointer(Get()); return *this; } V8_INLINE BasicMember& operator=(std::nullptr_t) { Clear(); return *this; } V8_INLINE BasicMember& operator=(SentinelPointer s) { Base::SetRawAtomic(s); return *this; } template <typename OtherWeaknessTag, typename OtherBarrierPolicy, typename OtherCheckingPolicy> V8_INLINE void Swap(BasicMember<T, OtherWeaknessTag, OtherBarrierPolicy, OtherCheckingPolicy, StorageType>& other) { auto tmp = GetRawStorage(); *this = other; other = tmp; } V8_INLINE explicit operator bool() const { return !Base::IsCleared(); } V8_INLINE operator T*() const { return Get(); } V8_INLINE T* operator->() const { return Get(); } V8_INLINE T& operator*() const { return *Get(); } // CFI cast exemption to allow passing SentinelPointer through T* and support // heterogeneous assignments between different Member and Persistent handles // based on their actual types. V8_INLINE V8_CLANG_NO_SANITIZE("cfi-unrelated-cast") T* Get() const { // Executed by the mutator, hence non atomic load. // // The const_cast below removes the constness from MemberBase storage. The // following static_cast re-adds any constness if specified through the // user-visible template parameter T. return static_cast<T*>(const_cast<void*>(Base::GetRaw())); } V8_INLINE void Clear() { Base::SetRawStorageAtomic(RawStorage{}); } V8_INLINE T* Release() { T* result = Get(); Clear(); return result; } V8_INLINE const T** GetSlotForTesting() const { return reinterpret_cast<const T**>(Base::GetRawSlot()); } V8_INLINE RawStorage GetRawStorage() const { return Base::GetRawStorage(); } private: V8_INLINE explicit BasicMember(RawStorage raw) : Base(raw) { InitializingWriteBarrier(Get()); this->CheckPointer(Get()); } V8_INLINE BasicMember& operator=(RawStorage other) { Base::SetRawStorageAtomic(other); AssigningWriteBarrier(); this->CheckPointer(Get()); return *this; } V8_INLINE const T* GetRawAtomic() const { return static_cast<const T*>(Base::GetRawAtomic()); } V8_INLINE void InitializingWriteBarrier(T* value) const { WriteBarrierPolicy::InitializingBarrier(Base::GetRawSlot(), value); } V8_INLINE void AssigningWriteBarrier(T* value) const { WriteBarrierPolicy::template AssigningBarrier< StorageType::kWriteBarrierSlotType>(Base::GetRawSlot(), value); } V8_INLINE void AssigningWriteBarrier() const { WriteBarrierPolicy::template AssigningBarrier< StorageType::kWriteBarrierSlotType>(Base::GetRawSlot(), Base::GetRawStorage()); } V8_INLINE void ClearFromGC() const { Base::ClearFromGC(); } V8_INLINE T* GetFromGC() const { return Get(); } friend class cppgc::subtle::HeapConsistency; friend class cppgc::Visitor; template <typename U> friend struct cppgc::TraceTrait; template <typename T1, typename WeaknessTag1, typename WriteBarrierPolicy1, typename CheckingPolicy1, typename StorageType1> friend class BasicMember; }; // Member equality operators. template <typename T1, typename WeaknessTag1, typename WriteBarrierPolicy1, typename CheckingPolicy1, typename T2, typename WeaknessTag2, typename WriteBarrierPolicy2, typename CheckingPolicy2, typename StorageType> V8_INLINE bool operator==( const BasicMember<T1, WeaknessTag1, WriteBarrierPolicy1, CheckingPolicy1, StorageType>& member1, const BasicMember<T2, WeaknessTag2, WriteBarrierPolicy2, CheckingPolicy2, StorageType>& member2) { if constexpr (internal::IsDecayedSameV<T1, T2>) { // Check compressed pointers if types are the same. return member1.GetRawStorage() == member2.GetRawStorage(); } else { static_assert(internal::IsStrictlyBaseOfV<T1, T2> || internal::IsStrictlyBaseOfV<T2, T1>); // Otherwise, check decompressed pointers. return member1.Get() == member2.Get(); } } template <typename T1, typename WeaknessTag1, typename WriteBarrierPolicy1, typename CheckingPolicy1, typename T2, typename WeaknessTag2, typename WriteBarrierPolicy2, typename CheckingPolicy2, typename StorageType> V8_INLINE bool operator!=( const BasicMember<T1, WeaknessTag1, WriteBarrierPolicy1, CheckingPolicy1, StorageType>& member1, const BasicMember<T2, WeaknessTag2, WriteBarrierPolicy2, CheckingPolicy2, StorageType>& member2) { return !(member1 == member2); } // Equality with raw pointers. template <typename T, typename WeaknessTag, typename WriteBarrierPolicy, typename CheckingPolicy, typename StorageType, typename U> V8_INLINE bool operator==( const BasicMember<T, WeaknessTag, WriteBarrierPolicy, CheckingPolicy, StorageType>& member, U* raw) { // Never allow comparison with erased pointers. static_assert(!internal::IsDecayedSameV<void, U>); if constexpr (internal::IsDecayedSameV<T, U>) { // Check compressed pointers if types are the same. return member.GetRawStorage() == StorageType(raw); } else if constexpr (internal::IsStrictlyBaseOfV<T, U>) { // Cast the raw pointer to T, which may adjust the pointer. return member.GetRawStorage() == StorageType(static_cast<T*>(raw)); } else { // Otherwise, decompressed the member. return member.Get() == raw; } } template <typename T, typename WeaknessTag, typename WriteBarrierPolicy, typename CheckingPolicy, typename StorageType, typename U> V8_INLINE bool operator!=( const BasicMember<T, WeaknessTag, WriteBarrierPolicy, CheckingPolicy, StorageType>& member, U* raw) { return !(member == raw); } template <typename T, typename U, typename WeaknessTag, typename WriteBarrierPolicy, typename CheckingPolicy, typename StorageType> V8_INLINE bool operator==( T* raw, const BasicMember<U, WeaknessTag, WriteBarrierPolicy, CheckingPolicy, StorageType>& member) { return member == raw; } template <typename T, typename U, typename WeaknessTag, typename WriteBarrierPolicy, typename CheckingPolicy, typename StorageType> V8_INLINE bool operator!=( T* raw, const BasicMember<U, WeaknessTag, WriteBarrierPolicy, CheckingPolicy, StorageType>& member) { return !(raw == member); } // Equality with sentinel. template <typename T, typename WeaknessTag, typename WriteBarrierPolicy, typename CheckingPolicy, typename StorageType> V8_INLINE bool operator==( const BasicMember<T, WeaknessTag, WriteBarrierPolicy, CheckingPolicy, StorageType>& member, SentinelPointer) { return member.GetRawStorage().IsSentinel(); } template <typename T, typename WeaknessTag, typename WriteBarrierPolicy, typename CheckingPolicy, typename StorageType> V8_INLINE bool operator!=( const BasicMember<T, WeaknessTag, WriteBarrierPolicy, CheckingPolicy, StorageType>& member, SentinelPointer s) { return !(member == s); } template <typename T, typename WeaknessTag, typename WriteBarrierPolicy, typename CheckingPolicy, typename StorageType> V8_INLINE bool operator==( SentinelPointer s, const BasicMember<T, WeaknessTag, WriteBarrierPolicy, CheckingPolicy, StorageType>& member) { return member == s; } template <typename T, typename WeaknessTag, typename WriteBarrierPolicy, typename CheckingPolicy, typename StorageType> V8_INLINE bool operator!=( SentinelPointer s, const BasicMember<T, WeaknessTag, WriteBarrierPolicy, CheckingPolicy, StorageType>& member) { return !(s == member); } // Equality with nullptr. template <typename T, typename WeaknessTag, typename WriteBarrierPolicy, typename CheckingPolicy, typename StorageType> V8_INLINE bool operator==( const BasicMember<T, WeaknessTag, WriteBarrierPolicy, CheckingPolicy, StorageType>& member, std::nullptr_t) { return !static_cast<bool>(member); } template <typename T, typename WeaknessTag, typename WriteBarrierPolicy, typename CheckingPolicy, typename StorageType> V8_INLINE bool operator!=( const BasicMember<T, WeaknessTag, WriteBarrierPolicy, CheckingPolicy, StorageType>& member, std::nullptr_t n) { return !(member == n); } template <typename T, typename WeaknessTag, typename WriteBarrierPolicy, typename CheckingPolicy, typename StorageType> V8_INLINE bool operator==( std::nullptr_t n, const BasicMember<T, WeaknessTag, WriteBarrierPolicy, CheckingPolicy, StorageType>& member) { return member == n; } template <typename T, typename WeaknessTag, typename WriteBarrierPolicy, typename CheckingPolicy, typename StorageType> V8_INLINE bool operator!=( std::nullptr_t n, const BasicMember<T, WeaknessTag, WriteBarrierPolicy, CheckingPolicy, StorageType>& member) { return !(n == member); } // Relational operators. template <typename T1, typename WeaknessTag1, typename WriteBarrierPolicy1, typename CheckingPolicy1, typename T2, typename WeaknessTag2, typename WriteBarrierPolicy2, typename CheckingPolicy2, typename StorageType> V8_INLINE bool operator<( const BasicMember<T1, WeaknessTag1, WriteBarrierPolicy1, CheckingPolicy1, StorageType>& member1, const BasicMember<T2, WeaknessTag2, WriteBarrierPolicy2, CheckingPolicy2, StorageType>& member2) { static_assert( internal::IsDecayedSameV<T1, T2>, "Comparison works only for same pointer type modulo cv-qualifiers"); return member1.GetRawStorage() < member2.GetRawStorage(); } template <typename T1, typename WeaknessTag1, typename WriteBarrierPolicy1, typename CheckingPolicy1, typename T2, typename WeaknessTag2, typename WriteBarrierPolicy2, typename CheckingPolicy2, typename StorageType> V8_INLINE bool operator<=( const BasicMember<T1, WeaknessTag1, WriteBarrierPolicy1, CheckingPolicy1, StorageType>& member1, const BasicMember<T2, WeaknessTag2, WriteBarrierPolicy2, CheckingPolicy2, StorageType>& member2) { static_assert( internal::IsDecayedSameV<T1, T2>, "Comparison works only for same pointer type modulo cv-qualifiers"); return member1.GetRawStorage() <= member2.GetRawStorage(); } template <typename T1, typename WeaknessTag1, typename WriteBarrierPolicy1, typename CheckingPolicy1, typename T2, typename WeaknessTag2, typename WriteBarrierPolicy2, typename CheckingPolicy2, typename StorageType> V8_INLINE bool operator>( const BasicMember<T1, WeaknessTag1, WriteBarrierPolicy1, CheckingPolicy1, StorageType>& member1, const BasicMember<T2, WeaknessTag2, WriteBarrierPolicy2, CheckingPolicy2, StorageType>& member2) { static_assert( internal::IsDecayedSameV<T1, T2>, "Comparison works only for same pointer type modulo cv-qualifiers"); return member1.GetRawStorage() > member2.GetRawStorage(); } template <typename T1, typename WeaknessTag1, typename WriteBarrierPolicy1, typename CheckingPolicy1, typename T2, typename WeaknessTag2, typename WriteBarrierPolicy2, typename CheckingPolicy2, typename StorageType> V8_INLINE bool operator>=( const BasicMember<T1, WeaknessTag1, WriteBarrierPolicy1, CheckingPolicy1, StorageType>& member1, const BasicMember<T2, WeaknessTag2, WriteBarrierPolicy2, CheckingPolicy2, StorageType>& member2) { static_assert( internal::IsDecayedSameV<T1, T2>, "Comparison works only for same pointer type modulo cv-qualifiers"); return member1.GetRawStorage() >= member2.GetRawStorage(); } template <typename T, typename WriteBarrierPolicy, typename CheckingPolicy, typename StorageType> struct IsWeak<internal::BasicMember<T, WeakMemberTag, WriteBarrierPolicy, CheckingPolicy, StorageType>> : std::true_type {}; } // namespace internal /** * Members are used in classes to contain strong pointers to other garbage * collected objects. All Member fields of a class must be traced in the class' * trace method. */ template <typename T> using Member = internal::BasicMember< T, internal::StrongMemberTag, internal::DijkstraWriteBarrierPolicy, internal::DefaultMemberCheckingPolicy, internal::DefaultMemberStorage>; /** * WeakMember is similar to Member in that it is used to point to other garbage * collected objects. However instead of creating a strong pointer to the * object, the WeakMember creates a weak pointer, which does not keep the * pointee alive. Hence if all pointers to to a heap allocated object are weak * the object will be garbage collected. At the time of GC the weak pointers * will automatically be set to null. */ template <typename T> using WeakMember = internal::BasicMember< T, internal::WeakMemberTag, internal::DijkstraWriteBarrierPolicy, internal::DefaultMemberCheckingPolicy, internal::DefaultMemberStorage>; /** * UntracedMember is a pointer to an on-heap object that is not traced for some * reason. Do not use this unless you know what you are doing. Keeping raw * pointers to on-heap objects is prohibited unless used from stack. Pointee * must be kept alive through other means. */ template <typename T> using UntracedMember = internal::BasicMember< T, internal::UntracedMemberTag, internal::NoWriteBarrierPolicy, internal::DefaultMemberCheckingPolicy, internal::DefaultMemberStorage>; namespace subtle { /** * UncompressedMember. Use with care in hot paths that would otherwise cause * many decompression cycles. */ template <typename T> using UncompressedMember = internal::BasicMember< T, internal::StrongMemberTag, internal::DijkstraWriteBarrierPolicy, internal::DefaultMemberCheckingPolicy, internal::RawPointer>; #if defined(CPPGC_POINTER_COMPRESSION) /** * CompressedMember. Default implementation of cppgc::Member on builds with * pointer compression. */ template <typename T> using CompressedMember = internal::BasicMember< T, internal::StrongMemberTag, internal::DijkstraWriteBarrierPolicy, internal::DefaultMemberCheckingPolicy, internal::CompressedPointer>; #endif // defined(CPPGC_POINTER_COMPRESSION) } // namespace subtle namespace internal { struct Dummy; static constexpr size_t kSizeOfMember = sizeof(Member<Dummy>); static constexpr size_t kSizeOfUncompressedMember = sizeof(subtle::UncompressedMember<Dummy>); #if defined(CPPGC_POINTER_COMPRESSION) static constexpr size_t kSizeofCompressedMember = sizeof(subtle::CompressedMember<Dummy>); #endif // defined(CPPGC_POINTER_COMPRESSION) } // namespace internal } // namespace cppgc #endif // INCLUDE_CPPGC_MEMBER_H_