Commit db7c21e4 authored by Anton Bikineev's avatar Anton Bikineev Committed by Commit Bot

cppgc: Port Persistent

CrossThreadPersistent and friends are the followup.

Bug: chromium:1056170
Change-Id: Ide910062d80952da73b922398c281162b1861f47
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2144957
Commit-Queue: Anton Bikineev <bikineev@chromium.org>
Reviewed-by: 's avatarMichael Lippautz <mlippautz@chromium.org>
Reviewed-by: 's avatarOmer Katz <omerkatz@chromium.org>
Reviewed-by: 's avatarUlan Degenbaev <ulan@chromium.org>
Cr-Commit-Position: refs/heads/master@{#67153}
parent 8428feed
...@@ -218,6 +218,9 @@ declare_args() { ...@@ -218,6 +218,9 @@ declare_args() {
# Enable control-flow integrity features, such as pointer authentication for # Enable control-flow integrity features, such as pointer authentication for
# ARM64. # ARM64.
v8_control_flow_integrity = false v8_control_flow_integrity = false
# Enable object names in cppgc for debug purposes.
cppgc_enable_object_names = false
} }
# Derived defaults. # Derived defaults.
...@@ -351,15 +354,19 @@ config("cppgc_base_config") { ...@@ -351,15 +354,19 @@ config("cppgc_base_config") {
# Assume is_clang = false means GCC or other compilers that are compatible # Assume is_clang = false means GCC or other compilers that are compatible
# with gas inline assembly on non-Windows builds. Cross builds for # with gas inline assembly on non-Windows builds. Cross builds for
# Linux->Windows are covered as they use clang. # Linux->Windows are covered as they use clang.
defines = []
if (is_clang || !is_win) { if (is_clang || !is_win) {
if (target_cpu == "x64" || target_cpu == "x86" || target_cpu == "arm" || if (target_cpu == "x64" || target_cpu == "x86" || target_cpu == "arm" ||
target_cpu == "arm64" || target_cpu == "ppc64" || target_cpu == "arm64" || target_cpu == "ppc64" ||
target_cpu == "s390x") { target_cpu == "s390x") {
defines = [ "CPPGC_SUPPORTS_CONSERVATIVE_STACK_SCAN" ] defines += [ "CPPGC_SUPPORTS_CONSERVATIVE_STACK_SCAN" ]
} }
} else if (is_win) { } else if (is_win) {
# Assume that non-clang builds on Windows use native tools. # Assume that non-clang builds on Windows use native tools.
defines = [ "CPPGC_SUPPORTS_CONSERVATIVE_STACK_SCAN" ] defines += [ "CPPGC_SUPPORTS_CONSERVATIVE_STACK_SCAN" ]
}
if (cppgc_enable_object_names) {
defines += [ "CPPGC_SUPPORTS_OBJECT_NAMES" ]
} }
} }
...@@ -3955,12 +3962,14 @@ v8_source_set("cppgc_base") { ...@@ -3955,12 +3962,14 @@ v8_source_set("cppgc_base") {
"include/cppgc/internal/compiler-specific.h", "include/cppgc/internal/compiler-specific.h",
"include/cppgc/internal/finalizer-traits.h", "include/cppgc/internal/finalizer-traits.h",
"include/cppgc/internal/gc-info.h", "include/cppgc/internal/gc-info.h",
"include/cppgc/internal/persistent-node.h",
"include/cppgc/internal/pointer-policies.h", "include/cppgc/internal/pointer-policies.h",
"include/cppgc/internal/prefinalizer-handler.h", "include/cppgc/internal/prefinalizer-handler.h",
"include/cppgc/liveness-broker.h", "include/cppgc/liveness-broker.h",
"include/cppgc/liveness-broker.h", "include/cppgc/liveness-broker.h",
"include/cppgc/macros.h", "include/cppgc/macros.h",
"include/cppgc/member.h", "include/cppgc/member.h",
"include/cppgc/persistent.h",
"include/cppgc/platform.h", "include/cppgc/platform.h",
"include/cppgc/prefinalizer.h", "include/cppgc/prefinalizer.h",
"include/cppgc/source-location.h", "include/cppgc/source-location.h",
...@@ -3985,6 +3994,7 @@ v8_source_set("cppgc_base") { ...@@ -3985,6 +3994,7 @@ v8_source_set("cppgc_base") {
"src/heap/cppgc/page-memory-inl.h", "src/heap/cppgc/page-memory-inl.h",
"src/heap/cppgc/page-memory.cc", "src/heap/cppgc/page-memory.cc",
"src/heap/cppgc/page-memory.h", "src/heap/cppgc/page-memory.h",
"src/heap/cppgc/persistent-node.cc",
"src/heap/cppgc/platform.cc", "src/heap/cppgc/platform.cc",
"src/heap/cppgc/pointer-policies.cc", "src/heap/cppgc/pointer-policies.cc",
"src/heap/cppgc/prefinalizer-handler.cc", "src/heap/cppgc/prefinalizer-handler.cc",
......
// 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_INTERNAL_PERSISTENT_NODE_H_
#define INCLUDE_CPPGC_INTERNAL_PERSISTENT_NODE_H_
#include <array>
#include <memory>
#include <vector>
#include "include/cppgc/internal/logging.h"
#include "include/cppgc/trace-trait.h"
#include "include/v8config.h"
namespace cppgc {
class Visitor;
namespace internal {
// PersistentNode represesents a variant of two states:
// 1) traceable node with a back pointer to the Persistent object;
// 2) freelist entry.
class PersistentNode final {
public:
PersistentNode() = default;
PersistentNode(const PersistentNode&) = delete;
PersistentNode& operator=(const PersistentNode&) = delete;
void InitializeAsUsedNode(void* owner, TraceCallback trace) {
owner_ = owner;
trace_ = trace;
}
void InitializeAsFreeNode(PersistentNode* next) {
next_ = next;
trace_ = nullptr;
}
void UpdateOwner(void* owner) {
CPPGC_DCHECK(IsUsed());
owner_ = owner;
}
PersistentNode* FreeListNext() const {
CPPGC_DCHECK(!IsUsed());
return next_;
}
void Trace(Visitor* visitor) const {
CPPGC_DCHECK(IsUsed());
trace_(visitor, owner_);
}
bool IsUsed() const { return trace_; }
private:
// PersistentNode acts as a designated union:
// If trace_ != nullptr, owner_ points to the corresponding Persistent handle.
// Otherwise, next_ points to the next freed PersistentNode.
union {
void* owner_ = nullptr;
PersistentNode* next_;
};
TraceCallback trace_ = nullptr;
};
class V8_EXPORT PersistentRegion {
using PersistentNodeSlots = std::array<PersistentNode, 256u>;
public:
PersistentRegion() = default;
PersistentRegion(const PersistentRegion&) = delete;
PersistentRegion& operator=(const PersistentRegion&) = delete;
PersistentNode* AllocateNode(void* owner, TraceCallback trace) {
if (!free_list_head_) {
EnsureNodeSlots();
}
PersistentNode* node = free_list_head_;
free_list_head_ = free_list_head_->FreeListNext();
node->InitializeAsUsedNode(owner, trace);
return node;
}
void FreeNode(PersistentNode* node) {
node->InitializeAsFreeNode(free_list_head_);
free_list_head_ = node;
}
void Trace(Visitor*);
size_t NodesInUse() const;
private:
void EnsureNodeSlots();
std::vector<std::unique_ptr<PersistentNodeSlots>> nodes_;
PersistentNode* free_list_head_ = nullptr;
};
} // namespace internal
} // namespace cppgc
#endif // INCLUDE_CPPGC_INTERNAL_PERSISTENT_NODE_H_
...@@ -6,12 +6,16 @@ ...@@ -6,12 +6,16 @@
#define INCLUDE_CPPGC_INTERNAL_POINTER_POLICIES_H_ #define INCLUDE_CPPGC_INTERNAL_POINTER_POLICIES_H_
#include <cstdint> #include <cstdint>
#include <type_traits>
#include "include/cppgc/source-location.h"
#include "include/v8config.h" #include "include/v8config.h"
namespace cppgc { namespace cppgc {
namespace internal { namespace internal {
class PersistentRegion;
// Tags to distinguish between strong and weak member types. // Tags to distinguish between strong and weak member types.
class StrongMemberTag; class StrongMemberTag;
class WeakMemberTag; class WeakMemberTag;
...@@ -52,6 +56,61 @@ using DefaultCheckingPolicy = EnabledCheckingPolicy; ...@@ -52,6 +56,61 @@ using DefaultCheckingPolicy = EnabledCheckingPolicy;
using DefaultCheckingPolicy = DisabledCheckingPolicy; using DefaultCheckingPolicy = DisabledCheckingPolicy;
#endif #endif
class KeepLocationPolicy {
public:
constexpr const SourceLocation& Location() const { return location_; }
protected:
constexpr explicit KeepLocationPolicy(const SourceLocation& location)
: location_(location) {}
// KeepLocationPolicy must not copy underlying source locations.
KeepLocationPolicy(const KeepLocationPolicy&) = delete;
KeepLocationPolicy& operator=(const KeepLocationPolicy&) = delete;
// Location of the original moved from object should be preserved.
KeepLocationPolicy(KeepLocationPolicy&&) = default;
KeepLocationPolicy& operator=(KeepLocationPolicy&&) = default;
private:
SourceLocation location_;
};
class IgnoreLocationPolicy {
public:
constexpr SourceLocation Location() const { return {}; }
protected:
constexpr explicit IgnoreLocationPolicy(const SourceLocation&) {}
};
#if CPPGC_SUPPORTS_OBJECT_NAMES
using DefaultLocationPolicy = KeepLocationPolicy;
#else
using DefaultLocationPolicy = IgnoreLocationPolicy;
#endif
struct StrongPersistentPolicy {
using IsStrongPersistent = std::true_type;
static V8_EXPORT PersistentRegion& GetPersistentRegion(void* object);
};
struct WeakPersistentPolicy {
using IsStrongPersistent = std::false_type;
static V8_EXPORT PersistentRegion& GetPersistentRegion(void* object);
};
// Persistent/Member forward declarations.
template <typename T, typename WeaknessPolicy,
typename LocationPolicy = DefaultLocationPolicy,
typename CheckingPolicy = DefaultCheckingPolicy>
class BasicPersistent;
template <typename T, typename WeaknessTag, typename WriteBarrierPolicy,
typename CheckingPolicy = DefaultCheckingPolicy>
class BasicMember;
// Special tag type used to denote some sentinel member. The semantics of the // Special tag type used to denote some sentinel member. The semantics of the
// sentinel is defined by the embedder. // sentinel is defined by the embedder.
struct SentinelPointer { struct SentinelPointer {
......
...@@ -21,13 +21,15 @@ namespace internal { ...@@ -21,13 +21,15 @@ namespace internal {
// The basic class from which all Member classes are 'generated'. // The basic class from which all Member classes are 'generated'.
template <typename T, typename WeaknessTag, typename WriteBarrierPolicy, template <typename T, typename WeaknessTag, typename WriteBarrierPolicy,
typename CheckingPolicy = DefaultCheckingPolicy> typename CheckingPolicy>
class BasicMember : private CheckingPolicy { class BasicMember : private CheckingPolicy {
public: public:
using PointeeType = T;
constexpr BasicMember() = default; constexpr BasicMember() = default;
constexpr BasicMember(std::nullptr_t) {} // NOLINT constexpr BasicMember(std::nullptr_t) {} // NOLINT
BasicMember(SentinelPointer s) : raw_(s) {} // NOLINT BasicMember(SentinelPointer s) : raw_(s) {} // NOLINT
BasicMember(T* raw) : raw_(raw) { // NOLINT BasicMember(T* raw) : raw_(raw) { // NOLINT
InitializingWriteBarrier(); InitializingWriteBarrier();
this->CheckPointer(raw_); this->CheckPointer(raw_);
} }
...@@ -41,6 +43,16 @@ class BasicMember : private CheckingPolicy { ...@@ -41,6 +43,16 @@ class BasicMember : private CheckingPolicy {
const BasicMember<U, OtherWeaknessTag, OtherBarrierPolicy, const BasicMember<U, OtherWeaknessTag, OtherBarrierPolicy,
OtherCheckingPolicy>& other) OtherCheckingPolicy>& other)
: BasicMember(other.Get()) {} : BasicMember(other.Get()) {}
// Construction from Persistent.
template <typename U, typename PersistentWeaknessPolicy,
typename PersistentLocationPolicy,
typename PersistentCheckingPolicy,
typename = std::enable_if_t<std::is_base_of<T, U>::value>>
BasicMember( // NOLINT
const BasicPersistent<U, PersistentWeaknessPolicy,
PersistentLocationPolicy, PersistentCheckingPolicy>&
p)
: BasicMember(p.Get()) {}
BasicMember& operator=(const BasicMember& other) { BasicMember& operator=(const BasicMember& other) {
return operator=(other.Get()); return operator=(other.Get());
...@@ -54,6 +66,17 @@ class BasicMember : private CheckingPolicy { ...@@ -54,6 +66,17 @@ class BasicMember : private CheckingPolicy {
OtherCheckingPolicy>& other) { OtherCheckingPolicy>& other) {
return operator=(other.Get()); return operator=(other.Get());
} }
// Assignment from Persistent.
template <typename U, typename PersistentWeaknessPolicy,
typename PersistentLocationPolicy,
typename PersistentCheckingPolicy,
typename = std::enable_if_t<std::is_base_of<T, U>::value>>
BasicMember& operator=(
const BasicPersistent<U, PersistentWeaknessPolicy,
PersistentLocationPolicy, PersistentCheckingPolicy>&
other) {
return operator=(other.Get());
}
BasicMember& operator=(T* other) { BasicMember& operator=(T* other) {
SetRawAtomic(other); SetRawAtomic(other);
AssigningWriteBarrier(); AssigningWriteBarrier();
......
This diff is collapsed.
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
#include "include/cppgc/internal/pointer-policies.h" #include "include/cppgc/internal/pointer-policies.h"
#include "include/cppgc/liveness-broker.h" #include "include/cppgc/liveness-broker.h"
#include "include/cppgc/member.h" #include "include/cppgc/member.h"
#include "include/cppgc/source-location.h"
#include "include/cppgc/trace-trait.h" #include "include/cppgc/trace-trait.h"
namespace cppgc { namespace cppgc {
...@@ -17,8 +18,6 @@ namespace internal { ...@@ -17,8 +18,6 @@ namespace internal {
class VisitorBase; class VisitorBase;
} // namespace internal } // namespace internal
class Visitor;
using WeakCallback = void (*)(const LivenessBroker&, const void*); using WeakCallback = void (*)(const LivenessBroker&, const void*);
/** /**
...@@ -50,24 +49,55 @@ class Visitor { ...@@ -50,24 +49,55 @@ class Visitor {
// TODO(chromium:1056170): DCHECK (or similar) for deleted values as they // TODO(chromium:1056170): DCHECK (or similar) for deleted values as they
// should come in at a different path. // should come in at a different path.
VisitWeak(value, TraceTrait<T>::GetTraceDescriptor(value), VisitWeak(value, TraceTrait<T>::GetTraceDescriptor(value),
&HandleWeakMember<T>, &weak_member); &HandleWeak<WeakMember<T>>, &weak_member);
}
template <typename Persistent,
std::enable_if_t<Persistent::IsStrongPersistent::value>* = nullptr>
void TraceRoot(const Persistent& p, const SourceLocation& loc) {
using PointeeType = typename Persistent::PointeeType;
static_assert(sizeof(PointeeType),
"Persistent's pointee type must be fully defined");
static_assert(internal::IsGarbageCollectedType<PointeeType>::value,
"Persisent's pointee type must be GarabgeCollected or "
"GarbageCollectedMixin");
if (!p.Get()) {
return;
}
VisitRoot(p.Get(), TraceTrait<PointeeType>::GetTraceDescriptor(p.Get()),
loc);
}
template <typename Persistent,
std::enable_if_t<!Persistent::IsStrongPersistent::value>* = nullptr>
void TraceRoot(const Persistent& p, const SourceLocation& loc) {
using PointeeType = typename Persistent::PointeeType;
static_assert(sizeof(PointeeType),
"Persistent's pointee type must be fully defined");
static_assert(internal::IsGarbageCollectedType<PointeeType>::value,
"Persisent's pointee type must be GarabgeCollected or "
"GarbageCollectedMixin");
VisitWeakRoot(&p, &HandleWeak<Persistent>);
} }
protected: protected:
virtual void Visit(const void* self, TraceDescriptor) {} virtual void Visit(const void* self, TraceDescriptor) {}
virtual void VisitWeak(const void* self, TraceDescriptor, WeakCallback, virtual void VisitWeak(const void* self, TraceDescriptor, WeakCallback,
const void* weak_member) {} const void* weak_member) {}
virtual void VisitRoot(const void*, TraceDescriptor,
const SourceLocation& loc) {}
virtual void VisitWeakRoot(const void*, WeakCallback) {}
private: private:
template <typename T> template <typename PointerType>
static void HandleWeakMember(const LivenessBroker& info, const void* object) { static void HandleWeak(const LivenessBroker& info, const void* object) {
const WeakMember<T>* weak_member = const PointerType* weak = static_cast<const PointerType*>(object);
reinterpret_cast<const WeakMember<T>*>(object); const auto* raw = weak->Get();
if (!info.IsHeapObjectAlive(*weak_member)) { if (raw && !info.IsHeapObjectAlive(raw)) {
// Object is passed down through the marker as const. Alternatives are // Object is passed down through the marker as const. Alternatives are
// - non-const Trace method; // - non-const Trace method;
// - mutable pointer in MemberBase; // - mutable pointer in MemberBase;
const_cast<WeakMember<T>*>(weak_member)->Clear(); const_cast<PointerType*>(weak)->Clear();
} }
} }
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
#include "include/cppgc/heap.h" #include "include/cppgc/heap.h"
#include "include/cppgc/internal/gc-info.h" #include "include/cppgc/internal/gc-info.h"
#include "include/cppgc/internal/persistent-node.h"
#include "include/cppgc/liveness-broker.h" #include "include/cppgc/liveness-broker.h"
#include "src/heap/cppgc/heap-object-header.h" #include "src/heap/cppgc/heap-object-header.h"
#include "src/heap/cppgc/prefinalizer-handler.h" #include "src/heap/cppgc/prefinalizer-handler.h"
...@@ -75,6 +76,19 @@ class V8_EXPORT_PRIVATE Heap final : public cppgc::Heap { ...@@ -75,6 +76,19 @@ class V8_EXPORT_PRIVATE Heap final : public cppgc::Heap {
return prefinalizer_handler_.get(); return prefinalizer_handler_.get();
} }
PersistentRegion& GetStrongPersistentRegion() {
return strong_persistent_region_;
}
const PersistentRegion& GetStrongPersistentRegion() const {
return strong_persistent_region_;
}
PersistentRegion& GetWeakPersistentRegion() {
return weak_persistent_region_;
}
const PersistentRegion& GetWeakPersistentRegion() const {
return weak_persistent_region_;
}
private: private:
// TODO(chromium:1056170): Remove as soon as arenas are available for // TODO(chromium:1056170): Remove as soon as arenas are available for
// allocation. // allocation.
...@@ -106,6 +120,9 @@ class V8_EXPORT_PRIVATE Heap final : public cppgc::Heap { ...@@ -106,6 +120,9 @@ class V8_EXPORT_PRIVATE Heap final : public cppgc::Heap {
std::vector<HeapObjectHeader*> objects_; std::vector<HeapObjectHeader*> objects_;
std::unique_ptr<PreFinalizerHandler> prefinalizer_handler_; std::unique_ptr<PreFinalizerHandler> prefinalizer_handler_;
PersistentRegion strong_persistent_region_;
PersistentRegion weak_persistent_region_;
size_t no_gc_scope_ = 0; size_t no_gc_scope_ = 0;
size_t no_allocation_scope_ = 0; size_t no_allocation_scope_ = 0;
}; };
......
// 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.
#include "include/cppgc/internal/persistent-node.h"
#include <algorithm>
#include <numeric>
namespace cppgc {
namespace internal {
size_t PersistentRegion::NodesInUse() const {
return std::accumulate(
nodes_.cbegin(), nodes_.cend(), 0u, [](size_t acc, const auto& slots) {
return acc + std::count_if(slots->cbegin(), slots->cend(),
[](const PersistentNode& node) {
return node.IsUsed();
});
});
}
void PersistentRegion::EnsureNodeSlots() {
nodes_.push_back(std::make_unique<PersistentNodeSlots>());
for (auto& node : *nodes_.back()) {
node.InitializeAsFreeNode(free_list_head_);
free_list_head_ = &node;
}
}
void PersistentRegion::Trace(Visitor* visitor) {
free_list_head_ = nullptr;
for (auto& slots : nodes_) {
bool is_empty = true;
for (auto& node : *slots) {
if (node.IsUsed()) {
node.Trace(visitor);
is_empty = false;
} else {
node.InitializeAsFreeNode(free_list_head_);
free_list_head_ = &node;
}
}
if (is_empty) {
PersistentNode* first_next = (*slots)[0].FreeListNext();
// First next was processed first in the loop above, guaranteeing that it
// either points to null or into a different node block.
CPPGC_DCHECK(!first_next || first_next < &slots->front() ||
first_next > &slots->back());
free_list_head_ = first_next;
slots.reset();
}
}
nodes_.erase(std::remove_if(nodes_.begin(), nodes_.end(),
[](const auto& ptr) { return !ptr; }),
nodes_.end());
}
} // namespace internal
} // namespace cppgc
...@@ -3,8 +3,11 @@ ...@@ -3,8 +3,11 @@
// found in the LICENSE file. // found in the LICENSE file.
#include "include/cppgc/internal/pointer-policies.h" #include "include/cppgc/internal/pointer-policies.h"
#include "include/cppgc/internal/persistent-node.h"
#include "include/cppgc/internal/accessors.h"
#include "src/base/macros.h" #include "src/base/macros.h"
#include "src/heap/cppgc/heap.h"
namespace cppgc { namespace cppgc {
namespace internal { namespace internal {
...@@ -18,5 +21,15 @@ void EnabledCheckingPolicy::CheckPointer(const void* ptr) { ...@@ -18,5 +21,15 @@ void EnabledCheckingPolicy::CheckPointer(const void* ptr) {
// TODO(chromium:1056170): Provide implementation. // TODO(chromium:1056170): Provide implementation.
} }
PersistentRegion& StrongPersistentPolicy::GetPersistentRegion(void* object) {
auto* heap = Heap::From(GetHeapFromPayload(object));
return heap->GetStrongPersistentRegion();
}
PersistentRegion& WeakPersistentPolicy::GetPersistentRegion(void* object) {
auto* heap = Heap::From(GetHeapFromPayload(object));
return heap->GetWeakPersistentRegion();
}
} // namespace internal } // namespace internal
} // namespace cppgc } // namespace cppgc
...@@ -53,6 +53,7 @@ v8_source_set("cppgc_unittests_sources") { ...@@ -53,6 +53,7 @@ v8_source_set("cppgc_unittests_sources") {
"heap/cppgc/logging_unittest.cc", "heap/cppgc/logging_unittest.cc",
"heap/cppgc/member_unittests.cc", "heap/cppgc/member_unittests.cc",
"heap/cppgc/page-memory_unittest.cc", "heap/cppgc/page-memory_unittest.cc",
"heap/cppgc/persistent_unittests.cc",
"heap/cppgc/prefinalizer_unittests.cc", "heap/cppgc/prefinalizer_unittests.cc",
"heap/cppgc/source-location_unittest.cc", "heap/cppgc/source-location_unittest.cc",
"heap/cppgc/stack_unittest.cc", "heap/cppgc/stack_unittest.cc",
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
#include "include/cppgc/allocation.h" #include "include/cppgc/allocation.h"
#include "include/cppgc/garbage-collected.h" #include "include/cppgc/garbage-collected.h"
#include "include/cppgc/member.h" #include "include/cppgc/member.h"
#include "include/cppgc/persistent.h"
#include "include/cppgc/type-traits.h" #include "include/cppgc/type-traits.h"
#include "test/unittests/heap/cppgc/tests.h" #include "test/unittests/heap/cppgc/tests.h"
...@@ -18,8 +19,12 @@ namespace internal { ...@@ -18,8 +19,12 @@ namespace internal {
namespace { namespace {
struct GCed : GarbageCollected<GCed> {}; struct GCed : GarbageCollected<GCed> {
struct DerivedGCed : GCed {}; virtual void Trace(cppgc::Visitor*) {}
};
struct DerivedGCed : GCed {
void Trace(cppgc::Visitor* v) override { GCed::Trace(v); }
};
// Compile tests. // Compile tests.
static_assert(!IsWeakV<Member<GCed>>, "Member is always strong."); static_assert(!IsWeakV<Member<GCed>>, "Member is always strong.");
...@@ -60,15 +65,15 @@ class MemberTest : public testing::TestSupportingAllocationOnly {}; ...@@ -60,15 +65,15 @@ class MemberTest : public testing::TestSupportingAllocationOnly {};
} // namespace } // namespace
template <template <typename> class Member> template <template <typename> class MemberType>
void EmptyTest() { void EmptyTest() {
{ {
Member<GCed> empty; MemberType<GCed> empty;
EXPECT_EQ(nullptr, empty.Get()); EXPECT_EQ(nullptr, empty.Get());
EXPECT_EQ(nullptr, empty.Release()); EXPECT_EQ(nullptr, empty.Release());
} }
{ {
Member<GCed> empty = nullptr; MemberType<GCed> empty = nullptr;
EXPECT_EQ(nullptr, empty.Get()); EXPECT_EQ(nullptr, empty.Get());
EXPECT_EQ(nullptr, empty.Release()); EXPECT_EQ(nullptr, empty.Release());
} }
...@@ -80,9 +85,9 @@ TEST_F(MemberTest, Empty) { ...@@ -80,9 +85,9 @@ TEST_F(MemberTest, Empty) {
EmptyTest<UntracedMember>(); EmptyTest<UntracedMember>();
} }
template <template <typename> class Member> template <template <typename> class MemberType>
void ClearTest(cppgc::Heap* heap) { void ClearTest(cppgc::Heap* heap) {
Member<GCed> member = MakeGarbageCollected<GCed>(heap); MemberType<GCed> member = MakeGarbageCollected<GCed>(heap);
EXPECT_NE(nullptr, member.Get()); EXPECT_NE(nullptr, member.Get());
member.Clear(); member.Clear();
EXPECT_EQ(nullptr, member.Get()); EXPECT_EQ(nullptr, member.Get());
...@@ -95,10 +100,10 @@ TEST_F(MemberTest, Clear) { ...@@ -95,10 +100,10 @@ TEST_F(MemberTest, Clear) {
ClearTest<UntracedMember>(heap); ClearTest<UntracedMember>(heap);
} }
template <template <typename> class Member> template <template <typename> class MemberType>
void ReleaseTest(cppgc::Heap* heap) { void ReleaseTest(cppgc::Heap* heap) {
GCed* gced = MakeGarbageCollected<GCed>(heap); GCed* gced = MakeGarbageCollected<GCed>(heap);
Member<GCed> member = gced; MemberType<GCed> member = gced;
EXPECT_NE(nullptr, member.Get()); EXPECT_NE(nullptr, member.Get());
GCed* raw = member.Release(); GCed* raw = member.Release();
EXPECT_EQ(gced, raw); EXPECT_EQ(gced, raw);
...@@ -112,12 +117,13 @@ TEST_F(MemberTest, Release) { ...@@ -112,12 +117,13 @@ TEST_F(MemberTest, Release) {
ReleaseTest<UntracedMember>(heap); ReleaseTest<UntracedMember>(heap);
} }
template <template <typename> class Member1, template <typename> class Member2> template <template <typename> class MemberType1,
template <typename> class MemberType2>
void SwapTest(cppgc::Heap* heap) { void SwapTest(cppgc::Heap* heap) {
GCed* gced1 = MakeGarbageCollected<GCed>(heap); GCed* gced1 = MakeGarbageCollected<GCed>(heap);
GCed* gced2 = MakeGarbageCollected<GCed>(heap); GCed* gced2 = MakeGarbageCollected<GCed>(heap);
Member1<GCed> member1 = gced1; MemberType1<GCed> member1 = gced1;
Member2<GCed> member2 = gced2; MemberType2<GCed> member2 = gced2;
EXPECT_EQ(gced1, member1.Get()); EXPECT_EQ(gced1, member1.Get());
EXPECT_EQ(gced2, member2.Get()); EXPECT_EQ(gced2, member2.Get());
member1.Swap(member2); member1.Swap(member2);
...@@ -138,27 +144,28 @@ TEST_F(MemberTest, Swap) { ...@@ -138,27 +144,28 @@ TEST_F(MemberTest, Swap) {
SwapTest<UntracedMember, UntracedMember>(heap); SwapTest<UntracedMember, UntracedMember>(heap);
} }
template <template <typename> class Member1, template <typename> class Member2> template <template <typename> class MemberType1,
template <typename> class MemberType2>
void HeterogeneousConversionTest(cppgc::Heap* heap) { void HeterogeneousConversionTest(cppgc::Heap* heap) {
{ {
Member1<GCed> member1 = MakeGarbageCollected<GCed>(heap); MemberType1<GCed> member1 = MakeGarbageCollected<GCed>(heap);
Member2<GCed> member2 = member1; MemberType2<GCed> member2 = member1;
EXPECT_EQ(member1.Get(), member2.Get()); EXPECT_EQ(member1.Get(), member2.Get());
} }
{ {
Member1<DerivedGCed> member1 = MakeGarbageCollected<DerivedGCed>(heap); MemberType1<DerivedGCed> member1 = MakeGarbageCollected<DerivedGCed>(heap);
Member2<GCed> member2 = member1; MemberType2<GCed> member2 = member1;
EXPECT_EQ(member1.Get(), member2.Get()); EXPECT_EQ(member1.Get(), member2.Get());
} }
{ {
Member1<GCed> member1 = MakeGarbageCollected<GCed>(heap); MemberType1<GCed> member1 = MakeGarbageCollected<GCed>(heap);
Member2<GCed> member2; MemberType2<GCed> member2;
member2 = member1; member2 = member1;
EXPECT_EQ(member1.Get(), member2.Get()); EXPECT_EQ(member1.Get(), member2.Get());
} }
{ {
Member1<DerivedGCed> member1 = MakeGarbageCollected<DerivedGCed>(heap); MemberType1<DerivedGCed> member1 = MakeGarbageCollected<DerivedGCed>(heap);
Member2<GCed> member2; MemberType2<GCed> member2;
member2 = member1; member2 = member1;
EXPECT_EQ(member1.Get(), member2.Get()); EXPECT_EQ(member1.Get(), member2.Get());
} }
...@@ -177,12 +184,52 @@ TEST_F(MemberTest, HeterogeneousInterface) { ...@@ -177,12 +184,52 @@ TEST_F(MemberTest, HeterogeneousInterface) {
HeterogeneousConversionTest<UntracedMember, UntracedMember>(heap); HeterogeneousConversionTest<UntracedMember, UntracedMember>(heap);
} }
template <template <typename> class Member1, template <typename> class Member2> template <template <typename> class MemberType,
template <typename> class PersistentType>
void PersistentConversionTest(cppgc::Heap* heap) {
{
PersistentType<GCed> persistent = MakeGarbageCollected<GCed>(heap);
MemberType<GCed> member = persistent;
EXPECT_EQ(persistent.Get(), member.Get());
}
{
PersistentType<DerivedGCed> persistent =
MakeGarbageCollected<DerivedGCed>(heap);
MemberType<GCed> member = persistent;
EXPECT_EQ(persistent.Get(), member.Get());
}
{
PersistentType<GCed> persistent = MakeGarbageCollected<GCed>(heap);
MemberType<GCed> member;
member = persistent;
EXPECT_EQ(persistent.Get(), member.Get());
}
{
PersistentType<DerivedGCed> persistent =
MakeGarbageCollected<DerivedGCed>(heap);
MemberType<GCed> member;
member = persistent;
EXPECT_EQ(persistent.Get(), member.Get());
}
}
TEST_F(MemberTest, PersistentConversion) {
cppgc::Heap* heap = GetHeap();
PersistentConversionTest<Member, Persistent>(heap);
PersistentConversionTest<Member, WeakPersistent>(heap);
PersistentConversionTest<WeakMember, Persistent>(heap);
PersistentConversionTest<WeakMember, WeakPersistent>(heap);
PersistentConversionTest<UntracedMember, Persistent>(heap);
PersistentConversionTest<UntracedMember, WeakPersistent>(heap);
}
template <template <typename> class MemberType1,
template <typename> class MemberType2>
void EqualityTest(cppgc::Heap* heap) { void EqualityTest(cppgc::Heap* heap) {
{ {
GCed* gced = MakeGarbageCollected<GCed>(heap); GCed* gced = MakeGarbageCollected<GCed>(heap);
Member1<GCed> member1 = gced; MemberType1<GCed> member1 = gced;
Member2<GCed> member2 = gced; MemberType2<GCed> member2 = gced;
EXPECT_TRUE(member1 == member2); EXPECT_TRUE(member1 == member2);
EXPECT_FALSE(member1 != member2); EXPECT_FALSE(member1 != member2);
member2 = member1; member2 = member1;
...@@ -190,8 +237,8 @@ void EqualityTest(cppgc::Heap* heap) { ...@@ -190,8 +237,8 @@ void EqualityTest(cppgc::Heap* heap) {
EXPECT_FALSE(member1 != member2); EXPECT_FALSE(member1 != member2);
} }
{ {
Member1<GCed> member1 = MakeGarbageCollected<GCed>(heap); MemberType1<GCed> member1 = MakeGarbageCollected<GCed>(heap);
Member2<GCed> member2 = MakeGarbageCollected<GCed>(heap); MemberType2<GCed> member2 = MakeGarbageCollected<GCed>(heap);
EXPECT_TRUE(member1 != member2); EXPECT_TRUE(member1 != member2);
EXPECT_FALSE(member1 == member2); EXPECT_FALSE(member1 == member2);
} }
...@@ -229,6 +276,7 @@ TEST_F(MemberTest, WriteBarrierTriggered) { ...@@ -229,6 +276,7 @@ TEST_F(MemberTest, WriteBarrierTriggered) {
EXPECT_EQ(1u, CustomWriteBarrierPolicy::AssigningWriteBarriersTriggered); EXPECT_EQ(1u, CustomWriteBarrierPolicy::AssigningWriteBarriersTriggered);
member2 = kSentinelPointer; member2 = kSentinelPointer;
EXPECT_EQ(kSentinelPointer, member2.Get()); EXPECT_EQ(kSentinelPointer, member2.Get());
EXPECT_EQ(kSentinelPointer, member2);
// No initializing barriers for pointer sentinel. // No initializing barriers for pointer sentinel.
EXPECT_EQ(1u, CustomWriteBarrierPolicy::InitializingWriteBarriersTriggered); EXPECT_EQ(1u, CustomWriteBarrierPolicy::InitializingWriteBarriersTriggered);
EXPECT_EQ(1u, CustomWriteBarrierPolicy::AssigningWriteBarriersTriggered); EXPECT_EQ(1u, CustomWriteBarrierPolicy::AssigningWriteBarriersTriggered);
......
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment