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() {
# Enable control-flow integrity features, such as pointer authentication for
# ARM64.
v8_control_flow_integrity = false
# Enable object names in cppgc for debug purposes.
cppgc_enable_object_names = false
}
# Derived defaults.
......@@ -351,15 +354,19 @@ config("cppgc_base_config") {
# Assume is_clang = false means GCC or other compilers that are compatible
# with gas inline assembly on non-Windows builds. Cross builds for
# Linux->Windows are covered as they use clang.
defines = []
if (is_clang || !is_win) {
if (target_cpu == "x64" || target_cpu == "x86" || target_cpu == "arm" ||
target_cpu == "arm64" || target_cpu == "ppc64" ||
target_cpu == "s390x") {
defines = [ "CPPGC_SUPPORTS_CONSERVATIVE_STACK_SCAN" ]
defines += [ "CPPGC_SUPPORTS_CONSERVATIVE_STACK_SCAN" ]
}
} else if (is_win) {
# 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") {
"include/cppgc/internal/compiler-specific.h",
"include/cppgc/internal/finalizer-traits.h",
"include/cppgc/internal/gc-info.h",
"include/cppgc/internal/persistent-node.h",
"include/cppgc/internal/pointer-policies.h",
"include/cppgc/internal/prefinalizer-handler.h",
"include/cppgc/liveness-broker.h",
"include/cppgc/liveness-broker.h",
"include/cppgc/macros.h",
"include/cppgc/member.h",
"include/cppgc/persistent.h",
"include/cppgc/platform.h",
"include/cppgc/prefinalizer.h",
"include/cppgc/source-location.h",
......@@ -3985,6 +3994,7 @@ v8_source_set("cppgc_base") {
"src/heap/cppgc/page-memory-inl.h",
"src/heap/cppgc/page-memory.cc",
"src/heap/cppgc/page-memory.h",
"src/heap/cppgc/persistent-node.cc",
"src/heap/cppgc/platform.cc",
"src/heap/cppgc/pointer-policies.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 @@
#define INCLUDE_CPPGC_INTERNAL_POINTER_POLICIES_H_
#include <cstdint>
#include <type_traits>
#include "include/cppgc/source-location.h"
#include "include/v8config.h"
namespace cppgc {
namespace internal {
class PersistentRegion;
// Tags to distinguish between strong and weak member types.
class StrongMemberTag;
class WeakMemberTag;
......@@ -52,6 +56,61 @@ using DefaultCheckingPolicy = EnabledCheckingPolicy;
using DefaultCheckingPolicy = DisabledCheckingPolicy;
#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
// sentinel is defined by the embedder.
struct SentinelPointer {
......
......@@ -21,13 +21,15 @@ namespace internal {
// The basic class from which all Member classes are 'generated'.
template <typename T, typename WeaknessTag, typename WriteBarrierPolicy,
typename CheckingPolicy = DefaultCheckingPolicy>
typename CheckingPolicy>
class BasicMember : private CheckingPolicy {
public:
using PointeeType = T;
constexpr BasicMember() = default;
constexpr BasicMember(std::nullptr_t) {} // NOLINT
constexpr BasicMember(std::nullptr_t) {} // NOLINT
BasicMember(SentinelPointer s) : raw_(s) {} // NOLINT
BasicMember(T* raw) : raw_(raw) { // NOLINT
BasicMember(T* raw) : raw_(raw) { // NOLINT
InitializingWriteBarrier();
this->CheckPointer(raw_);
}
......@@ -41,6 +43,16 @@ class BasicMember : private CheckingPolicy {
const BasicMember<U, OtherWeaknessTag, OtherBarrierPolicy,
OtherCheckingPolicy>& other)
: 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) {
return operator=(other.Get());
......@@ -54,6 +66,17 @@ class BasicMember : private CheckingPolicy {
OtherCheckingPolicy>& other) {
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) {
SetRawAtomic(other);
AssigningWriteBarrier();
......
This diff is collapsed.
......@@ -10,6 +10,7 @@
#include "include/cppgc/internal/pointer-policies.h"
#include "include/cppgc/liveness-broker.h"
#include "include/cppgc/member.h"
#include "include/cppgc/source-location.h"
#include "include/cppgc/trace-trait.h"
namespace cppgc {
......@@ -17,8 +18,6 @@ namespace internal {
class VisitorBase;
} // namespace internal
class Visitor;
using WeakCallback = void (*)(const LivenessBroker&, const void*);
/**
......@@ -50,24 +49,55 @@ class Visitor {
// TODO(chromium:1056170): DCHECK (or similar) for deleted values as they
// should come in at a different path.
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:
virtual void Visit(const void* self, TraceDescriptor) {}
virtual void VisitWeak(const void* self, TraceDescriptor, WeakCallback,
const void* weak_member) {}
virtual void VisitRoot(const void*, TraceDescriptor,
const SourceLocation& loc) {}
virtual void VisitWeakRoot(const void*, WeakCallback) {}
private:
template <typename T>
static void HandleWeakMember(const LivenessBroker& info, const void* object) {
const WeakMember<T>* weak_member =
reinterpret_cast<const WeakMember<T>*>(object);
if (!info.IsHeapObjectAlive(*weak_member)) {
template <typename PointerType>
static void HandleWeak(const LivenessBroker& info, const void* object) {
const PointerType* weak = static_cast<const PointerType*>(object);
const auto* raw = weak->Get();
if (raw && !info.IsHeapObjectAlive(raw)) {
// Object is passed down through the marker as const. Alternatives are
// - non-const Trace method;
// - mutable pointer in MemberBase;
const_cast<WeakMember<T>*>(weak_member)->Clear();
const_cast<PointerType*>(weak)->Clear();
}
}
......
......@@ -10,6 +10,7 @@
#include "include/cppgc/heap.h"
#include "include/cppgc/internal/gc-info.h"
#include "include/cppgc/internal/persistent-node.h"
#include "include/cppgc/liveness-broker.h"
#include "src/heap/cppgc/heap-object-header.h"
#include "src/heap/cppgc/prefinalizer-handler.h"
......@@ -75,6 +76,19 @@ class V8_EXPORT_PRIVATE Heap final : public cppgc::Heap {
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:
// TODO(chromium:1056170): Remove as soon as arenas are available for
// allocation.
......@@ -106,6 +120,9 @@ class V8_EXPORT_PRIVATE Heap final : public cppgc::Heap {
std::vector<HeapObjectHeader*> objects_;
std::unique_ptr<PreFinalizerHandler> prefinalizer_handler_;
PersistentRegion strong_persistent_region_;
PersistentRegion weak_persistent_region_;
size_t no_gc_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 @@
// found in the LICENSE file.
#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/heap/cppgc/heap.h"
namespace cppgc {
namespace internal {
......@@ -18,5 +21,15 @@ void EnabledCheckingPolicy::CheckPointer(const void* ptr) {
// 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 cppgc
......@@ -53,6 +53,7 @@ v8_source_set("cppgc_unittests_sources") {
"heap/cppgc/logging_unittest.cc",
"heap/cppgc/member_unittests.cc",
"heap/cppgc/page-memory_unittest.cc",
"heap/cppgc/persistent_unittests.cc",
"heap/cppgc/prefinalizer_unittests.cc",
"heap/cppgc/source-location_unittest.cc",
"heap/cppgc/stack_unittest.cc",
......
......@@ -8,6 +8,7 @@
#include "include/cppgc/allocation.h"
#include "include/cppgc/garbage-collected.h"
#include "include/cppgc/member.h"
#include "include/cppgc/persistent.h"
#include "include/cppgc/type-traits.h"
#include "test/unittests/heap/cppgc/tests.h"
......@@ -18,8 +19,12 @@ namespace internal {
namespace {
struct GCed : GarbageCollected<GCed> {};
struct DerivedGCed : GCed {};
struct GCed : GarbageCollected<GCed> {
virtual void Trace(cppgc::Visitor*) {}
};
struct DerivedGCed : GCed {
void Trace(cppgc::Visitor* v) override { GCed::Trace(v); }
};
// Compile tests.
static_assert(!IsWeakV<Member<GCed>>, "Member is always strong.");
......@@ -60,15 +65,15 @@ class MemberTest : public testing::TestSupportingAllocationOnly {};
} // namespace
template <template <typename> class Member>
template <template <typename> class MemberType>
void EmptyTest() {
{
Member<GCed> empty;
MemberType<GCed> empty;
EXPECT_EQ(nullptr, empty.Get());
EXPECT_EQ(nullptr, empty.Release());
}
{
Member<GCed> empty = nullptr;
MemberType<GCed> empty = nullptr;
EXPECT_EQ(nullptr, empty.Get());
EXPECT_EQ(nullptr, empty.Release());
}
......@@ -80,9 +85,9 @@ TEST_F(MemberTest, Empty) {
EmptyTest<UntracedMember>();
}
template <template <typename> class Member>
template <template <typename> class MemberType>
void ClearTest(cppgc::Heap* heap) {
Member<GCed> member = MakeGarbageCollected<GCed>(heap);
MemberType<GCed> member = MakeGarbageCollected<GCed>(heap);
EXPECT_NE(nullptr, member.Get());
member.Clear();
EXPECT_EQ(nullptr, member.Get());
......@@ -95,10 +100,10 @@ TEST_F(MemberTest, Clear) {
ClearTest<UntracedMember>(heap);
}
template <template <typename> class Member>
template <template <typename> class MemberType>
void ReleaseTest(cppgc::Heap* heap) {
GCed* gced = MakeGarbageCollected<GCed>(heap);
Member<GCed> member = gced;
MemberType<GCed> member = gced;
EXPECT_NE(nullptr, member.Get());
GCed* raw = member.Release();
EXPECT_EQ(gced, raw);
......@@ -112,12 +117,13 @@ TEST_F(MemberTest, Release) {
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) {
GCed* gced1 = MakeGarbageCollected<GCed>(heap);
GCed* gced2 = MakeGarbageCollected<GCed>(heap);
Member1<GCed> member1 = gced1;
Member2<GCed> member2 = gced2;
MemberType1<GCed> member1 = gced1;
MemberType2<GCed> member2 = gced2;
EXPECT_EQ(gced1, member1.Get());
EXPECT_EQ(gced2, member2.Get());
member1.Swap(member2);
......@@ -138,27 +144,28 @@ TEST_F(MemberTest, Swap) {
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) {
{
Member1<GCed> member1 = MakeGarbageCollected<GCed>(heap);
Member2<GCed> member2 = member1;
MemberType1<GCed> member1 = MakeGarbageCollected<GCed>(heap);
MemberType2<GCed> member2 = member1;
EXPECT_EQ(member1.Get(), member2.Get());
}
{
Member1<DerivedGCed> member1 = MakeGarbageCollected<DerivedGCed>(heap);
Member2<GCed> member2 = member1;
MemberType1<DerivedGCed> member1 = MakeGarbageCollected<DerivedGCed>(heap);
MemberType2<GCed> member2 = member1;
EXPECT_EQ(member1.Get(), member2.Get());
}
{
Member1<GCed> member1 = MakeGarbageCollected<GCed>(heap);
Member2<GCed> member2;
MemberType1<GCed> member1 = MakeGarbageCollected<GCed>(heap);
MemberType2<GCed> member2;
member2 = member1;
EXPECT_EQ(member1.Get(), member2.Get());
}
{
Member1<DerivedGCed> member1 = MakeGarbageCollected<DerivedGCed>(heap);
Member2<GCed> member2;
MemberType1<DerivedGCed> member1 = MakeGarbageCollected<DerivedGCed>(heap);
MemberType2<GCed> member2;
member2 = member1;
EXPECT_EQ(member1.Get(), member2.Get());
}
......@@ -177,12 +184,52 @@ TEST_F(MemberTest, HeterogeneousInterface) {
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) {
{
GCed* gced = MakeGarbageCollected<GCed>(heap);
Member1<GCed> member1 = gced;
Member2<GCed> member2 = gced;
MemberType1<GCed> member1 = gced;
MemberType2<GCed> member2 = gced;
EXPECT_TRUE(member1 == member2);
EXPECT_FALSE(member1 != member2);
member2 = member1;
......@@ -190,8 +237,8 @@ void EqualityTest(cppgc::Heap* heap) {
EXPECT_FALSE(member1 != member2);
}
{
Member1<GCed> member1 = MakeGarbageCollected<GCed>(heap);
Member2<GCed> member2 = MakeGarbageCollected<GCed>(heap);
MemberType1<GCed> member1 = MakeGarbageCollected<GCed>(heap);
MemberType2<GCed> member2 = MakeGarbageCollected<GCed>(heap);
EXPECT_TRUE(member1 != member2);
EXPECT_FALSE(member1 == member2);
}
......@@ -229,6 +276,7 @@ TEST_F(MemberTest, WriteBarrierTriggered) {
EXPECT_EQ(1u, CustomWriteBarrierPolicy::AssigningWriteBarriersTriggered);
member2 = kSentinelPointer;
EXPECT_EQ(kSentinelPointer, member2.Get());
EXPECT_EQ(kSentinelPointer, member2);
// No initializing barriers for pointer sentinel.
EXPECT_EQ(1u, CustomWriteBarrierPolicy::InitializingWriteBarriersTriggered);
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