580917d252
This reverts commit d3a72e3c2a
.
Reason for revert: MSAN failures (https://ci.chromium.org/p/v8/builders/ci/V8%20Linux%20-%20arm64%20-%20sim%20-%20MSAN/32360)
Original change's description:
> cppgc: Stack scanning using ObjectStartBitmap
>
> This CL implements stack scanning for cppgc.
> Given a value on the stack, the MarkingVisitor uses
> PageBackend::Lookup to checks whether that address is on
> the heap. If it is, BasePage::TryObjectHeaderFromInnerAddress
> (introduced in this CL) is used to get the relevant object
> header. Note that random addresses on the heap might point to
> free memory, object-start-bitmap, etc.
>
> If a valid object header is found:
> * If the object is not in construction, the GCInfoIndex is used
> the get the relevant Trace method and the object is traced.
> * Otherwise, the object is conservatively scanned - i.e. the
> payload of the object is iterated word by word and each word is
> treated as a possible pointer.
>
> Only addresses pointing to the payload on non-free objects are
> traced.
>
> BasePage::TryObjectHeaderFromInnerAddress assumes on LAB on the
> relevant space, thus all LABs are reset before scanning the stack.
>
> Bug: chromium:1056170
> Change-Id: I172850f6f1bbb6f0efca8e44ad8fdfe222977b9f
> Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2190426
> Commit-Queue: Omer Katz <omerkatz@chromium.org>
> Reviewed-by: Michael Lippautz <mlippautz@chromium.org>
> Reviewed-by: Ulan Degenbaev <ulan@chromium.org>
> Reviewed-by: Anton Bikineev <bikineev@chromium.org>
> Cr-Commit-Position: refs/heads/master@{#67795}
TBR=ulan@chromium.org,mlippautz@chromium.org,bikineev@chromium.org,omerkatz@chromium.org
Change-Id: I3caef6f9f55911fd1a86e895c3495d1b98b1eac2
No-Presubmit: true
No-Tree-Checks: true
No-Try: true
Bug: chromium:1056170
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2201136
Reviewed-by: Leszek Swirski <leszeks@chromium.org>
Commit-Queue: Leszek Swirski <leszeks@chromium.org>
Cr-Commit-Position: refs/heads/master@{#67796}
189 lines
6.3 KiB
C++
189 lines
6.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 "src/heap/cppgc/marker.h"
|
|
|
|
#include "include/cppgc/allocation.h"
|
|
#include "include/cppgc/member.h"
|
|
#include "include/cppgc/persistent.h"
|
|
#include "src/heap/cppgc/heap-object-header-inl.h"
|
|
#include "test/unittests/heap/cppgc/tests.h"
|
|
#include "testing/gtest/include/gtest/gtest.h"
|
|
|
|
namespace cppgc {
|
|
namespace internal {
|
|
|
|
namespace {
|
|
|
|
class MarkerTest : public testing::TestWithHeap {
|
|
public:
|
|
using MarkingConfig = Marker::MarkingConfig;
|
|
|
|
void DoMarking(MarkingConfig config) {
|
|
Marker marker(Heap::From(GetHeap()));
|
|
marker.StartMarking(config);
|
|
marker.FinishMarking();
|
|
marker.ProcessWeakness();
|
|
}
|
|
};
|
|
|
|
class GCed : public GarbageCollected<GCed> {
|
|
public:
|
|
void SetChild(GCed* child) { child_ = child; }
|
|
void SetWeakChild(GCed* child) { weak_child_ = child; }
|
|
GCed* child() const { return child_.Get(); }
|
|
GCed* weak_child() const { return weak_child_.Get(); }
|
|
void Trace(cppgc::Visitor* visitor) const {
|
|
visitor->Trace(child_);
|
|
visitor->Trace(weak_child_);
|
|
}
|
|
|
|
private:
|
|
Member<GCed> child_;
|
|
WeakMember<GCed> weak_child_;
|
|
};
|
|
|
|
template <typename T>
|
|
V8_NOINLINE T access(volatile const T& t) {
|
|
return t;
|
|
}
|
|
|
|
} // namespace
|
|
|
|
TEST_F(MarkerTest, PersistentIsMarked) {
|
|
Persistent<GCed> object = MakeGarbageCollected<GCed>(GetHeap());
|
|
HeapObjectHeader& header = HeapObjectHeader::FromPayload(object);
|
|
EXPECT_FALSE(header.IsMarked());
|
|
DoMarking(MarkingConfig(MarkingConfig::StackState::kNoHeapPointers));
|
|
EXPECT_TRUE(header.IsMarked());
|
|
}
|
|
|
|
TEST_F(MarkerTest, ReachableMemberIsMarked) {
|
|
Persistent<GCed> parent = MakeGarbageCollected<GCed>(GetHeap());
|
|
parent->SetChild(MakeGarbageCollected<GCed>(GetHeap()));
|
|
HeapObjectHeader& header = HeapObjectHeader::FromPayload(parent->child());
|
|
EXPECT_FALSE(header.IsMarked());
|
|
DoMarking(MarkingConfig(MarkingConfig::StackState::kNoHeapPointers));
|
|
EXPECT_TRUE(header.IsMarked());
|
|
}
|
|
|
|
TEST_F(MarkerTest, UnreachableMemberIsNotMarked) {
|
|
Member<GCed> object = MakeGarbageCollected<GCed>(GetHeap());
|
|
HeapObjectHeader& header = HeapObjectHeader::FromPayload(object);
|
|
EXPECT_FALSE(header.IsMarked());
|
|
DoMarking(MarkingConfig(MarkingConfig::StackState::kNoHeapPointers));
|
|
EXPECT_FALSE(header.IsMarked());
|
|
}
|
|
|
|
TEST_F(MarkerTest, ObjectReachableFromStackIsMarked) {
|
|
GCed* object = MakeGarbageCollected<GCed>(GetHeap());
|
|
EXPECT_FALSE(HeapObjectHeader::FromPayload(object).IsMarked());
|
|
DoMarking(MarkingConfig(MarkingConfig::StackState::kMayContainHeapPointers));
|
|
EXPECT_TRUE(HeapObjectHeader::FromPayload(object).IsMarked());
|
|
access(object);
|
|
}
|
|
|
|
TEST_F(MarkerTest, ObjectReachableOnlyFromStackIsNotMarkedIfStackIsEmpty) {
|
|
GCed* object = MakeGarbageCollected<GCed>(GetHeap());
|
|
HeapObjectHeader& header = HeapObjectHeader::FromPayload(object);
|
|
EXPECT_FALSE(header.IsMarked());
|
|
DoMarking(MarkingConfig(MarkingConfig::StackState::kNoHeapPointers));
|
|
EXPECT_FALSE(header.IsMarked());
|
|
access(object);
|
|
}
|
|
|
|
TEST_F(MarkerTest, WeakReferenceToUnreachableObjectIsCleared) {
|
|
{
|
|
WeakPersistent<GCed> weak_object = MakeGarbageCollected<GCed>(GetHeap());
|
|
EXPECT_TRUE(weak_object);
|
|
DoMarking(MarkingConfig(MarkingConfig::StackState::kNoHeapPointers));
|
|
EXPECT_FALSE(weak_object);
|
|
}
|
|
{
|
|
Persistent<GCed> parent = MakeGarbageCollected<GCed>(GetHeap());
|
|
parent->SetWeakChild(MakeGarbageCollected<GCed>(GetHeap()));
|
|
EXPECT_TRUE(parent->weak_child());
|
|
DoMarking(MarkingConfig(MarkingConfig::StackState::kNoHeapPointers));
|
|
EXPECT_FALSE(parent->weak_child());
|
|
}
|
|
}
|
|
|
|
TEST_F(MarkerTest, WeakReferenceToReachableObjectIsNotCleared) {
|
|
// Reachable from Persistent
|
|
{
|
|
Persistent<GCed> object = MakeGarbageCollected<GCed>(GetHeap());
|
|
WeakPersistent<GCed> weak_object(object);
|
|
EXPECT_TRUE(weak_object);
|
|
DoMarking(MarkingConfig(MarkingConfig::StackState::kNoHeapPointers));
|
|
EXPECT_TRUE(weak_object);
|
|
}
|
|
{
|
|
Persistent<GCed> object = MakeGarbageCollected<GCed>(GetHeap());
|
|
Persistent<GCed> parent = MakeGarbageCollected<GCed>(GetHeap());
|
|
parent->SetWeakChild(object);
|
|
EXPECT_TRUE(parent->weak_child());
|
|
DoMarking(MarkingConfig(MarkingConfig::StackState::kNoHeapPointers));
|
|
EXPECT_TRUE(parent->weak_child());
|
|
}
|
|
// Reachable from Member
|
|
{
|
|
Persistent<GCed> parent = MakeGarbageCollected<GCed>(GetHeap());
|
|
WeakPersistent<GCed> weak_object(MakeGarbageCollected<GCed>(GetHeap()));
|
|
parent->SetChild(weak_object);
|
|
EXPECT_TRUE(weak_object);
|
|
DoMarking(MarkingConfig(MarkingConfig::StackState::kNoHeapPointers));
|
|
EXPECT_TRUE(weak_object);
|
|
}
|
|
{
|
|
Persistent<GCed> parent = MakeGarbageCollected<GCed>(GetHeap());
|
|
parent->SetChild(MakeGarbageCollected<GCed>(GetHeap()));
|
|
parent->SetWeakChild(parent->child());
|
|
EXPECT_TRUE(parent->weak_child());
|
|
DoMarking(MarkingConfig(MarkingConfig::StackState::kNoHeapPointers));
|
|
EXPECT_TRUE(parent->weak_child());
|
|
}
|
|
// Reachable from stack
|
|
{
|
|
GCed* object = MakeGarbageCollected<GCed>(GetHeap());
|
|
WeakPersistent<GCed> weak_object(object);
|
|
EXPECT_TRUE(weak_object);
|
|
DoMarking(
|
|
MarkingConfig(MarkingConfig::StackState::kMayContainHeapPointers));
|
|
EXPECT_TRUE(weak_object);
|
|
access(object);
|
|
}
|
|
{
|
|
GCed* object = MakeGarbageCollected<GCed>(GetHeap());
|
|
Persistent<GCed> parent = MakeGarbageCollected<GCed>(GetHeap());
|
|
parent->SetWeakChild(object);
|
|
EXPECT_TRUE(parent->weak_child());
|
|
DoMarking(
|
|
MarkingConfig(MarkingConfig::StackState::kMayContainHeapPointers));
|
|
EXPECT_TRUE(parent->weak_child());
|
|
access(object);
|
|
}
|
|
}
|
|
|
|
TEST_F(MarkerTest, DeepHierarchyIsMarked) {
|
|
static constexpr int kHierarchyDepth = 10;
|
|
Persistent<GCed> root = MakeGarbageCollected<GCed>(GetHeap());
|
|
GCed* parent = root;
|
|
for (int i = 0; i < kHierarchyDepth; ++i) {
|
|
parent->SetChild(MakeGarbageCollected<GCed>(GetHeap()));
|
|
parent->SetWeakChild(parent->child());
|
|
parent = parent->child();
|
|
}
|
|
DoMarking(MarkingConfig(MarkingConfig::StackState::kNoHeapPointers));
|
|
EXPECT_TRUE(HeapObjectHeader::FromPayload(root).IsMarked());
|
|
parent = root;
|
|
for (int i = 0; i < kHierarchyDepth; ++i) {
|
|
EXPECT_TRUE(HeapObjectHeader::FromPayload(parent->child()).IsMarked());
|
|
EXPECT_TRUE(parent->weak_child());
|
|
parent = parent->child();
|
|
}
|
|
}
|
|
|
|
} // namespace internal
|
|
} // namespace cppgc
|