2020-05-07 12:16:20 +00:00
|
|
|
// 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 "src/heap/cppgc/marking-visitor.h"
|
|
|
|
|
|
|
|
#include "include/cppgc/allocation.h"
|
|
|
|
#include "include/cppgc/member.h"
|
|
|
|
#include "include/cppgc/persistent.h"
|
|
|
|
#include "include/cppgc/source-location.h"
|
|
|
|
#include "src/heap/cppgc/globals.h"
|
2020-06-29 17:17:20 +00:00
|
|
|
#include "src/heap/cppgc/heap-object-header.h"
|
2020-05-07 12:16:20 +00:00
|
|
|
#include "src/heap/cppgc/marker.h"
|
2020-07-01 12:40:40 +00:00
|
|
|
#include "src/heap/cppgc/marking-state.h"
|
2020-05-07 12:16:20 +00:00
|
|
|
#include "test/unittests/heap/cppgc/tests.h"
|
|
|
|
#include "testing/gtest/include/gtest/gtest.h"
|
|
|
|
|
|
|
|
namespace cppgc {
|
|
|
|
namespace internal {
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
|
|
|
|
class MarkingVisitorTest : public testing::TestWithHeap {
|
|
|
|
public:
|
|
|
|
MarkingVisitorTest()
|
2021-12-03 12:53:10 +00:00
|
|
|
: marker_(std::make_unique<Marker>(*Heap::From(GetHeap()),
|
|
|
|
GetPlatformHandle().get())) {
|
|
|
|
marker_->StartMarking();
|
|
|
|
}
|
2020-07-03 19:28:57 +00:00
|
|
|
~MarkingVisitorTest() override { marker_->ClearAllWorklistsForTesting(); }
|
2020-05-07 12:16:20 +00:00
|
|
|
|
|
|
|
Marker* GetMarker() { return marker_.get(); }
|
|
|
|
|
|
|
|
private:
|
|
|
|
std::unique_ptr<Marker> marker_;
|
|
|
|
};
|
|
|
|
|
|
|
|
class GCed : public GarbageCollected<GCed> {
|
|
|
|
public:
|
|
|
|
void Trace(cppgc::Visitor*) const {}
|
|
|
|
};
|
|
|
|
|
|
|
|
class Mixin : public GarbageCollectedMixin {};
|
|
|
|
class GCedWithMixin : public GarbageCollected<GCedWithMixin>, public Mixin {
|
|
|
|
public:
|
|
|
|
void Trace(cppgc::Visitor*) const override {}
|
|
|
|
};
|
|
|
|
|
2020-10-05 17:40:21 +00:00
|
|
|
class TestMarkingVisitor : public MutatorMarkingVisitor {
|
2020-07-03 19:28:57 +00:00
|
|
|
public:
|
|
|
|
explicit TestMarkingVisitor(Marker* marker)
|
2020-10-05 17:40:21 +00:00
|
|
|
: MutatorMarkingVisitor(marker->heap(),
|
2022-03-23 20:16:39 +00:00
|
|
|
marker->MutatorMarkingStateForTesting()) {}
|
2020-09-09 08:50:34 +00:00
|
|
|
~TestMarkingVisitor() { marking_state_.Publish(); }
|
2020-10-02 12:52:05 +00:00
|
|
|
|
2021-12-03 12:53:10 +00:00
|
|
|
BasicMarkingState& marking_state() { return marking_state_; }
|
2020-07-03 19:28:57 +00:00
|
|
|
};
|
|
|
|
|
2020-05-07 12:16:20 +00:00
|
|
|
} // namespace
|
|
|
|
|
2020-06-05 11:23:49 +00:00
|
|
|
TEST_F(MarkingVisitorTest, MarkedBytesAreInitiallyZero) {
|
2020-10-05 17:40:21 +00:00
|
|
|
EXPECT_EQ(0u, GetMarker()->MutatorMarkingStateForTesting().marked_bytes());
|
2020-06-05 11:23:49 +00:00
|
|
|
}
|
|
|
|
|
2020-07-01 12:40:40 +00:00
|
|
|
// Strong references are marked.
|
2020-05-07 12:16:20 +00:00
|
|
|
|
|
|
|
TEST_F(MarkingVisitorTest, MarkMember) {
|
2020-06-10 22:28:41 +00:00
|
|
|
Member<GCed> object(MakeGarbageCollected<GCed>(GetAllocationHandle()));
|
2021-05-12 18:08:11 +00:00
|
|
|
HeapObjectHeader& header = HeapObjectHeader::FromObject(object);
|
2020-05-07 12:16:20 +00:00
|
|
|
|
2020-07-03 19:28:57 +00:00
|
|
|
TestMarkingVisitor visitor(GetMarker());
|
2020-05-07 12:16:20 +00:00
|
|
|
|
|
|
|
EXPECT_FALSE(header.IsMarked());
|
|
|
|
|
|
|
|
visitor.Trace(object);
|
|
|
|
|
|
|
|
EXPECT_TRUE(header.IsMarked());
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_F(MarkingVisitorTest, MarkMemberMixin) {
|
2020-06-10 22:28:41 +00:00
|
|
|
GCedWithMixin* object(
|
|
|
|
MakeGarbageCollected<GCedWithMixin>(GetAllocationHandle()));
|
2020-05-07 12:16:20 +00:00
|
|
|
Member<Mixin> mixin(object);
|
2021-05-12 18:08:11 +00:00
|
|
|
HeapObjectHeader& header = HeapObjectHeader::FromObject(object);
|
2020-05-07 12:16:20 +00:00
|
|
|
|
2020-07-03 19:28:57 +00:00
|
|
|
TestMarkingVisitor visitor(GetMarker());
|
2020-05-07 12:16:20 +00:00
|
|
|
|
|
|
|
EXPECT_FALSE(header.IsMarked());
|
|
|
|
|
|
|
|
visitor.Trace(mixin);
|
|
|
|
|
|
|
|
EXPECT_TRUE(header.IsMarked());
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_F(MarkingVisitorTest, MarkPersistent) {
|
2020-06-10 22:28:41 +00:00
|
|
|
Persistent<GCed> object(MakeGarbageCollected<GCed>(GetAllocationHandle()));
|
2021-05-12 18:08:11 +00:00
|
|
|
HeapObjectHeader& header = HeapObjectHeader::FromObject(object);
|
2020-05-07 12:16:20 +00:00
|
|
|
|
2020-07-03 19:28:57 +00:00
|
|
|
TestMarkingVisitor visitor(GetMarker());
|
2020-05-07 12:16:20 +00:00
|
|
|
|
|
|
|
EXPECT_FALSE(header.IsMarked());
|
|
|
|
|
2020-06-08 15:26:04 +00:00
|
|
|
visitor.TraceRootForTesting(object, SourceLocation::Current());
|
2020-05-07 12:16:20 +00:00
|
|
|
|
|
|
|
EXPECT_TRUE(header.IsMarked());
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_F(MarkingVisitorTest, MarkPersistentMixin) {
|
2020-06-10 22:28:41 +00:00
|
|
|
GCedWithMixin* object(
|
|
|
|
MakeGarbageCollected<GCedWithMixin>(GetAllocationHandle()));
|
2020-05-07 12:16:20 +00:00
|
|
|
Persistent<Mixin> mixin(object);
|
2021-05-12 18:08:11 +00:00
|
|
|
HeapObjectHeader& header = HeapObjectHeader::FromObject(object);
|
2020-05-07 12:16:20 +00:00
|
|
|
|
2020-07-03 19:28:57 +00:00
|
|
|
TestMarkingVisitor visitor(GetMarker());
|
2020-05-07 12:16:20 +00:00
|
|
|
|
|
|
|
EXPECT_FALSE(header.IsMarked());
|
|
|
|
|
2020-06-08 15:26:04 +00:00
|
|
|
visitor.TraceRootForTesting(mixin, SourceLocation::Current());
|
2020-05-07 12:16:20 +00:00
|
|
|
|
|
|
|
EXPECT_TRUE(header.IsMarked());
|
|
|
|
}
|
|
|
|
|
|
|
|
// Weak references are not marked.
|
|
|
|
|
|
|
|
TEST_F(MarkingVisitorTest, DontMarkWeakMember) {
|
2020-06-10 22:28:41 +00:00
|
|
|
WeakMember<GCed> object(MakeGarbageCollected<GCed>(GetAllocationHandle()));
|
2021-05-12 18:08:11 +00:00
|
|
|
HeapObjectHeader& header = HeapObjectHeader::FromObject(object);
|
2020-05-07 12:16:20 +00:00
|
|
|
|
2020-07-03 19:28:57 +00:00
|
|
|
TestMarkingVisitor visitor(GetMarker());
|
2020-05-07 12:16:20 +00:00
|
|
|
|
|
|
|
EXPECT_FALSE(header.IsMarked());
|
|
|
|
|
|
|
|
visitor.Trace(object);
|
|
|
|
|
|
|
|
EXPECT_FALSE(header.IsMarked());
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_F(MarkingVisitorTest, DontMarkWeakMemberMixin) {
|
2020-06-10 22:28:41 +00:00
|
|
|
GCedWithMixin* object(
|
|
|
|
MakeGarbageCollected<GCedWithMixin>(GetAllocationHandle()));
|
2020-05-07 12:16:20 +00:00
|
|
|
WeakMember<Mixin> mixin(object);
|
2021-05-12 18:08:11 +00:00
|
|
|
HeapObjectHeader& header = HeapObjectHeader::FromObject(object);
|
2020-05-07 12:16:20 +00:00
|
|
|
|
2020-07-03 19:28:57 +00:00
|
|
|
TestMarkingVisitor visitor(GetMarker());
|
2020-05-07 12:16:20 +00:00
|
|
|
|
|
|
|
EXPECT_FALSE(header.IsMarked());
|
|
|
|
|
|
|
|
visitor.Trace(mixin);
|
|
|
|
|
|
|
|
EXPECT_FALSE(header.IsMarked());
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_F(MarkingVisitorTest, DontMarkWeakPersistent) {
|
2020-06-10 22:28:41 +00:00
|
|
|
WeakPersistent<GCed> object(
|
|
|
|
MakeGarbageCollected<GCed>(GetAllocationHandle()));
|
2021-05-12 18:08:11 +00:00
|
|
|
HeapObjectHeader& header = HeapObjectHeader::FromObject(object);
|
2020-05-07 12:16:20 +00:00
|
|
|
|
2020-07-03 19:28:57 +00:00
|
|
|
TestMarkingVisitor visitor(GetMarker());
|
2020-05-07 12:16:20 +00:00
|
|
|
|
|
|
|
EXPECT_FALSE(header.IsMarked());
|
|
|
|
|
2020-06-08 15:26:04 +00:00
|
|
|
visitor.TraceRootForTesting(object, SourceLocation::Current());
|
2020-05-07 12:16:20 +00:00
|
|
|
|
|
|
|
EXPECT_FALSE(header.IsMarked());
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_F(MarkingVisitorTest, DontMarkWeakPersistentMixin) {
|
2020-06-10 22:28:41 +00:00
|
|
|
GCedWithMixin* object(
|
|
|
|
MakeGarbageCollected<GCedWithMixin>(GetAllocationHandle()));
|
2020-05-07 12:16:20 +00:00
|
|
|
WeakPersistent<Mixin> mixin(object);
|
2021-05-12 18:08:11 +00:00
|
|
|
HeapObjectHeader& header = HeapObjectHeader::FromObject(object);
|
2020-05-07 12:16:20 +00:00
|
|
|
|
2020-07-03 19:28:57 +00:00
|
|
|
TestMarkingVisitor visitor(GetMarker());
|
2020-05-07 12:16:20 +00:00
|
|
|
|
|
|
|
EXPECT_FALSE(header.IsMarked());
|
|
|
|
|
2020-06-08 15:26:04 +00:00
|
|
|
visitor.TraceRootForTesting(mixin, SourceLocation::Current());
|
2020-05-07 12:16:20 +00:00
|
|
|
|
|
|
|
EXPECT_FALSE(header.IsMarked());
|
|
|
|
}
|
|
|
|
|
|
|
|
// In construction objects are not marked.
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
|
|
|
|
class GCedWithInConstructionCallback
|
|
|
|
: public GarbageCollected<GCedWithInConstructionCallback> {
|
|
|
|
public:
|
|
|
|
template <typename Callback>
|
|
|
|
explicit GCedWithInConstructionCallback(Callback callback) {
|
|
|
|
callback(this);
|
|
|
|
}
|
|
|
|
void Trace(cppgc::Visitor*) const {}
|
|
|
|
};
|
|
|
|
|
|
|
|
class MixinWithInConstructionCallback : public GarbageCollectedMixin {
|
|
|
|
public:
|
|
|
|
template <typename Callback>
|
|
|
|
explicit MixinWithInConstructionCallback(Callback callback) {
|
|
|
|
callback(this);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
class GCedWithMixinWithInConstructionCallback
|
|
|
|
: public GarbageCollected<GCedWithMixinWithInConstructionCallback>,
|
|
|
|
public MixinWithInConstructionCallback {
|
|
|
|
public:
|
|
|
|
template <typename Callback>
|
|
|
|
explicit GCedWithMixinWithInConstructionCallback(Callback callback)
|
|
|
|
: MixinWithInConstructionCallback(callback) {}
|
|
|
|
void Trace(cppgc::Visitor*) const override {}
|
|
|
|
};
|
|
|
|
|
|
|
|
} // namespace
|
|
|
|
|
2020-08-04 13:48:55 +00:00
|
|
|
TEST_F(MarkingVisitorTest, MarkMemberInConstruction) {
|
2020-07-03 19:28:57 +00:00
|
|
|
TestMarkingVisitor visitor(GetMarker());
|
2020-05-07 12:16:20 +00:00
|
|
|
GCedWithInConstructionCallback* gced =
|
|
|
|
MakeGarbageCollected<GCedWithInConstructionCallback>(
|
2020-06-10 22:28:41 +00:00
|
|
|
GetAllocationHandle(),
|
|
|
|
[&visitor](GCedWithInConstructionCallback* obj) {
|
2020-05-07 12:16:20 +00:00
|
|
|
Member<GCedWithInConstructionCallback> object(obj);
|
|
|
|
visitor.Trace(object);
|
|
|
|
});
|
2021-05-12 18:08:11 +00:00
|
|
|
HeapObjectHeader& header = HeapObjectHeader::FromObject(gced);
|
2020-10-22 12:17:57 +00:00
|
|
|
EXPECT_TRUE(visitor.marking_state().not_fully_constructed_worklist().Contains(
|
|
|
|
&header));
|
2020-10-02 12:52:05 +00:00
|
|
|
EXPECT_FALSE(header.IsMarked());
|
2020-05-07 12:16:20 +00:00
|
|
|
}
|
|
|
|
|
2020-08-04 13:48:55 +00:00
|
|
|
TEST_F(MarkingVisitorTest, MarkMemberMixinInConstruction) {
|
2020-07-03 19:28:57 +00:00
|
|
|
TestMarkingVisitor visitor(GetMarker());
|
2020-05-07 12:16:20 +00:00
|
|
|
GCedWithMixinWithInConstructionCallback* gced =
|
|
|
|
MakeGarbageCollected<GCedWithMixinWithInConstructionCallback>(
|
2020-06-10 22:28:41 +00:00
|
|
|
GetAllocationHandle(),
|
|
|
|
[&visitor](MixinWithInConstructionCallback* obj) {
|
2020-05-07 12:16:20 +00:00
|
|
|
Member<MixinWithInConstructionCallback> mixin(obj);
|
|
|
|
visitor.Trace(mixin);
|
|
|
|
});
|
2021-05-12 18:08:11 +00:00
|
|
|
HeapObjectHeader& header = HeapObjectHeader::FromObject(gced);
|
2020-10-22 12:17:57 +00:00
|
|
|
EXPECT_TRUE(visitor.marking_state().not_fully_constructed_worklist().Contains(
|
|
|
|
&header));
|
2020-10-02 12:52:05 +00:00
|
|
|
EXPECT_FALSE(header.IsMarked());
|
2020-05-07 12:16:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
TEST_F(MarkingVisitorTest, DontMarkWeakMemberInConstruction) {
|
2020-07-03 19:28:57 +00:00
|
|
|
TestMarkingVisitor visitor(GetMarker());
|
2020-05-07 12:16:20 +00:00
|
|
|
GCedWithInConstructionCallback* gced =
|
|
|
|
MakeGarbageCollected<GCedWithInConstructionCallback>(
|
2020-06-10 22:28:41 +00:00
|
|
|
GetAllocationHandle(),
|
|
|
|
[&visitor](GCedWithInConstructionCallback* obj) {
|
2020-05-07 12:16:20 +00:00
|
|
|
WeakMember<GCedWithInConstructionCallback> object(obj);
|
|
|
|
visitor.Trace(object);
|
|
|
|
});
|
2021-05-12 18:08:11 +00:00
|
|
|
HeapObjectHeader& header = HeapObjectHeader::FromObject(gced);
|
2020-10-22 12:17:57 +00:00
|
|
|
EXPECT_FALSE(
|
|
|
|
visitor.marking_state().not_fully_constructed_worklist().Contains(
|
|
|
|
&header));
|
2020-10-02 12:52:05 +00:00
|
|
|
EXPECT_FALSE(header.IsMarked());
|
2020-05-07 12:16:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
TEST_F(MarkingVisitorTest, DontMarkWeakMemberMixinInConstruction) {
|
2020-07-03 19:28:57 +00:00
|
|
|
TestMarkingVisitor visitor(GetMarker());
|
2020-05-07 12:16:20 +00:00
|
|
|
GCedWithMixinWithInConstructionCallback* gced =
|
|
|
|
MakeGarbageCollected<GCedWithMixinWithInConstructionCallback>(
|
2020-06-10 22:28:41 +00:00
|
|
|
GetAllocationHandle(),
|
|
|
|
[&visitor](MixinWithInConstructionCallback* obj) {
|
2020-05-07 12:16:20 +00:00
|
|
|
WeakMember<MixinWithInConstructionCallback> mixin(obj);
|
|
|
|
visitor.Trace(mixin);
|
|
|
|
});
|
2021-05-12 18:08:11 +00:00
|
|
|
HeapObjectHeader& header = HeapObjectHeader::FromObject(gced);
|
2020-10-22 12:17:57 +00:00
|
|
|
EXPECT_FALSE(
|
|
|
|
visitor.marking_state().not_fully_constructed_worklist().Contains(
|
|
|
|
&header));
|
2020-10-02 12:52:05 +00:00
|
|
|
EXPECT_FALSE(header.IsMarked());
|
2020-05-07 12:16:20 +00:00
|
|
|
}
|
|
|
|
|
2020-08-04 13:48:55 +00:00
|
|
|
TEST_F(MarkingVisitorTest, MarkPersistentInConstruction) {
|
2020-07-03 19:28:57 +00:00
|
|
|
TestMarkingVisitor visitor(GetMarker());
|
2020-05-07 12:16:20 +00:00
|
|
|
GCedWithInConstructionCallback* gced =
|
|
|
|
MakeGarbageCollected<GCedWithInConstructionCallback>(
|
2020-06-10 22:28:41 +00:00
|
|
|
GetAllocationHandle(),
|
|
|
|
[&visitor](GCedWithInConstructionCallback* obj) {
|
2020-05-07 12:16:20 +00:00
|
|
|
Persistent<GCedWithInConstructionCallback> object(obj);
|
2020-06-08 15:26:04 +00:00
|
|
|
visitor.TraceRootForTesting(object, SourceLocation::Current());
|
2020-05-07 12:16:20 +00:00
|
|
|
});
|
2021-05-12 18:08:11 +00:00
|
|
|
HeapObjectHeader& header = HeapObjectHeader::FromObject(gced);
|
2020-10-22 12:17:57 +00:00
|
|
|
EXPECT_TRUE(visitor.marking_state().not_fully_constructed_worklist().Contains(
|
|
|
|
&header));
|
2020-10-02 12:52:05 +00:00
|
|
|
EXPECT_FALSE(header.IsMarked());
|
2020-05-07 12:16:20 +00:00
|
|
|
}
|
|
|
|
|
2020-08-04 13:48:55 +00:00
|
|
|
TEST_F(MarkingVisitorTest, MarkPersistentMixinInConstruction) {
|
2020-07-03 19:28:57 +00:00
|
|
|
TestMarkingVisitor visitor(GetMarker());
|
2020-05-07 12:16:20 +00:00
|
|
|
GCedWithMixinWithInConstructionCallback* gced =
|
|
|
|
MakeGarbageCollected<GCedWithMixinWithInConstructionCallback>(
|
2020-06-10 22:28:41 +00:00
|
|
|
GetAllocationHandle(),
|
|
|
|
[&visitor](MixinWithInConstructionCallback* obj) {
|
2020-05-07 12:16:20 +00:00
|
|
|
Persistent<MixinWithInConstructionCallback> mixin(obj);
|
2020-06-08 15:26:04 +00:00
|
|
|
visitor.TraceRootForTesting(mixin, SourceLocation::Current());
|
2020-05-07 12:16:20 +00:00
|
|
|
});
|
2021-05-12 18:08:11 +00:00
|
|
|
HeapObjectHeader& header = HeapObjectHeader::FromObject(gced);
|
2020-10-22 12:17:57 +00:00
|
|
|
EXPECT_TRUE(visitor.marking_state().not_fully_constructed_worklist().Contains(
|
|
|
|
&header));
|
2020-10-02 12:52:05 +00:00
|
|
|
EXPECT_FALSE(header.IsMarked());
|
2020-05-07 12:16:20 +00:00
|
|
|
}
|
|
|
|
|
2020-10-16 08:55:19 +00:00
|
|
|
TEST_F(MarkingVisitorTest, StrongTracingMarksWeakMember) {
|
|
|
|
WeakMember<GCed> object(MakeGarbageCollected<GCed>(GetAllocationHandle()));
|
2021-05-12 18:08:11 +00:00
|
|
|
HeapObjectHeader& header = HeapObjectHeader::FromObject(object);
|
2020-10-16 08:55:19 +00:00
|
|
|
|
|
|
|
TestMarkingVisitor visitor(GetMarker());
|
|
|
|
|
|
|
|
EXPECT_FALSE(header.IsMarked());
|
|
|
|
|
|
|
|
visitor.TraceStrongly(object);
|
|
|
|
|
|
|
|
EXPECT_TRUE(header.IsMarked());
|
|
|
|
}
|
|
|
|
|
2020-05-07 12:16:20 +00:00
|
|
|
} // namespace internal
|
|
|
|
} // namespace cppgc
|