v8/test/unittests/heap/cppgc/garbage-collected-unittest.cc
Michael Lippautz 373803c959 cppgc: Fix IsGarabgeCollected trait and friends
The TraceTrait<T> checks whether T is a mixin to decide whether we can
use the fast (arithmetic) or slow (bitmap) method to look up the HoH.
Before this CL, the mixin application would also be considered as a
mixin because the marker is present, resulting in all cases going
through the object start bitmap.

The initial intention was to use the arithmetic for the mixin
applications as those inherit from GCed.

Bug: chromium:1056170
Change-Id: Ib0ba82a8f98e0481d2879ebacc1ca9bd9e675858
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2643395
Commit-Queue: Michael Lippautz <mlippautz@chromium.org>
Reviewed-by: Omer Katz <omerkatz@chromium.org>
Cr-Commit-Position: refs/heads/master@{#72262}
2021-01-22 16:20:46 +00:00

151 lines
5.3 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 "include/cppgc/garbage-collected.h"
#include "include/cppgc/allocation.h"
#include "include/cppgc/type-traits.h"
#include "src/heap/cppgc/heap-object-header.h"
#include "src/heap/cppgc/heap.h"
#include "test/unittests/heap/cppgc/tests.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace cppgc {
namespace internal {
namespace {
class GCed : public GarbageCollected<GCed> {
public:
void Trace(Visitor*) const {}
};
class NotGCed {};
class Mixin : public GarbageCollectedMixin {};
class GCedWithMixin : public GarbageCollected<GCedWithMixin>, public Mixin {};
class OtherMixin : public GarbageCollectedMixin {};
class MergedMixins : public Mixin, public OtherMixin {
public:
void Trace(cppgc::Visitor* visitor) const override {
Mixin::Trace(visitor);
OtherMixin::Trace(visitor);
}
};
class GCWithMergedMixins : public GCed, public MergedMixins {
public:
void Trace(cppgc::Visitor* visitor) const override {
MergedMixins::Trace(visitor);
}
};
class GarbageCollectedTestWithHeap
: public testing::TestSupportingAllocationOnly {};
} // namespace
TEST(GarbageCollectedTest, GarbageCollectedTrait) {
STATIC_ASSERT(!IsGarbageCollectedType<int>::value);
STATIC_ASSERT(!IsGarbageCollectedType<NotGCed>::value);
STATIC_ASSERT(IsGarbageCollectedType<GCed>::value);
STATIC_ASSERT(!IsGarbageCollectedType<Mixin>::value);
STATIC_ASSERT(IsGarbageCollectedType<GCedWithMixin>::value);
STATIC_ASSERT(!IsGarbageCollectedType<MergedMixins>::value);
STATIC_ASSERT(IsGarbageCollectedType<GCWithMergedMixins>::value);
}
TEST(GarbageCollectedTest, GarbageCollectedMixinTrait) {
STATIC_ASSERT(!IsGarbageCollectedMixinType<int>::value);
STATIC_ASSERT(!IsGarbageCollectedMixinType<GCed>::value);
STATIC_ASSERT(!IsGarbageCollectedMixinType<NotGCed>::value);
STATIC_ASSERT(IsGarbageCollectedMixinType<Mixin>::value);
STATIC_ASSERT(!IsGarbageCollectedMixinType<GCedWithMixin>::value);
STATIC_ASSERT(IsGarbageCollectedMixinType<MergedMixins>::value);
STATIC_ASSERT(!IsGarbageCollectedMixinType<GCWithMergedMixins>::value);
}
TEST(GarbageCollectedTest, GarbageCollectedOrMixinTrait) {
STATIC_ASSERT(!IsGarbageCollectedOrMixinType<int>::value);
STATIC_ASSERT(IsGarbageCollectedOrMixinType<GCed>::value);
STATIC_ASSERT(!IsGarbageCollectedOrMixinType<NotGCed>::value);
STATIC_ASSERT(IsGarbageCollectedOrMixinType<Mixin>::value);
STATIC_ASSERT(IsGarbageCollectedOrMixinType<GCedWithMixin>::value);
STATIC_ASSERT(IsGarbageCollectedOrMixinType<MergedMixins>::value);
STATIC_ASSERT(IsGarbageCollectedOrMixinType<GCWithMergedMixins>::value);
}
TEST_F(GarbageCollectedTestWithHeap, GetObjectStartReturnsCurrentAddress) {
GCed* gced = MakeGarbageCollected<GCed>(GetAllocationHandle());
GCedWithMixin* gced_with_mixin =
MakeGarbageCollected<GCedWithMixin>(GetAllocationHandle());
const void* base_object_payload = TraceTrait<Mixin>::GetTraceDescriptor(
static_cast<Mixin*>(gced_with_mixin))
.base_object_payload;
EXPECT_EQ(gced_with_mixin, base_object_payload);
EXPECT_NE(gced, base_object_payload);
}
namespace {
class GCedWithPostConstructionCallback final : public GCed {
public:
static size_t cb_callcount;
GCedWithPostConstructionCallback() { cb_callcount = 0; }
};
size_t GCedWithPostConstructionCallback::cb_callcount;
class MixinWithPostConstructionCallback {
public:
static size_t cb_callcount;
MixinWithPostConstructionCallback() { cb_callcount = 0; }
using MarkerForMixinWithPostConstructionCallback = int;
};
size_t MixinWithPostConstructionCallback::cb_callcount;
class GCedWithMixinWithPostConstructionCallback final
: public GCed,
public MixinWithPostConstructionCallback {};
} // namespace
} // namespace internal
template <>
struct PostConstructionCallbackTrait<
internal::GCedWithPostConstructionCallback> {
static void Call(internal::GCedWithPostConstructionCallback* object) {
EXPECT_FALSE(
internal::HeapObjectHeader::FromPayload(object).IsInConstruction());
internal::GCedWithPostConstructionCallback::cb_callcount++;
}
};
template <typename T>
struct PostConstructionCallbackTrait<
T,
internal::void_t<typename T::MarkerForMixinWithPostConstructionCallback>> {
// The parameter could just be T*.
static void Call(
internal::GCedWithMixinWithPostConstructionCallback* object) {
EXPECT_FALSE(
internal::HeapObjectHeader::FromPayload(object).IsInConstruction());
internal::GCedWithMixinWithPostConstructionCallback::cb_callcount++;
}
};
namespace internal {
TEST_F(GarbageCollectedTestWithHeap, PostConstructionCallback) {
EXPECT_EQ(0u, GCedWithPostConstructionCallback::cb_callcount);
MakeGarbageCollected<GCedWithPostConstructionCallback>(GetAllocationHandle());
EXPECT_EQ(1u, GCedWithPostConstructionCallback::cb_callcount);
}
TEST_F(GarbageCollectedTestWithHeap, PostConstructionCallbackForMixin) {
EXPECT_EQ(0u, MixinWithPostConstructionCallback::cb_callcount);
MakeGarbageCollected<GCedWithMixinWithPostConstructionCallback>(
GetAllocationHandle());
EXPECT_EQ(1u, MixinWithPostConstructionCallback::cb_callcount);
}
} // namespace internal
} // namespace cppgc