c02258f01d
This change comprises a few tiny changes wrt Member: 1) Move member policies to a separate file so that some of them (CheckingPolicy) can be reused by Persistent; 2) SFINAE out incompatible pointers from heterogeneous ctor/asgnmt; 3) Rename kMemberSentinel to kSentinelPointer. Bug: chromium:1056170 Change-Id: I4482998e6ba61005a5d0861dcae9fab2aa43702c Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2139587 Reviewed-by: Omer Katz <omerkatz@chromium.org> Reviewed-by: Michael Lippautz <mlippautz@chromium.org> Commit-Queue: Anton Bikineev <bikineev@chromium.org> Cr-Commit-Position: refs/heads/master@{#67061}
257 lines
8.4 KiB
C++
257 lines
8.4 KiB
C++
// 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 <algorithm>
|
|
#include <vector>
|
|
|
|
#include "include/cppgc/allocation.h"
|
|
#include "include/cppgc/garbage-collected.h"
|
|
#include "include/cppgc/member.h"
|
|
#include "include/cppgc/type-traits.h"
|
|
|
|
#include "test/unittests/heap/cppgc/tests.h"
|
|
#include "testing/gtest/include/gtest/gtest.h"
|
|
|
|
namespace cppgc {
|
|
namespace internal {
|
|
|
|
namespace {
|
|
|
|
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 =
|
|
BasicMember<GCed, StrongMemberTag, CustomWriteBarrierPolicy>;
|
|
|
|
struct CustomCheckingPolicy {
|
|
static std::vector<GCed*> Cached;
|
|
static size_t ChecksTriggered;
|
|
void CheckPointer(const void* ptr) {
|
|
EXPECT_NE(Cached.cend(), std::find(Cached.cbegin(), Cached.cend(), ptr));
|
|
++ChecksTriggered;
|
|
}
|
|
};
|
|
std::vector<GCed*> CustomCheckingPolicy::Cached;
|
|
size_t CustomCheckingPolicy::ChecksTriggered = 0;
|
|
|
|
using MemberWithCustomChecking =
|
|
BasicMember<GCed, StrongMemberTag, DijkstraWriteBarrierPolicy,
|
|
CustomCheckingPolicy>;
|
|
|
|
class MemberTest : public testing::TestSupportingAllocationOnly {};
|
|
|
|
} // namespace
|
|
|
|
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_F(MemberTest, Empty) {
|
|
EmptyTest<Member>();
|
|
EmptyTest<WeakMember>();
|
|
EmptyTest<UntracedMember>();
|
|
}
|
|
|
|
template <template <typename> class Member>
|
|
void ClearTest(cppgc::Heap* heap) {
|
|
Member<GCed> member = MakeGarbageCollected<GCed>(heap);
|
|
EXPECT_NE(nullptr, member.Get());
|
|
member.Clear();
|
|
EXPECT_EQ(nullptr, member.Get());
|
|
}
|
|
|
|
TEST_F(MemberTest, Clear) {
|
|
cppgc::Heap* heap = GetHeap();
|
|
ClearTest<Member>(heap);
|
|
ClearTest<WeakMember>(heap);
|
|
ClearTest<UntracedMember>(heap);
|
|
}
|
|
|
|
template <template <typename> class Member>
|
|
void ReleaseTest(cppgc::Heap* heap) {
|
|
GCed* gced = MakeGarbageCollected<GCed>(heap);
|
|
Member<GCed> member = gced;
|
|
EXPECT_NE(nullptr, member.Get());
|
|
GCed* raw = member.Release();
|
|
EXPECT_EQ(gced, raw);
|
|
EXPECT_EQ(nullptr, member.Get());
|
|
}
|
|
|
|
TEST_F(MemberTest, Release) {
|
|
cppgc::Heap* heap = GetHeap();
|
|
ReleaseTest<Member>(heap);
|
|
ReleaseTest<WeakMember>(heap);
|
|
ReleaseTest<UntracedMember>(heap);
|
|
}
|
|
|
|
template <template <typename> class Member1, template <typename> class Member2>
|
|
void SwapTest(cppgc::Heap* heap) {
|
|
GCed* gced1 = MakeGarbageCollected<GCed>(heap);
|
|
GCed* gced2 = MakeGarbageCollected<GCed>(heap);
|
|
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_F(MemberTest, Swap) {
|
|
cppgc::Heap* heap = GetHeap();
|
|
SwapTest<Member, Member>(heap);
|
|
SwapTest<Member, WeakMember>(heap);
|
|
SwapTest<Member, UntracedMember>(heap);
|
|
SwapTest<WeakMember, Member>(heap);
|
|
SwapTest<WeakMember, WeakMember>(heap);
|
|
SwapTest<WeakMember, UntracedMember>(heap);
|
|
SwapTest<UntracedMember, Member>(heap);
|
|
SwapTest<UntracedMember, WeakMember>(heap);
|
|
SwapTest<UntracedMember, UntracedMember>(heap);
|
|
}
|
|
|
|
template <template <typename> class Member1, template <typename> class Member2>
|
|
void HeterogeneousConversionTest(cppgc::Heap* heap) {
|
|
{
|
|
Member1<GCed> member1 = MakeGarbageCollected<GCed>(heap);
|
|
Member2<GCed> member2 = member1;
|
|
EXPECT_EQ(member1.Get(), member2.Get());
|
|
}
|
|
{
|
|
Member1<DerivedGCed> member1 = MakeGarbageCollected<DerivedGCed>(heap);
|
|
Member2<GCed> member2 = member1;
|
|
EXPECT_EQ(member1.Get(), member2.Get());
|
|
}
|
|
{
|
|
Member1<GCed> member1 = MakeGarbageCollected<GCed>(heap);
|
|
Member2<GCed> member2;
|
|
member2 = member1;
|
|
EXPECT_EQ(member1.Get(), member2.Get());
|
|
}
|
|
{
|
|
Member1<DerivedGCed> member1 = MakeGarbageCollected<DerivedGCed>(heap);
|
|
Member2<GCed> member2;
|
|
member2 = member1;
|
|
EXPECT_EQ(member1.Get(), member2.Get());
|
|
}
|
|
}
|
|
|
|
TEST_F(MemberTest, HeterogeneousInterface) {
|
|
cppgc::Heap* heap = GetHeap();
|
|
HeterogeneousConversionTest<Member, Member>(heap);
|
|
HeterogeneousConversionTest<Member, WeakMember>(heap);
|
|
HeterogeneousConversionTest<Member, UntracedMember>(heap);
|
|
HeterogeneousConversionTest<WeakMember, Member>(heap);
|
|
HeterogeneousConversionTest<WeakMember, WeakMember>(heap);
|
|
HeterogeneousConversionTest<WeakMember, UntracedMember>(heap);
|
|
HeterogeneousConversionTest<UntracedMember, Member>(heap);
|
|
HeterogeneousConversionTest<UntracedMember, WeakMember>(heap);
|
|
HeterogeneousConversionTest<UntracedMember, UntracedMember>(heap);
|
|
}
|
|
|
|
template <template <typename> class Member1, template <typename> class Member2>
|
|
void EqualityTest(cppgc::Heap* heap) {
|
|
{
|
|
GCed* gced = MakeGarbageCollected<GCed>(heap);
|
|
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);
|
|
}
|
|
{
|
|
Member1<GCed> member1 = MakeGarbageCollected<GCed>(heap);
|
|
Member2<GCed> member2 = MakeGarbageCollected<GCed>(heap);
|
|
EXPECT_TRUE(member1 != member2);
|
|
EXPECT_FALSE(member1 == member2);
|
|
}
|
|
}
|
|
|
|
TEST_F(MemberTest, EqualityTest) {
|
|
cppgc::Heap* heap = GetHeap();
|
|
EqualityTest<Member, Member>(heap);
|
|
EqualityTest<Member, WeakMember>(heap);
|
|
EqualityTest<Member, UntracedMember>(heap);
|
|
EqualityTest<WeakMember, Member>(heap);
|
|
EqualityTest<WeakMember, WeakMember>(heap);
|
|
EqualityTest<WeakMember, UntracedMember>(heap);
|
|
EqualityTest<UntracedMember, Member>(heap);
|
|
EqualityTest<UntracedMember, WeakMember>(heap);
|
|
EqualityTest<UntracedMember, UntracedMember>(heap);
|
|
}
|
|
|
|
TEST_F(MemberTest, WriteBarrierTriggered) {
|
|
CustomWriteBarrierPolicy::InitializingWriteBarriersTriggered = 0;
|
|
CustomWriteBarrierPolicy::AssigningWriteBarriersTriggered = 0;
|
|
GCed* gced = MakeGarbageCollected<GCed>(GetHeap());
|
|
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 = kSentinelPointer;
|
|
EXPECT_EQ(kSentinelPointer, member2.Get());
|
|
// No initializing barriers for pointer sentinel.
|
|
EXPECT_EQ(1u, CustomWriteBarrierPolicy::InitializingWriteBarriersTriggered);
|
|
EXPECT_EQ(1u, CustomWriteBarrierPolicy::AssigningWriteBarriersTriggered);
|
|
member2.Swap(member1);
|
|
EXPECT_EQ(3u, CustomWriteBarrierPolicy::AssigningWriteBarriersTriggered);
|
|
}
|
|
|
|
TEST_F(MemberTest, CheckingPolicy) {
|
|
static constexpr size_t kElements = 64u;
|
|
CustomCheckingPolicy::ChecksTriggered = 0u;
|
|
|
|
for (std::size_t i = 0; i < kElements; ++i) {
|
|
CustomCheckingPolicy::Cached.push_back(
|
|
MakeGarbageCollected<GCed>(GetHeap()));
|
|
}
|
|
|
|
MemberWithCustomChecking member;
|
|
for (GCed* item : CustomCheckingPolicy::Cached) {
|
|
member = item;
|
|
}
|
|
EXPECT_EQ(CustomCheckingPolicy::Cached.size(),
|
|
CustomCheckingPolicy::ChecksTriggered);
|
|
}
|
|
} // namespace internal
|
|
} // namespace cppgc
|