// 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_PERSISTENT_H_ #define INCLUDE_CPPGC_PERSISTENT_H_ #include #include "cppgc/internal/persistent-node.h" #include "cppgc/internal/pointer-policies.h" #include "cppgc/source-location.h" #include "cppgc/type-traits.h" #include "cppgc/visitor.h" #include "v8config.h" // NOLINT(build/include_directory) namespace cppgc { namespace internal { // The basic class from which all Persistent classes are generated. template class BasicPersistent : public LocationPolicy, private WeaknessPolicy, private CheckingPolicy { public: using typename WeaknessPolicy::IsStrongPersistent; using PointeeType = T; // Null-state/sentinel constructors. BasicPersistent( // NOLINT const SourceLocation& loc = SourceLocation::Current()) : LocationPolicy(loc) {} BasicPersistent(std::nullptr_t, // NOLINT const SourceLocation& loc = SourceLocation::Current()) : LocationPolicy(loc) {} BasicPersistent( // NOLINT SentinelPointer s, const SourceLocation& loc = SourceLocation::Current()) : LocationPolicy(loc), raw_(s) {} // Raw value contstructors. BasicPersistent(T* raw, // NOLINT const SourceLocation& loc = SourceLocation::Current()) : LocationPolicy(loc), raw_(raw) { if (!IsValid()) return; node_ = WeaknessPolicy::GetPersistentRegion(raw_).AllocateNode( this, &BasicPersistent::Trace); this->CheckPointer(Get()); } BasicPersistent(T& raw, // NOLINT const SourceLocation& loc = SourceLocation::Current()) : BasicPersistent(&raw, loc) {} // Copy ctor. BasicPersistent(const BasicPersistent& other, const SourceLocation& loc = SourceLocation::Current()) : BasicPersistent(other.Get(), loc) {} // Heterogeneous ctor. template ::value>> BasicPersistent( // NOLINT const BasicPersistent& other, const SourceLocation& loc = SourceLocation::Current()) : BasicPersistent(other.Get(), loc) {} // Move ctor. The heterogeneous move ctor is not supported since e.g. // persistent can't reuse persistent node from weak persistent. BasicPersistent( BasicPersistent&& other, const SourceLocation& loc = SourceLocation::Current()) noexcept : LocationPolicy(std::move(other)), raw_(std::move(other.raw_)), node_(std::move(other.node_)) { if (!IsValid()) return; node_->UpdateOwner(this); other.raw_ = nullptr; other.node_ = nullptr; this->CheckPointer(Get()); } // Constructor from member. template ::value>> BasicPersistent(internal::BasicMember member, const SourceLocation& loc = SourceLocation::Current()) : BasicPersistent(member.Get(), loc) {} ~BasicPersistent() { Clear(); } // Copy assignment. BasicPersistent& operator=(const BasicPersistent& other) { return operator=(other.Get()); } template ::value>> BasicPersistent& operator=( const BasicPersistent& other) { return operator=(other.Get()); } // Move assignment. BasicPersistent& operator=(BasicPersistent&& other) { if (this == &other) return *this; Clear(); LocationPolicy::operator=(std::move(other)); raw_ = std::move(other.raw_); node_ = std::move(other.node_); if (!IsValid()) return *this; node_->UpdateOwner(this); other.raw_ = nullptr; other.node_ = nullptr; this->CheckPointer(Get()); return *this; } // Assignment from member. template ::value>> BasicPersistent& operator=( internal::BasicMember member) { return operator=(member.Get()); } BasicPersistent& operator=(T* other) { Assign(other); return *this; } BasicPersistent& operator=(std::nullptr_t) { Clear(); return *this; } BasicPersistent& operator=(SentinelPointer s) { Assign(s); return *this; } explicit operator bool() const { return Get(); } operator T*() const { return Get(); } T* operator->() const { return Get(); } T& operator*() const { return *Get(); } T* Get() const { return raw_; } void Clear() { Assign(nullptr); } T* Release() { T* result = Get(); Clear(); return result; } private: static void Trace(Visitor* v, const void* ptr) { const auto* persistent = static_cast(ptr); v->TraceRoot(*persistent, persistent->Location()); } bool IsValid() const { // Ideally, handling kSentinelPointer would be done by the embedder. On the // other hand, having Persistent aware of it is beneficial since no node // gets wasted. return raw_ != nullptr && raw_ != kSentinelPointer; } void Assign(T* ptr) { if (IsValid()) { if (ptr && ptr != kSentinelPointer) { // Simply assign the pointer reusing the existing node. raw_ = ptr; this->CheckPointer(ptr); return; } WeaknessPolicy::GetPersistentRegion(raw_).FreeNode(node_); node_ = nullptr; } raw_ = ptr; if (!IsValid()) return; node_ = WeaknessPolicy::GetPersistentRegion(raw_).AllocateNode( this, &BasicPersistent::Trace); this->CheckPointer(Get()); } T* raw_ = nullptr; PersistentNode* node_ = nullptr; }; template bool operator==(const BasicPersistent& p1, const BasicPersistent& p2) { return p1.Get() == p2.Get(); } template bool operator!=(const BasicPersistent& p1, const BasicPersistent& p2) { return !(p1 == p2); } template bool operator==(const BasicPersistent& p, BasicMember m) { return p.Get() == m.Get(); } template bool operator!=(const BasicPersistent& p, BasicMember m) { return !(p == m); } template bool operator==(BasicMember m, const BasicPersistent& p) { return m.Get() == p.Get(); } template bool operator!=(BasicMember m, const BasicPersistent& p) { return !(m == p); } template struct IsWeak> : std::true_type {}; } // namespace internal /** * Persistent is a way to create a strong pointer from an off-heap object to * another on-heap object. As long as the Persistent handle is alive the GC will * keep the object pointed to alive. The Persistent handle is always a GC root * from the point of view of the GC. Persistent must be constructed and * destructed in the same thread. */ template using Persistent = internal::BasicPersistent; /** * WeakPersistent is a way to create a weak pointer from an off-heap object to * an on-heap object. The pointer is automatically cleared when the pointee gets * collected. WeakPersistent must be constructed and destructed in the same * thread. */ template using WeakPersistent = internal::BasicPersistent; } // namespace cppgc #endif // INCLUDE_CPPGC_PERSISTENT_H_