Commit 0defc528 authored by Michael Lippautz's avatar Michael Lippautz Committed by Commit Bot

cppgc: Add test for handling objects conservatively

The test ensures that in-construction objects that have been found
through a write barrier are properly processed (marked + trace) when
finalizing the collection conservatively with a different stack.

This is a test for https://crrev.com/c/2744074

Bug: chromium:1056170
Change-Id: I8099bca1fb9025a315a8f0a3530aac822d1c45d2
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2745334Reviewed-by: 's avatarOmer Katz <omerkatz@chromium.org>
Commit-Queue: Michael Lippautz <mlippautz@chromium.org>
Cr-Commit-Position: refs/heads/master@{#73306}
parent e3072158
......@@ -4,10 +4,13 @@
#include "src/heap/cppgc/marker.h"
#include <memory>
#include "include/cppgc/allocation.h"
#include "include/cppgc/internal/pointer-policies.h"
#include "include/cppgc/member.h"
#include "include/cppgc/persistent.h"
#include "include/cppgc/trace-trait.h"
#include "src/heap/cppgc/heap-object-header.h"
#include "src/heap/cppgc/marking-visitor.h"
#include "src/heap/cppgc/stats-collector.h"
......@@ -212,6 +215,7 @@ TEST_F(MarkerTest, NestedObjectsOnStackAreMarked) {
}
namespace {
class GCedWithCallback : public GarbageCollected<GCedWithCallback> {
public:
template <typename Callback>
......@@ -219,8 +223,19 @@ class GCedWithCallback : public GarbageCollected<GCedWithCallback> {
callback(this);
}
void Trace(Visitor*) const {}
template <typename Callback>
GCedWithCallback(Callback callback, GCed* gced) : gced_(gced) {
callback(this);
}
void Trace(Visitor* visitor) const { visitor->Trace(gced_); }
GCed* gced() const { return gced_; }
private:
Member<GCed> gced_;
};
} // namespace
TEST_F(MarkerTest, InConstructionObjectIsEventuallyMarkedEmptyStack) {
......@@ -254,6 +269,63 @@ TEST_F(MarkerTest, InConstructionObjectIsEventuallyMarkedNonEmptyStack) {
});
}
namespace {
// Storage that can be used to hide a pointer from the GC. Only useful when
// dealing with the stack separately.
class GCObliviousObjectStorage final {
public:
GCObliviousObjectStorage()
: storage_(std::make_unique<const void*>(nullptr)) {}
template <typename T>
void set_object(T* t) {
*storage_.get() = TraceTrait<T>::GetTraceDescriptor(t).base_object_payload;
}
const void* object() const { return *storage_; }
private:
std::unique_ptr<const void*> storage_;
};
V8_NOINLINE void RegisterInConstructionObject(
AllocationHandle& allocation_handle, Visitor& v,
GCObliviousObjectStorage& storage) {
// Create deeper stack to avoid finding any temporary reference in the caller.
char space[500];
USE(space);
MakeGarbageCollected<GCedWithCallback>(
allocation_handle,
[&visitor = v, &storage](GCedWithCallback* obj) {
Member<GCedWithCallback> member(obj);
// Adds GCedWithCallback to in-construction objects.
visitor.Trace(member);
EXPECT_FALSE(HeapObjectHeader::FromPayload(obj).IsMarked());
// The inner object GCed is only found if GCedWithCallback is processed.
storage.set_object(obj->gced());
},
// Initializing store does not trigger a write barrier.
MakeGarbageCollected<GCed>(allocation_handle));
}
} // namespace
TEST_F(MarkerTest,
InConstructionObjectIsEventuallyMarkedDifferentNonEmptyStack) {
static const Marker::MarkingConfig config = {
MarkingConfig::CollectionType::kMajor,
MarkingConfig::StackState::kMayContainHeapPointers};
InitializeMarker(*Heap::From(GetHeap()), GetPlatformHandle().get(), config);
GCObliviousObjectStorage storage;
RegisterInConstructionObject(GetAllocationHandle(), marker()->Visitor(),
storage);
EXPECT_FALSE(HeapObjectHeader::FromPayload(storage.object()).IsMarked());
marker()->FinishMarking(MarkingConfig::StackState::kMayContainHeapPointers);
EXPECT_TRUE(HeapObjectHeader::FromPayload(storage.object()).IsMarked());
}
TEST_F(MarkerTest, SentinelNotClearedOnWeakPersistentHandling) {
static const Marker::MarkingConfig config = {
MarkingConfig::CollectionType::kMajor,
......@@ -290,7 +362,8 @@ class IncrementalMarkingTest : public testing::TestWithHeap {
MarkingConfig::MarkingType::kIncremental};
void FinishSteps(MarkingConfig::StackState stack_state) {
while (!SingleStep(stack_state)) {}
while (!SingleStep(stack_state)) {
}
}
void FinishMarking() {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment