Add files
This commit is contained in:
366
v8/include/cppgc/persistent.h
Normal file
366
v8/include/cppgc/persistent.h
Normal file
@ -0,0 +1,366 @@
|
||||
// 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 <type_traits>
|
||||
|
||||
#include "cppgc/internal/persistent-node.h"
|
||||
#include "cppgc/internal/pointer-policies.h"
|
||||
#include "cppgc/sentinel-pointer.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 {
|
||||
|
||||
// PersistentBase always refers to the object as const object and defers to
|
||||
// BasicPersistent on casting to the right type as needed.
|
||||
class PersistentBase {
|
||||
protected:
|
||||
PersistentBase() = default;
|
||||
explicit PersistentBase(const void* raw) : raw_(raw) {}
|
||||
|
||||
const void* GetValue() const { return raw_; }
|
||||
void SetValue(const void* value) { raw_ = value; }
|
||||
|
||||
PersistentNode* GetNode() const { return node_; }
|
||||
void SetNode(PersistentNode* node) { node_ = node; }
|
||||
|
||||
// Performs a shallow clear which assumes that internal persistent nodes are
|
||||
// destroyed elsewhere.
|
||||
void ClearFromGC() const {
|
||||
raw_ = nullptr;
|
||||
node_ = nullptr;
|
||||
}
|
||||
|
||||
protected:
|
||||
mutable const void* raw_ = nullptr;
|
||||
mutable PersistentNode* node_ = nullptr;
|
||||
|
||||
friend class PersistentRegionBase;
|
||||
};
|
||||
|
||||
// The basic class from which all Persistent classes are generated.
|
||||
template <typename T, typename WeaknessPolicy, typename LocationPolicy,
|
||||
typename CheckingPolicy>
|
||||
class BasicPersistent final : public PersistentBase,
|
||||
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())
|
||||
: PersistentBase(s), LocationPolicy(loc) {}
|
||||
|
||||
// Raw value constructors.
|
||||
BasicPersistent(T* raw, // NOLINT
|
||||
const SourceLocation& loc = SourceLocation::Current())
|
||||
: PersistentBase(raw), LocationPolicy(loc) {
|
||||
if (!IsValid()) return;
|
||||
SetNode(WeaknessPolicy::GetPersistentRegion(GetValue())
|
||||
.AllocateNode(this, &TraceAsRoot));
|
||||
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 <typename U, typename OtherWeaknessPolicy,
|
||||
typename OtherLocationPolicy, typename OtherCheckingPolicy,
|
||||
typename = std::enable_if_t<std::is_base_of<T, U>::value>>
|
||||
BasicPersistent(
|
||||
const BasicPersistent<U, OtherWeaknessPolicy, OtherLocationPolicy,
|
||||
OtherCheckingPolicy>& 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
|
||||
: PersistentBase(std::move(other)), LocationPolicy(std::move(other)) {
|
||||
if (!IsValid()) return;
|
||||
GetNode()->UpdateOwner(this);
|
||||
other.SetValue(nullptr);
|
||||
other.SetNode(nullptr);
|
||||
this->CheckPointer(Get());
|
||||
}
|
||||
|
||||
// Constructor from member.
|
||||
template <typename U, typename MemberBarrierPolicy,
|
||||
typename MemberWeaknessTag, typename MemberCheckingPolicy,
|
||||
typename = std::enable_if_t<std::is_base_of<T, U>::value>>
|
||||
BasicPersistent(
|
||||
const internal::BasicMember<U, MemberBarrierPolicy, MemberWeaknessTag,
|
||||
MemberCheckingPolicy>& member,
|
||||
const SourceLocation& loc = SourceLocation::Current())
|
||||
: BasicPersistent(member.Get(), loc) {}
|
||||
|
||||
~BasicPersistent() { Clear(); }
|
||||
|
||||
// Copy assignment.
|
||||
BasicPersistent& operator=(const BasicPersistent& other) {
|
||||
return operator=(other.Get());
|
||||
}
|
||||
|
||||
template <typename U, typename OtherWeaknessPolicy,
|
||||
typename OtherLocationPolicy, typename OtherCheckingPolicy,
|
||||
typename = std::enable_if_t<std::is_base_of<T, U>::value>>
|
||||
BasicPersistent& operator=(
|
||||
const BasicPersistent<U, OtherWeaknessPolicy, OtherLocationPolicy,
|
||||
OtherCheckingPolicy>& other) {
|
||||
return operator=(other.Get());
|
||||
}
|
||||
|
||||
// Move assignment.
|
||||
BasicPersistent& operator=(BasicPersistent&& other) noexcept {
|
||||
if (this == &other) return *this;
|
||||
Clear();
|
||||
PersistentBase::operator=(std::move(other));
|
||||
LocationPolicy::operator=(std::move(other));
|
||||
if (!IsValid()) return *this;
|
||||
GetNode()->UpdateOwner(this);
|
||||
other.SetValue(nullptr);
|
||||
other.SetNode(nullptr);
|
||||
this->CheckPointer(Get());
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Assignment from member.
|
||||
template <typename U, typename MemberBarrierPolicy,
|
||||
typename MemberWeaknessTag, typename MemberCheckingPolicy,
|
||||
typename = std::enable_if_t<std::is_base_of<T, U>::value>>
|
||||
BasicPersistent& operator=(
|
||||
const internal::BasicMember<U, MemberBarrierPolicy, MemberWeaknessTag,
|
||||
MemberCheckingPolicy>& 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(); }
|
||||
|
||||
// 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_CLANG_NO_SANITIZE("cfi-unrelated-cast") T* Get() const {
|
||||
// The const_cast below removes the constness from PersistentBase 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*>(GetValue()));
|
||||
}
|
||||
|
||||
void Clear() {
|
||||
// Simplified version of `Assign()` to allow calling without a complete type
|
||||
// `T`.
|
||||
if (IsValid()) {
|
||||
WeaknessPolicy::GetPersistentRegion(GetValue()).FreeNode(GetNode());
|
||||
SetNode(nullptr);
|
||||
}
|
||||
SetValue(nullptr);
|
||||
}
|
||||
|
||||
T* Release() {
|
||||
T* result = Get();
|
||||
Clear();
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename U, typename OtherWeaknessPolicy = WeaknessPolicy,
|
||||
typename OtherLocationPolicy = LocationPolicy,
|
||||
typename OtherCheckingPolicy = CheckingPolicy>
|
||||
BasicPersistent<U, OtherWeaknessPolicy, OtherLocationPolicy,
|
||||
OtherCheckingPolicy>
|
||||
To() const {
|
||||
return BasicPersistent<U, OtherWeaknessPolicy, OtherLocationPolicy,
|
||||
OtherCheckingPolicy>(static_cast<U*>(Get()));
|
||||
}
|
||||
|
||||
private:
|
||||
static void TraceAsRoot(RootVisitor& root_visitor, const void* ptr) {
|
||||
root_visitor.Trace(*static_cast<const BasicPersistent*>(ptr));
|
||||
}
|
||||
|
||||
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 GetValue() != nullptr && GetValue() != kSentinelPointer;
|
||||
}
|
||||
|
||||
void Assign(T* ptr) {
|
||||
if (IsValid()) {
|
||||
if (ptr && ptr != kSentinelPointer) {
|
||||
// Simply assign the pointer reusing the existing node.
|
||||
SetValue(ptr);
|
||||
this->CheckPointer(ptr);
|
||||
return;
|
||||
}
|
||||
WeaknessPolicy::GetPersistentRegion(GetValue()).FreeNode(GetNode());
|
||||
SetNode(nullptr);
|
||||
}
|
||||
SetValue(ptr);
|
||||
if (!IsValid()) return;
|
||||
SetNode(WeaknessPolicy::GetPersistentRegion(GetValue())
|
||||
.AllocateNode(this, &TraceAsRoot));
|
||||
this->CheckPointer(Get());
|
||||
}
|
||||
|
||||
void ClearFromGC() const {
|
||||
if (IsValid()) {
|
||||
WeaknessPolicy::GetPersistentRegion(GetValue()).FreeNode(GetNode());
|
||||
PersistentBase::ClearFromGC();
|
||||
}
|
||||
}
|
||||
|
||||
// Set Get() for details.
|
||||
V8_CLANG_NO_SANITIZE("cfi-unrelated-cast")
|
||||
T* GetFromGC() const {
|
||||
return static_cast<T*>(const_cast<void*>(GetValue()));
|
||||
}
|
||||
|
||||
friend class internal::RootVisitor;
|
||||
};
|
||||
|
||||
template <typename T1, typename WeaknessPolicy1, typename LocationPolicy1,
|
||||
typename CheckingPolicy1, typename T2, typename WeaknessPolicy2,
|
||||
typename LocationPolicy2, typename CheckingPolicy2>
|
||||
bool operator==(const BasicPersistent<T1, WeaknessPolicy1, LocationPolicy1,
|
||||
CheckingPolicy1>& p1,
|
||||
const BasicPersistent<T2, WeaknessPolicy2, LocationPolicy2,
|
||||
CheckingPolicy2>& p2) {
|
||||
return p1.Get() == p2.Get();
|
||||
}
|
||||
|
||||
template <typename T1, typename WeaknessPolicy1, typename LocationPolicy1,
|
||||
typename CheckingPolicy1, typename T2, typename WeaknessPolicy2,
|
||||
typename LocationPolicy2, typename CheckingPolicy2>
|
||||
bool operator!=(const BasicPersistent<T1, WeaknessPolicy1, LocationPolicy1,
|
||||
CheckingPolicy1>& p1,
|
||||
const BasicPersistent<T2, WeaknessPolicy2, LocationPolicy2,
|
||||
CheckingPolicy2>& p2) {
|
||||
return !(p1 == p2);
|
||||
}
|
||||
|
||||
template <typename T1, typename PersistentWeaknessPolicy,
|
||||
typename PersistentLocationPolicy, typename PersistentCheckingPolicy,
|
||||
typename T2, typename MemberWriteBarrierPolicy,
|
||||
typename MemberWeaknessTag, typename MemberCheckingPolicy>
|
||||
bool operator==(
|
||||
const BasicPersistent<T1, PersistentWeaknessPolicy,
|
||||
PersistentLocationPolicy, PersistentCheckingPolicy>&
|
||||
p,
|
||||
const BasicMember<T2, MemberWeaknessTag, MemberWriteBarrierPolicy,
|
||||
MemberCheckingPolicy>& m) {
|
||||
return p.Get() == m.Get();
|
||||
}
|
||||
|
||||
template <typename T1, typename PersistentWeaknessPolicy,
|
||||
typename PersistentLocationPolicy, typename PersistentCheckingPolicy,
|
||||
typename T2, typename MemberWriteBarrierPolicy,
|
||||
typename MemberWeaknessTag, typename MemberCheckingPolicy>
|
||||
bool operator!=(
|
||||
const BasicPersistent<T1, PersistentWeaknessPolicy,
|
||||
PersistentLocationPolicy, PersistentCheckingPolicy>&
|
||||
p,
|
||||
const BasicMember<T2, MemberWeaknessTag, MemberWriteBarrierPolicy,
|
||||
MemberCheckingPolicy>& m) {
|
||||
return !(p == m);
|
||||
}
|
||||
|
||||
template <typename T1, typename MemberWriteBarrierPolicy,
|
||||
typename MemberWeaknessTag, typename MemberCheckingPolicy,
|
||||
typename T2, typename PersistentWeaknessPolicy,
|
||||
typename PersistentLocationPolicy, typename PersistentCheckingPolicy>
|
||||
bool operator==(
|
||||
const BasicMember<T2, MemberWeaknessTag, MemberWriteBarrierPolicy,
|
||||
MemberCheckingPolicy>& m,
|
||||
const BasicPersistent<T1, PersistentWeaknessPolicy,
|
||||
PersistentLocationPolicy, PersistentCheckingPolicy>&
|
||||
p) {
|
||||
return m.Get() == p.Get();
|
||||
}
|
||||
|
||||
template <typename T1, typename MemberWriteBarrierPolicy,
|
||||
typename MemberWeaknessTag, typename MemberCheckingPolicy,
|
||||
typename T2, typename PersistentWeaknessPolicy,
|
||||
typename PersistentLocationPolicy, typename PersistentCheckingPolicy>
|
||||
bool operator!=(
|
||||
const BasicMember<T2, MemberWeaknessTag, MemberWriteBarrierPolicy,
|
||||
MemberCheckingPolicy>& m,
|
||||
const BasicPersistent<T1, PersistentWeaknessPolicy,
|
||||
PersistentLocationPolicy, PersistentCheckingPolicy>&
|
||||
p) {
|
||||
return !(m == p);
|
||||
}
|
||||
|
||||
template <typename T, typename LocationPolicy, typename CheckingPolicy>
|
||||
struct IsWeak<BasicPersistent<T, internal::WeakPersistentPolicy, LocationPolicy,
|
||||
CheckingPolicy>> : 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 <typename T>
|
||||
using Persistent =
|
||||
internal::BasicPersistent<T, internal::StrongPersistentPolicy>;
|
||||
|
||||
/**
|
||||
* 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 <typename T>
|
||||
using WeakPersistent =
|
||||
internal::BasicPersistent<T, internal::WeakPersistentPolicy>;
|
||||
|
||||
} // namespace cppgc
|
||||
|
||||
#endif // INCLUDE_CPPGC_PERSISTENT_H_
|
Reference in New Issue
Block a user