blob: 1172eedb866c7a1a4723fd96ce9070219deec32e [file] [log] [blame]
// 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/ephemeron-pair.h"
#include "include/cppgc/allocation.h"
#include "include/cppgc/persistent.h"
#include "src/heap/cppgc/heap-object-header.h"
#include "src/heap/cppgc/marking-visitor.h"
#include "src/heap/cppgc/stats-collector.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(cppgc::Visitor*) const {}
};
class EphemeronHolder : public GarbageCollected<GCed> {
public:
EphemeronHolder(GCed* key, GCed* value) : ephemeron_pair_(key, value) {}
void Trace(cppgc::Visitor* visitor) const { visitor->Trace(ephemeron_pair_); }
private:
EphemeronPair<GCed, GCed> ephemeron_pair_;
};
class EhpemeronPairTest : public testing::TestWithHeap {
using MarkingConfig = Marker::MarkingConfig;
static constexpr Marker::MarkingConfig IncrementalPreciseMarkingConfig = {
MarkingConfig::CollectionType::kMajor,
MarkingConfig::StackState::kNoHeapPointers,
MarkingConfig::MarkingType::kIncremental};
public:
void FinishSteps() {
while (!SingleStep()) {
}
}
void FinishMarking() {
marker_->FinishMarking(MarkingConfig::StackState::kNoHeapPointers);
// Pretend do finish sweeping as StatsCollector verifies that Notify*
// methods are called in the right order.
Heap::From(GetHeap())->stats_collector()->NotifySweepingCompleted();
}
void InitializeMarker(HeapBase& heap, cppgc::Platform* platform) {
marker_ = MarkerFactory::CreateAndStartMarking<Marker>(
heap, platform, IncrementalPreciseMarkingConfig);
}
Marker* marker() const { return marker_.get(); }
private:
bool SingleStep() {
return marker_->IncrementalMarkingStepForTesting(
MarkingConfig::StackState::kNoHeapPointers);
}
std::unique_ptr<Marker> marker_;
};
// static
constexpr Marker::MarkingConfig
EhpemeronPairTest::IncrementalPreciseMarkingConfig;
} // namespace
TEST_F(EhpemeronPairTest, ValueMarkedWhenKeyIsMarked) {
GCed* key = MakeGarbageCollected<GCed>(GetAllocationHandle());
GCed* value = MakeGarbageCollected<GCed>(GetAllocationHandle());
Persistent<EphemeronHolder> holder =
MakeGarbageCollected<EphemeronHolder>(GetAllocationHandle(), key, value);
HeapObjectHeader::FromPayload(key).TryMarkAtomic();
InitializeMarker(*Heap::From(GetHeap()), GetPlatformHandle().get());
FinishMarking();
EXPECT_TRUE(HeapObjectHeader::FromPayload(value).IsMarked());
}
TEST_F(EhpemeronPairTest, ValueNotMarkedWhenKeyIsNotMarked) {
GCed* key = MakeGarbageCollected<GCed>(GetAllocationHandle());
GCed* value = MakeGarbageCollected<GCed>(GetAllocationHandle());
Persistent<EphemeronHolder> holder =
MakeGarbageCollected<EphemeronHolder>(GetAllocationHandle(), key, value);
InitializeMarker(*Heap::From(GetHeap()), GetPlatformHandle().get());
FinishMarking();
EXPECT_FALSE(HeapObjectHeader::FromPayload(key).IsMarked());
EXPECT_FALSE(HeapObjectHeader::FromPayload(value).IsMarked());
}
TEST_F(EhpemeronPairTest, ValueNotMarkedBeforeKey) {
GCed* key = MakeGarbageCollected<GCed>(GetAllocationHandle());
GCed* value = MakeGarbageCollected<GCed>(GetAllocationHandle());
Persistent<EphemeronHolder> holder =
MakeGarbageCollected<EphemeronHolder>(GetAllocationHandle(), key, value);
InitializeMarker(*Heap::From(GetHeap()), GetPlatformHandle().get());
FinishSteps();
EXPECT_FALSE(HeapObjectHeader::FromPayload(value).IsMarked());
HeapObjectHeader::FromPayload(key).TryMarkAtomic();
FinishMarking();
EXPECT_TRUE(HeapObjectHeader::FromPayload(value).IsMarked());
}
} // namespace internal
} // namespace cppgc