b7b3abe83a
This CL migrates cppgc to use Ulan's new worklist implementation. Since there is no central segments array anymore, we cannot rely on getting the same view (now renamed to Local) given the same task id. To avoid creating many short lived segments (e.g. for write barriers) marking state now holds local views for all worklists and provides access to them. Bug: chromium:1056170 Change-Id: Id19fe1196b79ed251810e91074046998dc2a9177 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2390771 Commit-Queue: Omer Katz <omerkatz@chromium.org> Reviewed-by: Michael Lippautz <mlippautz@chromium.org> Cr-Commit-Position: refs/heads/master@{#69767}
284 lines
8.7 KiB
C++
284 lines
8.7 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 "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"
|
|
#include "src/heap/cppgc/heap-object-header.h"
|
|
#include "src/heap/cppgc/marker.h"
|
|
#include "src/heap/cppgc/marking-state.h"
|
|
#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()
|
|
: marker_(MarkerFactory::CreateAndStartMarking<Marker>(
|
|
*Heap::From(GetHeap()), GetPlatformHandle().get())) {}
|
|
~MarkingVisitorTest() override { marker_->ClearAllWorklistsForTesting(); }
|
|
|
|
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 {}
|
|
};
|
|
|
|
class TestMarkingVisitor : public MarkingVisitor {
|
|
public:
|
|
explicit TestMarkingVisitor(Marker* marker)
|
|
: MarkingVisitor(marker->heap(), marker->MarkingStateForTesting()) {}
|
|
~TestMarkingVisitor() { marking_state_.Publish(); }
|
|
};
|
|
|
|
} // namespace
|
|
|
|
TEST_F(MarkingVisitorTest, MarkedBytesAreInitiallyZero) {
|
|
EXPECT_EQ(0u, GetMarker()->MarkingStateForTesting().marked_bytes());
|
|
}
|
|
|
|
// Strong references are marked.
|
|
|
|
TEST_F(MarkingVisitorTest, MarkMember) {
|
|
Member<GCed> object(MakeGarbageCollected<GCed>(GetAllocationHandle()));
|
|
HeapObjectHeader& header = HeapObjectHeader::FromPayload(object);
|
|
|
|
TestMarkingVisitor visitor(GetMarker());
|
|
|
|
EXPECT_FALSE(header.IsMarked());
|
|
|
|
visitor.Trace(object);
|
|
|
|
EXPECT_TRUE(header.IsMarked());
|
|
}
|
|
|
|
TEST_F(MarkingVisitorTest, MarkMemberMixin) {
|
|
GCedWithMixin* object(
|
|
MakeGarbageCollected<GCedWithMixin>(GetAllocationHandle()));
|
|
Member<Mixin> mixin(object);
|
|
HeapObjectHeader& header = HeapObjectHeader::FromPayload(object);
|
|
|
|
TestMarkingVisitor visitor(GetMarker());
|
|
|
|
EXPECT_FALSE(header.IsMarked());
|
|
|
|
visitor.Trace(mixin);
|
|
|
|
EXPECT_TRUE(header.IsMarked());
|
|
}
|
|
|
|
TEST_F(MarkingVisitorTest, MarkPersistent) {
|
|
Persistent<GCed> object(MakeGarbageCollected<GCed>(GetAllocationHandle()));
|
|
HeapObjectHeader& header = HeapObjectHeader::FromPayload(object);
|
|
|
|
TestMarkingVisitor visitor(GetMarker());
|
|
|
|
EXPECT_FALSE(header.IsMarked());
|
|
|
|
visitor.TraceRootForTesting(object, SourceLocation::Current());
|
|
|
|
EXPECT_TRUE(header.IsMarked());
|
|
}
|
|
|
|
TEST_F(MarkingVisitorTest, MarkPersistentMixin) {
|
|
GCedWithMixin* object(
|
|
MakeGarbageCollected<GCedWithMixin>(GetAllocationHandle()));
|
|
Persistent<Mixin> mixin(object);
|
|
HeapObjectHeader& header = HeapObjectHeader::FromPayload(object);
|
|
|
|
TestMarkingVisitor visitor(GetMarker());
|
|
|
|
EXPECT_FALSE(header.IsMarked());
|
|
|
|
visitor.TraceRootForTesting(mixin, SourceLocation::Current());
|
|
|
|
EXPECT_TRUE(header.IsMarked());
|
|
}
|
|
|
|
// Weak references are not marked.
|
|
|
|
TEST_F(MarkingVisitorTest, DontMarkWeakMember) {
|
|
WeakMember<GCed> object(MakeGarbageCollected<GCed>(GetAllocationHandle()));
|
|
HeapObjectHeader& header = HeapObjectHeader::FromPayload(object);
|
|
|
|
TestMarkingVisitor visitor(GetMarker());
|
|
|
|
EXPECT_FALSE(header.IsMarked());
|
|
|
|
visitor.Trace(object);
|
|
|
|
EXPECT_FALSE(header.IsMarked());
|
|
}
|
|
|
|
TEST_F(MarkingVisitorTest, DontMarkWeakMemberMixin) {
|
|
GCedWithMixin* object(
|
|
MakeGarbageCollected<GCedWithMixin>(GetAllocationHandle()));
|
|
WeakMember<Mixin> mixin(object);
|
|
HeapObjectHeader& header = HeapObjectHeader::FromPayload(object);
|
|
|
|
TestMarkingVisitor visitor(GetMarker());
|
|
|
|
EXPECT_FALSE(header.IsMarked());
|
|
|
|
visitor.Trace(mixin);
|
|
|
|
EXPECT_FALSE(header.IsMarked());
|
|
}
|
|
|
|
TEST_F(MarkingVisitorTest, DontMarkWeakPersistent) {
|
|
WeakPersistent<GCed> object(
|
|
MakeGarbageCollected<GCed>(GetAllocationHandle()));
|
|
HeapObjectHeader& header = HeapObjectHeader::FromPayload(object);
|
|
|
|
TestMarkingVisitor visitor(GetMarker());
|
|
|
|
EXPECT_FALSE(header.IsMarked());
|
|
|
|
visitor.TraceRootForTesting(object, SourceLocation::Current());
|
|
|
|
EXPECT_FALSE(header.IsMarked());
|
|
}
|
|
|
|
TEST_F(MarkingVisitorTest, DontMarkWeakPersistentMixin) {
|
|
GCedWithMixin* object(
|
|
MakeGarbageCollected<GCedWithMixin>(GetAllocationHandle()));
|
|
WeakPersistent<Mixin> mixin(object);
|
|
HeapObjectHeader& header = HeapObjectHeader::FromPayload(object);
|
|
|
|
TestMarkingVisitor visitor(GetMarker());
|
|
|
|
EXPECT_FALSE(header.IsMarked());
|
|
|
|
visitor.TraceRootForTesting(mixin, SourceLocation::Current());
|
|
|
|
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
|
|
|
|
TEST_F(MarkingVisitorTest, MarkMemberInConstruction) {
|
|
TestMarkingVisitor visitor(GetMarker());
|
|
GCedWithInConstructionCallback* gced =
|
|
MakeGarbageCollected<GCedWithInConstructionCallback>(
|
|
GetAllocationHandle(),
|
|
[&visitor](GCedWithInConstructionCallback* obj) {
|
|
Member<GCedWithInConstructionCallback> object(obj);
|
|
visitor.Trace(object);
|
|
});
|
|
EXPECT_TRUE(HeapObjectHeader::FromPayload(gced).IsMarked());
|
|
}
|
|
|
|
TEST_F(MarkingVisitorTest, MarkMemberMixinInConstruction) {
|
|
TestMarkingVisitor visitor(GetMarker());
|
|
GCedWithMixinWithInConstructionCallback* gced =
|
|
MakeGarbageCollected<GCedWithMixinWithInConstructionCallback>(
|
|
GetAllocationHandle(),
|
|
[&visitor](MixinWithInConstructionCallback* obj) {
|
|
Member<MixinWithInConstructionCallback> mixin(obj);
|
|
visitor.Trace(mixin);
|
|
});
|
|
EXPECT_TRUE(HeapObjectHeader::FromPayload(gced).IsMarked());
|
|
}
|
|
|
|
TEST_F(MarkingVisitorTest, DontMarkWeakMemberInConstruction) {
|
|
TestMarkingVisitor visitor(GetMarker());
|
|
GCedWithInConstructionCallback* gced =
|
|
MakeGarbageCollected<GCedWithInConstructionCallback>(
|
|
GetAllocationHandle(),
|
|
[&visitor](GCedWithInConstructionCallback* obj) {
|
|
WeakMember<GCedWithInConstructionCallback> object(obj);
|
|
visitor.Trace(object);
|
|
});
|
|
EXPECT_FALSE(HeapObjectHeader::FromPayload(gced).IsMarked());
|
|
}
|
|
|
|
TEST_F(MarkingVisitorTest, DontMarkWeakMemberMixinInConstruction) {
|
|
TestMarkingVisitor visitor(GetMarker());
|
|
GCedWithMixinWithInConstructionCallback* gced =
|
|
MakeGarbageCollected<GCedWithMixinWithInConstructionCallback>(
|
|
GetAllocationHandle(),
|
|
[&visitor](MixinWithInConstructionCallback* obj) {
|
|
WeakMember<MixinWithInConstructionCallback> mixin(obj);
|
|
visitor.Trace(mixin);
|
|
});
|
|
EXPECT_FALSE(HeapObjectHeader::FromPayload(gced).IsMarked());
|
|
}
|
|
|
|
TEST_F(MarkingVisitorTest, MarkPersistentInConstruction) {
|
|
TestMarkingVisitor visitor(GetMarker());
|
|
GCedWithInConstructionCallback* gced =
|
|
MakeGarbageCollected<GCedWithInConstructionCallback>(
|
|
GetAllocationHandle(),
|
|
[&visitor](GCedWithInConstructionCallback* obj) {
|
|
Persistent<GCedWithInConstructionCallback> object(obj);
|
|
visitor.TraceRootForTesting(object, SourceLocation::Current());
|
|
});
|
|
EXPECT_TRUE(HeapObjectHeader::FromPayload(gced).IsMarked());
|
|
}
|
|
|
|
TEST_F(MarkingVisitorTest, MarkPersistentMixinInConstruction) {
|
|
TestMarkingVisitor visitor(GetMarker());
|
|
GCedWithMixinWithInConstructionCallback* gced =
|
|
MakeGarbageCollected<GCedWithMixinWithInConstructionCallback>(
|
|
GetAllocationHandle(),
|
|
[&visitor](MixinWithInConstructionCallback* obj) {
|
|
Persistent<MixinWithInConstructionCallback> mixin(obj);
|
|
visitor.TraceRootForTesting(mixin, SourceLocation::Current());
|
|
});
|
|
EXPECT_TRUE(HeapObjectHeader::FromPayload(gced).IsMarked());
|
|
}
|
|
|
|
} // namespace internal
|
|
} // namespace cppgc
|