cppgc: Port Member
This CL introduces - Member - WeakMember - UntracedMember interfaces. Remaining work is to add pointer verifier and write barrier implementation. Bug: chromium:1056170 Change-Id: Iddb8e4d002db0b1d1652f2946ddfa08a98a889c7 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2124323 Commit-Queue: Anton Bikineev <bikineev@chromium.org> Reviewed-by: Michael Lippautz <mlippautz@chromium.org> Reviewed-by: Ulan Degenbaev <ulan@chromium.org> Reviewed-by: Omer Katz <omerkatz@chromium.org> Cr-Commit-Position: refs/heads/master@{#66927}
This commit is contained in:
parent
04a7a680a2
commit
d8936aac8f
3
BUILD.gn
3
BUILD.gn
@ -3933,7 +3933,9 @@ v8_source_set("cppgc_base") {
|
||||
"include/cppgc/garbage-collected.h",
|
||||
"include/cppgc/gc-info.h",
|
||||
"include/cppgc/heap.h",
|
||||
"include/cppgc/member.h",
|
||||
"include/cppgc/platform.h",
|
||||
"include/cppgc/type_traits.h",
|
||||
"include/v8config.h",
|
||||
"src/heap/cppgc/allocation.cc",
|
||||
"src/heap/cppgc/gc-info-table.cc",
|
||||
@ -3945,6 +3947,7 @@ v8_source_set("cppgc_base") {
|
||||
"src/heap/cppgc/heap-object-header.h",
|
||||
"src/heap/cppgc/heap.cc",
|
||||
"src/heap/cppgc/heap.h",
|
||||
"src/heap/cppgc/member.cc",
|
||||
"src/heap/cppgc/platform.cc",
|
||||
"src/heap/cppgc/sanitizers.h",
|
||||
"src/heap/cppgc/stack.cc",
|
||||
|
216
include/cppgc/member.h
Normal file
216
include/cppgc/member.h
Normal file
@ -0,0 +1,216 @@
|
||||
// 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 "include/cppgc/garbage-collected.h"
|
||||
#include "include/v8config.h"
|
||||
|
||||
namespace cppgc {
|
||||
|
||||
namespace internal {
|
||||
|
||||
struct DijkstraWriteBarrierPolicy {
|
||||
static void InitializingBarrier(const void*, const void*) {
|
||||
// Since in initializing writes the source object is always white, having no
|
||||
// barrier doesn't break the tri-color invariant.
|
||||
}
|
||||
static void AssigningBarrier(const void*, const void*) {
|
||||
// TODO(chromium:1056170): Add actual implementation.
|
||||
}
|
||||
};
|
||||
|
||||
struct NoWriteBarrierPolicy {
|
||||
static void InitializingBarrier(const void*, const void*) {}
|
||||
static void AssigningBarrier(const void*, const void*) {}
|
||||
};
|
||||
|
||||
class V8_EXPORT EnabledCheckingPolicy {
|
||||
public:
|
||||
EnabledCheckingPolicy();
|
||||
void CheckPointer(const void* ptr);
|
||||
|
||||
private:
|
||||
void* impl_;
|
||||
};
|
||||
|
||||
class DisabledCheckingPolicy {
|
||||
public:
|
||||
void CheckPointer(const void* raw) {}
|
||||
};
|
||||
|
||||
#if V8_ENABLE_CHECKS
|
||||
using DefaultCheckingPolicy = EnabledCheckingPolicy;
|
||||
#else
|
||||
using DefaultCheckingPolicy = DisabledCheckingPolicy;
|
||||
#endif
|
||||
|
||||
// Special tag type used to denote some sentinel member. The semantics of the
|
||||
// sentinel is defined by the embedder.
|
||||
struct MemberSentinel {};
|
||||
constexpr MemberSentinel kMemberSentinel;
|
||||
|
||||
// The basic class from which all Member classes are 'generated'.
|
||||
template <typename T, class WeaknessTag, class WriteBarrierPolicy,
|
||||
class CheckingPolicy = DefaultCheckingPolicy>
|
||||
class BasicMember : private CheckingPolicy {
|
||||
public:
|
||||
constexpr BasicMember() = default;
|
||||
constexpr BasicMember(std::nullptr_t) {} // NOLINT
|
||||
constexpr BasicMember(MemberSentinel) // NOLINT
|
||||
: raw_(reinterpret_cast<T*>(kSentinelValue)) {}
|
||||
BasicMember(T* raw) : raw_(raw) { // NOLINT
|
||||
InitializingWriteBarrier();
|
||||
this->CheckPointer(raw_);
|
||||
}
|
||||
// TODO(chromium:1056170): Unfortunately, this overload is used ubiquitously
|
||||
// in Blink. Reeavalute the possibility to remove it.
|
||||
BasicMember(T& raw) : BasicMember(&raw) {} // NOLINT
|
||||
BasicMember(const BasicMember& other) : BasicMember(other.Get()) {}
|
||||
// Allow heterogeneous construction.
|
||||
template <typename U, typename OtherBarrierPolicy, typename OtherWeaknessTag,
|
||||
typename OtherCheckingPolicy>
|
||||
BasicMember(const BasicMember<U, OtherWeaknessTag, OtherBarrierPolicy,
|
||||
OtherCheckingPolicy>& other)
|
||||
: BasicMember(other.Get()) {}
|
||||
|
||||
BasicMember& operator=(const BasicMember& other) {
|
||||
return operator=(other.Get());
|
||||
}
|
||||
// Allow heterogeneous assignment.
|
||||
template <typename U, typename OtherWeaknessTag, typename OtherBarrierPolicy,
|
||||
typename OtherCheckingPolicy>
|
||||
BasicMember& operator=(
|
||||
const BasicMember<U, OtherWeaknessTag, OtherBarrierPolicy,
|
||||
OtherCheckingPolicy>& other) {
|
||||
return operator=(other.Get());
|
||||
}
|
||||
BasicMember& operator=(T* other) {
|
||||
SetRawAtomic(other);
|
||||
AssigningWriteBarrier();
|
||||
this->CheckPointer(Get());
|
||||
return *this;
|
||||
}
|
||||
BasicMember& operator=(std::nullptr_t) {
|
||||
Clear();
|
||||
return *this;
|
||||
}
|
||||
BasicMember& operator=(MemberSentinel) {
|
||||
SetRawAtomic(reinterpret_cast<T*>(kSentinelValue));
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename U, typename OtherWeaknessTag, typename OtherBarrierPolicy,
|
||||
typename OtherCheckingPolicy>
|
||||
void Swap(BasicMember<U, OtherWeaknessTag, OtherBarrierPolicy,
|
||||
OtherCheckingPolicy>& other) {
|
||||
T* tmp = Get();
|
||||
*this = other;
|
||||
other = tmp;
|
||||
}
|
||||
|
||||
explicit operator bool() const { return Get(); }
|
||||
operator T*() const { return Get(); }
|
||||
T* operator->() const { return Get(); }
|
||||
T& operator*() const { return *Get(); }
|
||||
|
||||
T* Get() const {
|
||||
// Executed by the mutator, hence non atomic load.
|
||||
return raw_;
|
||||
}
|
||||
|
||||
void Clear() { SetRawAtomic(nullptr); }
|
||||
|
||||
T* Release() {
|
||||
T* result = Get();
|
||||
Clear();
|
||||
return result;
|
||||
}
|
||||
|
||||
private:
|
||||
// Must not be odr-used.
|
||||
static constexpr intptr_t kSentinelValue = -1;
|
||||
|
||||
void SetRawAtomic(T* raw) {
|
||||
reinterpret_cast<std::atomic<T*>*>(&raw_)->store(raw,
|
||||
std::memory_order_relaxed);
|
||||
}
|
||||
T* GetRawAtomic() const {
|
||||
return reinterpret_cast<const std::atomic<T*>*>(&raw_)->load(
|
||||
std::memory_order_relaxed);
|
||||
}
|
||||
|
||||
void InitializingWriteBarrier() const {
|
||||
WriteBarrierPolicy::InitializingBarrier(
|
||||
reinterpret_cast<const void*>(&raw_), static_cast<const void*>(raw_));
|
||||
}
|
||||
void AssigningWriteBarrier() const {
|
||||
WriteBarrierPolicy::AssigningBarrier(reinterpret_cast<const void*>(&raw_),
|
||||
static_cast<const void*>(raw_));
|
||||
}
|
||||
|
||||
T* raw_ = nullptr;
|
||||
};
|
||||
|
||||
template <typename T1, typename WeaknessTag1, typename WriteBarrierPolicy1,
|
||||
typename CheckingPolicy1, typename T2, typename WeaknessTag2,
|
||||
typename WriteBarrierPolicy2, typename CheckingPolicy2>
|
||||
bool operator==(
|
||||
BasicMember<T1, WeaknessTag1, WriteBarrierPolicy1, CheckingPolicy1> member1,
|
||||
BasicMember<T2, WeaknessTag2, WriteBarrierPolicy2, CheckingPolicy2>
|
||||
member2) {
|
||||
return member1.Get() == member2.Get();
|
||||
}
|
||||
|
||||
template <typename T1, typename WeaknessTag1, typename WriteBarrierPolicy1,
|
||||
typename CheckingPolicy1, typename T2, typename WeaknessTag2,
|
||||
typename WriteBarrierPolicy2, typename CheckingPolicy2>
|
||||
bool operator!=(
|
||||
BasicMember<T1, WeaknessTag1, WriteBarrierPolicy1, CheckingPolicy1> member1,
|
||||
BasicMember<T2, WeaknessTag2, WriteBarrierPolicy2, CheckingPolicy2>
|
||||
member2) {
|
||||
return !(member1 == member2);
|
||||
}
|
||||
|
||||
template <typename T, typename WriteBarrierPolicy>
|
||||
using BasicStrongMember =
|
||||
BasicMember<T, class StrongMemberTag, WriteBarrierPolicy>;
|
||||
|
||||
template <typename T, typename WriteBarrierPolicy>
|
||||
using BasicWeakMember = BasicMember<T, class WeakMemberTag, WriteBarrierPolicy>;
|
||||
|
||||
} // 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::BasicStrongMember<T, internal::DijkstraWriteBarrierPolicy>;
|
||||
|
||||
// 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::BasicWeakMember<T, internal::DijkstraWriteBarrierPolicy>;
|
||||
|
||||
// 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, class UntracedMemberTag,
|
||||
internal::NoWriteBarrierPolicy>;
|
||||
|
||||
} // namespace cppgc
|
||||
|
||||
#endif // INCLUDE_CPPGC_MEMBER_H_
|
31
include/cppgc/type_traits.h
Normal file
31
include/cppgc/type_traits.h
Normal file
@ -0,0 +1,31 @@
|
||||
// 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_TYPE_TRAITS_H_
|
||||
#define INCLUDE_CPPGC_TYPE_TRAITS_H_
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
#include "include/cppgc/member.h"
|
||||
|
||||
namespace cppgc {
|
||||
|
||||
namespace internal {
|
||||
|
||||
// Not supposed to be specialized by the user.
|
||||
template <typename T>
|
||||
struct IsWeak : std::false_type {};
|
||||
|
||||
template <typename T, typename WriteBarrierPolicy>
|
||||
struct IsWeak<internal::BasicWeakMember<T, WriteBarrierPolicy>>
|
||||
: std::true_type {};
|
||||
|
||||
} // namespace internal
|
||||
|
||||
template <typename T>
|
||||
constexpr bool IsWeakV = internal::IsWeak<T>::value;
|
||||
|
||||
} // namespace cppgc
|
||||
|
||||
#endif // INCLUDE_CPPGC_TYPE_TRAITS_H_
|
22
src/heap/cppgc/member.cc
Normal file
22
src/heap/cppgc/member.cc
Normal file
@ -0,0 +1,22 @@
|
||||
// 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/member.h"
|
||||
|
||||
#include "src/base/macros.h"
|
||||
|
||||
namespace cppgc {
|
||||
namespace internal {
|
||||
|
||||
EnabledCheckingPolicy::EnabledCheckingPolicy() {
|
||||
USE(impl_);
|
||||
// TODO(chromium:1056170): Save creating heap state.
|
||||
}
|
||||
|
||||
void EnabledCheckingPolicy::CheckPointer(const void* ptr) {
|
||||
// TODO(chromium:1056170): Provide implementation.
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace cppgc
|
@ -49,6 +49,7 @@ v8_source_set("cppgc_unittests_sources") {
|
||||
"heap/cppgc/garbage-collected_unittest.cc",
|
||||
"heap/cppgc/gc-info_unittest.cc",
|
||||
"heap/cppgc/heap-object-header_unittest.cc",
|
||||
"heap/cppgc/member_unittests.cc",
|
||||
"heap/cppgc/stack_unittest.cc",
|
||||
"heap/cppgc/tests.cc",
|
||||
"heap/cppgc/tests.h",
|
||||
|
240
test/unittests/heap/cppgc/member_unittests.cc
Normal file
240
test/unittests/heap/cppgc/member_unittests.cc
Normal file
@ -0,0 +1,240 @@
|
||||
// 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 <array>
|
||||
|
||||
#include "include/cppgc/member.h"
|
||||
#include "include/cppgc/type_traits.h"
|
||||
|
||||
#include "testing/gtest/include/gtest/gtest.h"
|
||||
|
||||
namespace cppgc {
|
||||
namespace internal {
|
||||
|
||||
struct GCed : GarbageCollected<GCed> {};
|
||||
struct DerivedGCed : GCed {};
|
||||
|
||||
// Compile tests.
|
||||
static_assert(!IsWeakV<Member<GCed>>, "Member is always strong.");
|
||||
static_assert(IsWeakV<WeakMember<GCed>>, "WeakMember is always weak.");
|
||||
|
||||
struct CustomWriteBarrierPolicy {
|
||||
static size_t InitializingWriteBarriersTriggered;
|
||||
static size_t AssigningWriteBarriersTriggered;
|
||||
static void InitializingBarrier(const void* slot, const void* value) {
|
||||
++InitializingWriteBarriersTriggered;
|
||||
}
|
||||
static void AssigningBarrier(const void* slot, const void* value) {
|
||||
++AssigningWriteBarriersTriggered;
|
||||
}
|
||||
};
|
||||
size_t CustomWriteBarrierPolicy::InitializingWriteBarriersTriggered = 0;
|
||||
size_t CustomWriteBarrierPolicy::AssigningWriteBarriersTriggered = 0;
|
||||
|
||||
using MemberWithCustomBarrier =
|
||||
BasicStrongMember<GCed, CustomWriteBarrierPolicy>;
|
||||
|
||||
struct CustomCheckingPolicy {
|
||||
static std::array<GCed, 10> Array;
|
||||
static size_t ChecksTriggered;
|
||||
void CheckPointer(const void* ptr) {
|
||||
EXPECT_LE(Array.data(), ptr);
|
||||
EXPECT_GT(Array.data() + Array.size(), ptr);
|
||||
++ChecksTriggered;
|
||||
}
|
||||
};
|
||||
std::array<GCed, 10> CustomCheckingPolicy::Array;
|
||||
size_t CustomCheckingPolicy::ChecksTriggered = 0;
|
||||
|
||||
using MemberWithCustomChecking =
|
||||
internal::BasicMember<GCed, class StrongMemberTag,
|
||||
DijkstraWriteBarrierPolicy, CustomCheckingPolicy>;
|
||||
|
||||
template <template <typename> class Member>
|
||||
void EmptyTest() {
|
||||
{
|
||||
Member<GCed> empty;
|
||||
EXPECT_EQ(nullptr, empty.Get());
|
||||
EXPECT_EQ(nullptr, empty.Release());
|
||||
}
|
||||
{
|
||||
Member<GCed> empty = nullptr;
|
||||
EXPECT_EQ(nullptr, empty.Get());
|
||||
EXPECT_EQ(nullptr, empty.Release());
|
||||
}
|
||||
}
|
||||
|
||||
TEST(MemberTest, Empty) {
|
||||
EmptyTest<Member>();
|
||||
EmptyTest<WeakMember>();
|
||||
EmptyTest<UntracedMember>();
|
||||
}
|
||||
|
||||
template <template <typename> class Member>
|
||||
void ClearTest() {
|
||||
GCed gced;
|
||||
Member<GCed> member = &gced;
|
||||
EXPECT_NE(nullptr, member.Get());
|
||||
member.Clear();
|
||||
EXPECT_EQ(nullptr, member.Get());
|
||||
}
|
||||
|
||||
TEST(MemberTest, Clear) {
|
||||
ClearTest<Member>();
|
||||
ClearTest<WeakMember>();
|
||||
ClearTest<UntracedMember>();
|
||||
}
|
||||
|
||||
template <template <typename> class Member>
|
||||
void ReleaseTest() {
|
||||
GCed gced;
|
||||
Member<GCed> member = &gced;
|
||||
EXPECT_NE(nullptr, member.Get());
|
||||
GCed* raw = member.Release();
|
||||
EXPECT_EQ(&gced, raw);
|
||||
EXPECT_EQ(nullptr, member.Get());
|
||||
}
|
||||
|
||||
TEST(MemberTest, Release) {
|
||||
ReleaseTest<Member>();
|
||||
ReleaseTest<WeakMember>();
|
||||
ReleaseTest<UntracedMember>();
|
||||
}
|
||||
|
||||
template <template <typename> class Member1, template <typename> class Member2>
|
||||
void SwapTest() {
|
||||
GCed gced1, gced2;
|
||||
Member1<GCed> member1 = &gced1;
|
||||
Member2<GCed> member2 = &gced2;
|
||||
EXPECT_EQ(&gced1, member1.Get());
|
||||
EXPECT_EQ(&gced2, member2.Get());
|
||||
member1.Swap(member2);
|
||||
EXPECT_EQ(&gced2, member1.Get());
|
||||
EXPECT_EQ(&gced1, member2.Get());
|
||||
}
|
||||
|
||||
TEST(MemberTest, Swap) {
|
||||
SwapTest<Member, Member>();
|
||||
SwapTest<Member, WeakMember>();
|
||||
SwapTest<Member, UntracedMember>();
|
||||
SwapTest<WeakMember, Member>();
|
||||
SwapTest<WeakMember, WeakMember>();
|
||||
SwapTest<WeakMember, UntracedMember>();
|
||||
SwapTest<UntracedMember, Member>();
|
||||
SwapTest<UntracedMember, WeakMember>();
|
||||
SwapTest<UntracedMember, UntracedMember>();
|
||||
}
|
||||
|
||||
template <template <typename> class Member1, template <typename> class Member2>
|
||||
void HeterogeneousConversionTest() {
|
||||
{
|
||||
GCed gced;
|
||||
Member1<GCed> member1 = &gced;
|
||||
Member2<GCed> member2 = member1;
|
||||
EXPECT_EQ(member1.Get(), member2.Get());
|
||||
}
|
||||
{
|
||||
DerivedGCed gced;
|
||||
Member1<DerivedGCed> member1 = &gced;
|
||||
Member2<GCed> member2 = member1;
|
||||
EXPECT_EQ(member1.Get(), member2.Get());
|
||||
}
|
||||
{
|
||||
GCed gced;
|
||||
Member1<GCed> member1 = &gced;
|
||||
Member2<GCed> member2;
|
||||
member2 = member1;
|
||||
EXPECT_EQ(member1.Get(), member2.Get());
|
||||
}
|
||||
{
|
||||
DerivedGCed gced;
|
||||
Member1<DerivedGCed> member1 = &gced;
|
||||
Member2<GCed> member2;
|
||||
member2 = member1;
|
||||
EXPECT_EQ(member1.Get(), member2.Get());
|
||||
}
|
||||
}
|
||||
|
||||
TEST(MemberTest, HeterogeneousInterface) {
|
||||
HeterogeneousConversionTest<Member, Member>();
|
||||
HeterogeneousConversionTest<Member, WeakMember>();
|
||||
HeterogeneousConversionTest<Member, UntracedMember>();
|
||||
HeterogeneousConversionTest<WeakMember, Member>();
|
||||
HeterogeneousConversionTest<WeakMember, WeakMember>();
|
||||
HeterogeneousConversionTest<WeakMember, UntracedMember>();
|
||||
HeterogeneousConversionTest<UntracedMember, Member>();
|
||||
HeterogeneousConversionTest<UntracedMember, WeakMember>();
|
||||
HeterogeneousConversionTest<UntracedMember, UntracedMember>();
|
||||
}
|
||||
|
||||
template <template <typename> class Member1, template <typename> class Member2>
|
||||
void EqualityTest() {
|
||||
{
|
||||
GCed gced;
|
||||
Member1<GCed> member1 = &gced;
|
||||
Member2<GCed> member2 = &gced;
|
||||
EXPECT_TRUE(member1 == member2);
|
||||
EXPECT_FALSE(member1 != member2);
|
||||
member2 = member1;
|
||||
EXPECT_TRUE(member1 == member2);
|
||||
EXPECT_FALSE(member1 != member2);
|
||||
}
|
||||
{
|
||||
GCed gced1;
|
||||
GCed gced2;
|
||||
Member1<GCed> member1 = &gced1;
|
||||
Member2<GCed> member2 = &gced2;
|
||||
EXPECT_TRUE(member1 != member2);
|
||||
EXPECT_FALSE(member1 == member2);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(MemberTest, EqualityTest) {
|
||||
EqualityTest<Member, Member>();
|
||||
EqualityTest<Member, WeakMember>();
|
||||
EqualityTest<Member, UntracedMember>();
|
||||
EqualityTest<WeakMember, Member>();
|
||||
EqualityTest<WeakMember, WeakMember>();
|
||||
EqualityTest<WeakMember, UntracedMember>();
|
||||
EqualityTest<UntracedMember, Member>();
|
||||
EqualityTest<UntracedMember, WeakMember>();
|
||||
EqualityTest<UntracedMember, UntracedMember>();
|
||||
}
|
||||
|
||||
TEST(MemberTest, WriteBarrierTriggered) {
|
||||
CustomWriteBarrierPolicy::InitializingWriteBarriersTriggered = 0;
|
||||
CustomWriteBarrierPolicy::AssigningWriteBarriersTriggered = 0;
|
||||
GCed gced;
|
||||
MemberWithCustomBarrier member1 = &gced;
|
||||
EXPECT_EQ(1u, CustomWriteBarrierPolicy::InitializingWriteBarriersTriggered);
|
||||
EXPECT_EQ(0u, CustomWriteBarrierPolicy::AssigningWriteBarriersTriggered);
|
||||
member1 = &gced;
|
||||
EXPECT_EQ(1u, CustomWriteBarrierPolicy::InitializingWriteBarriersTriggered);
|
||||
EXPECT_EQ(1u, CustomWriteBarrierPolicy::AssigningWriteBarriersTriggered);
|
||||
member1 = nullptr;
|
||||
EXPECT_EQ(1u, CustomWriteBarrierPolicy::InitializingWriteBarriersTriggered);
|
||||
EXPECT_EQ(1u, CustomWriteBarrierPolicy::AssigningWriteBarriersTriggered);
|
||||
MemberWithCustomBarrier member2 = nullptr;
|
||||
// No initializing barriers for std::nullptr_t.
|
||||
EXPECT_EQ(1u, CustomWriteBarrierPolicy::InitializingWriteBarriersTriggered);
|
||||
EXPECT_EQ(1u, CustomWriteBarrierPolicy::AssigningWriteBarriersTriggered);
|
||||
member2 = kMemberSentinel;
|
||||
// No initializing barriers for member sentinel.
|
||||
EXPECT_EQ(1u, CustomWriteBarrierPolicy::InitializingWriteBarriersTriggered);
|
||||
EXPECT_EQ(1u, CustomWriteBarrierPolicy::AssigningWriteBarriersTriggered);
|
||||
member2.Swap(member1);
|
||||
EXPECT_EQ(3u, CustomWriteBarrierPolicy::AssigningWriteBarriersTriggered);
|
||||
}
|
||||
|
||||
TEST(MemberTest, CheckingPolocy) {
|
||||
CustomCheckingPolicy::ChecksTriggered = 0u;
|
||||
MemberWithCustomChecking member;
|
||||
for (GCed& item : CustomCheckingPolicy::Array) {
|
||||
member = &item;
|
||||
}
|
||||
EXPECT_EQ(CustomCheckingPolicy::Array.size(),
|
||||
CustomCheckingPolicy::ChecksTriggered);
|
||||
}
|
||||
} // namespace internal
|
||||
} // namespace cppgc
|
Loading…
Reference in New Issue
Block a user