unified-young-gen: Trace cross-heap references

The CL enables the marking visitor in CppGC to trace
v8::TracedReferences (by just reusing the unified heap visitor from the
full GC). In addition, it specifies VisitJSApiObject for
NewSpaceVisitors to be able to trace wrappers from Minor MC in case
--cppgc-young-generation is enabled.

Bug: v8:13475
Change-Id: I04ba1f2a22e05caebf53dc8d64f2488c42ab8579
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/4026896
Commit-Queue: Anton Bikineev <bikineev@chromium.org>
Reviewed-by: Omer Katz <omerkatz@chromium.org>
Cr-Commit-Position: refs/heads/main@{#84313}
This commit is contained in:
Anton Bikineev 2022-11-16 18:42:09 +01:00 committed by V8 LUCI CQ
parent 47aaddc508
commit 43f03448d3
9 changed files with 115 additions and 51 deletions

View File

@ -220,12 +220,8 @@ class UnifiedHeapConcurrentMarker
std::unique_ptr<cppgc::Visitor>
UnifiedHeapConcurrentMarker::CreateConcurrentMarkingVisitor(
cppgc::internal::ConcurrentMarkingState& marking_state) const {
if (collection_type_ == CppHeap::CollectionType::kMajor)
return std::make_unique<ConcurrentUnifiedHeapMarkingVisitor>(
heap(), v8_heap_, marking_state);
else
return std::make_unique<ConcurrentMinorGCMarkingVisitor>(heap(), v8_heap_,
marking_state);
heap(), v8_heap_, marking_state, collection_type_);
}
void FatalOutOfMemoryHandlerImpl(const std::string& reason,
@ -312,13 +308,8 @@ UnifiedHeapMarker::UnifiedHeapMarker(Heap* v8_heap,
cppgc::internal::MarkingConfig config)
: cppgc::internal::MarkerBase(heap, platform, config),
mutator_unified_heap_marking_state_(v8_heap, nullptr),
marking_visitor_(config.collection_type == CppHeap::CollectionType::kMajor
? std::make_unique<MutatorUnifiedHeapMarkingVisitor>(
heap, mutator_marking_state_,
mutator_unified_heap_marking_state_)
: std::make_unique<MutatorMinorGCMarkingVisitor>(
heap, mutator_marking_state_,
mutator_unified_heap_marking_state_)),
marking_visitor_(std::make_unique<MutatorUnifiedHeapMarkingVisitor>(
heap, mutator_marking_state_, mutator_unified_heap_marking_state_)),
conservative_marking_visitor_(heap, mutator_marking_state_,
*marking_visitor_) {
concurrent_marker_ = std::make_unique<UnifiedHeapConcurrentMarker>(
@ -686,6 +677,18 @@ void CppHeap::InitializeTracing(CollectionType collection_type,
marking_config);
}
namespace {
MarkingWorklists::Local* GetV8MarkingWorklists(
Isolate* isolate, cppgc::internal::CollectionType collection_type) {
auto* heap = isolate->heap();
if (collection_type == cppgc::internal::CollectionType::kMajor) {
return heap->mark_compact_collector()->local_marking_worklists();
} else {
return heap->minor_mark_compact_collector()->local_marking_worklists();
}
}
} // namespace
void CppHeap::StartTracing() {
if (!TracingInitialized()) return;
if (isolate_) {
@ -695,9 +698,7 @@ void CppHeap::StartTracing() {
marker_.get()
->To<UnifiedHeapMarker>()
.GetMutatorUnifiedHeapMarkingState()
.Update(isolate_->heap()
->mark_compact_collector()
->local_marking_worklists());
.Update(GetV8MarkingWorklists(isolate_, *collection_type_));
}
marker_->StartMarking();
marking_done_ = false;
@ -742,11 +743,11 @@ void CppHeap::EnterFinalPause(cppgc::EmbedderStackState stack_state) {
auto& marker = marker_.get()->To<UnifiedHeapMarker>();
// Scan global handles conservatively in case we are attached to an Isolate.
// TODO(1029379): Support global handle marking visitors with minor GC.
if (isolate_ && !generational_gc_supported()) {
if (isolate_) {
auto& heap = *isolate()->heap();
marker.conservative_visitor().SetConservativeTracedHandlesMarkingVisitor(
std::make_unique<ConservativeTracedHandlesMarkingVisitor>(
heap, *heap.mark_compact_collector()->local_marking_worklists()));
heap, *GetV8MarkingWorklists(isolate_, *collection_type_)));
}
marker.EnterAtomicPause(stack_state);
compactor_.CancelIfShouldNotCompact(MarkingType::kAtomic, stack_state);

View File

@ -14,6 +14,18 @@
namespace v8 {
namespace internal {
namespace {
std::unique_ptr<MarkingWorklists::Local> GetV8MarkingWorklists(
Heap* heap, cppgc::internal::CollectionType collection_type) {
if (!heap) return {};
auto* worklist =
(collection_type == cppgc::internal::CollectionType::kMajor)
? heap->mark_compact_collector()->marking_worklists()
: heap->minor_mark_compact_collector()->marking_worklists();
return std::make_unique<MarkingWorklists::Local>(worklist);
}
} // namespace
UnifiedHeapMarkingVisitorBase::UnifiedHeapMarkingVisitorBase(
HeapBase& heap, cppgc::internal::BasicMarkingState& marking_state,
UnifiedHeapMarkingState& unified_heap_marking_state)
@ -67,13 +79,11 @@ MutatorUnifiedHeapMarkingVisitor::MutatorUnifiedHeapMarkingVisitor(
ConcurrentUnifiedHeapMarkingVisitor::ConcurrentUnifiedHeapMarkingVisitor(
HeapBase& heap, Heap* v8_heap,
cppgc::internal::ConcurrentMarkingState& marking_state)
cppgc::internal::ConcurrentMarkingState& marking_state,
CppHeap::CollectionType collectione_type)
: UnifiedHeapMarkingVisitorBase(heap, marking_state,
concurrent_unified_heap_marking_state_),
local_marking_worklist_(
v8_heap ? std::make_unique<MarkingWorklists::Local>(
v8_heap->mark_compact_collector()->marking_worklists())
: nullptr),
local_marking_worklist_(GetV8MarkingWorklists(v8_heap, collectione_type)),
concurrent_unified_heap_marking_state_(v8_heap,
local_marking_worklist_.get()) {}

View File

@ -67,23 +67,12 @@ class V8_EXPORT_PRIVATE MutatorUnifiedHeapMarkingVisitor
~MutatorUnifiedHeapMarkingVisitor() override = default;
};
class V8_EXPORT_PRIVATE MutatorMinorGCMarkingVisitor final
: public MutatorUnifiedHeapMarkingVisitor {
public:
using MutatorUnifiedHeapMarkingVisitor::MutatorUnifiedHeapMarkingVisitor;
~MutatorMinorGCMarkingVisitor() override = default;
protected:
// Override and make the function empty, since we don't want to trace V8
// reference during cppgc's minor GC.
void Visit(const TracedReferenceBase&) final {}
};
class V8_EXPORT_PRIVATE ConcurrentUnifiedHeapMarkingVisitor
: public UnifiedHeapMarkingVisitorBase {
public:
ConcurrentUnifiedHeapMarkingVisitor(HeapBase&, Heap*,
cppgc::internal::ConcurrentMarkingState&);
cppgc::internal::ConcurrentMarkingState&,
CppHeap::CollectionType);
~ConcurrentUnifiedHeapMarkingVisitor() override;
protected:
@ -100,20 +89,6 @@ class V8_EXPORT_PRIVATE ConcurrentUnifiedHeapMarkingVisitor
UnifiedHeapMarkingState concurrent_unified_heap_marking_state_;
};
// Same visitor as for full GCs unified heap, but avoids visiting
// TracedReferences.
class V8_EXPORT_PRIVATE ConcurrentMinorGCMarkingVisitor final
: public ConcurrentUnifiedHeapMarkingVisitor {
public:
using ConcurrentUnifiedHeapMarkingVisitor::
ConcurrentUnifiedHeapMarkingVisitor;
private:
// Override and make the function empty, since we don't want to trace V8
// reference during cppgc's minor GC.
void Visit(const TracedReferenceBase&) final {}
};
} // namespace internal
} // namespace v8

View File

@ -592,6 +592,23 @@ int YoungGenerationMarkingVisitorBase<
return size;
}
template <typename ConcreteVisitor, typename MarkingState>
int YoungGenerationMarkingVisitorBase<
ConcreteVisitor, MarkingState>::VisitJSApiObject(Map map, JSObject object) {
if (!worklists_local_->SupportsExtractWrapper())
return this->VisitJSObject(map, object);
if (!concrete_visitor()->ShouldVisit(object)) return 0;
MarkingWorklists::Local::WrapperSnapshot wrapper_snapshot;
const bool valid_snapshot =
worklists_local_->ExtractWrapper(map, object, wrapper_snapshot);
const int size = concrete_visitor()->VisitJSObjectSubclass(map, object);
if (size && valid_snapshot) {
// Success: The object needs to be processed for embedder references.
worklists_local_->PushExtractedWrapper(wrapper_snapshot);
}
return size;
}
template <typename ConcreteVisitor, typename MarkingState>
void YoungGenerationMarkingVisitorBase<ConcreteVisitor, MarkingState>::
MarkObjectViaMarkingWorklist(HeapObject object) {

View File

@ -244,6 +244,8 @@ class YoungGenerationMarkingVisitorBase
V8_INLINE int VisitJSArrayBuffer(Map map, JSArrayBuffer object);
V8_INLINE int VisitJSApiObject(Map map, JSObject object);
protected:
ConcreteVisitor* concrete_visitor() {
return static_cast<ConcreteVisitor*>(this);

View File

@ -216,7 +216,7 @@ template <typename ConcreteVisitor>
int NewSpaceVisitor<ConcreteVisitor>::VisitJSApiObject(Map map,
JSObject object) {
ConcreteVisitor* visitor = static_cast<ConcreteVisitor*>(this);
return visitor->VisitJSObject(map, object);
return visitor->VisitJSApiObject(map, object);
}
template <typename ConcreteVisitor>
@ -233,6 +233,16 @@ int NewSpaceVisitor<ConcreteVisitor>::VisitWeakCell(Map map,
return 0;
}
template <typename ConcreteVisitor>
template <typename T, typename TBodyDescriptor>
int NewSpaceVisitor<ConcreteVisitor>::VisitJSObjectSubclass(Map map, T object) {
if (!this->ShouldVisit(object)) return 0;
this->VisitMapPointer(object);
int size = TBodyDescriptor::SizeOf(map, object);
TBodyDescriptor::IterateBody(map, object, size, this);
return size;
}
} // namespace internal
} // namespace v8

View File

@ -148,6 +148,9 @@ class NewSpaceVisitor : public HeapVisitor<int, ConcreteVisitor> {
int VisitSharedFunctionInfo(Map map, SharedFunctionInfo object);
int VisitWeakCell(Map map, WeakCell weak_cell);
template <typename T, typename TBodyDescriptor = typename T::BodyDescriptor>
int VisitJSObjectSubclass(Map map, T object);
};
class WeakObjectRetainer;

View File

@ -479,6 +479,7 @@ class ScavengeVisitor final : public NewSpaceVisitor<ScavengeVisitor> {
V8_INLINE void VisitEmbeddedPointer(Code host, RelocInfo* rinfo) final;
V8_INLINE int VisitEphemeronHashTable(Map map, EphemeronHashTable object);
V8_INLINE int VisitJSArrayBuffer(Map map, JSArrayBuffer object);
V8_INLINE int VisitJSApiObject(Map map, JSObject object);
private:
template <typename TSlot>
@ -559,6 +560,10 @@ int ScavengeVisitor::VisitJSArrayBuffer(Map map, JSArrayBuffer object) {
return size;
}
int ScavengeVisitor::VisitJSApiObject(Map map, JSObject object) {
return VisitJSObject(map, object);
}
int ScavengeVisitor::VisitEphemeronHashTable(Map map,
EphemeronHashTable table) {
// Register table with the scavenger, so it can take care of the weak keys

View File

@ -87,6 +87,47 @@ TEST_F(YoungUnifiedHeapTest, CollectUnreachableCppGCObject) {
EXPECT_EQ(1u, Wrappable::destructor_callcount);
}
TEST_F(YoungUnifiedHeapTest, FindingV8ToCppGCReference) {
v8::HandleScope scope(v8_isolate());
v8::Local<v8::Context> context = v8::Context::New(v8_isolate());
v8::Context::Scope context_scope(context);
uint16_t wrappable_type = WrapperHelper::kTracedEmbedderId;
auto* wrappable_object =
cppgc::MakeGarbageCollected<Wrappable>(allocation_handle());
v8::Local<v8::Object> api_object =
WrapperHelper::CreateWrapper(context, &wrappable_type, wrappable_object);
EXPECT_FALSE(api_object.IsEmpty());
Wrappable::destructor_callcount = 0;
CollectYoungGarbageWithoutEmbedderStack(cppgc::Heap::SweepingType::kAtomic);
EXPECT_EQ(0u, Wrappable::destructor_callcount);
WrapperHelper::ResetWrappableConnection(api_object);
CollectGarbageWithoutEmbedderStack(cppgc::Heap::SweepingType::kAtomic);
EXPECT_EQ(1u, Wrappable::destructor_callcount);
}
TEST_F(YoungUnifiedHeapTest, FindingCppGCToV8Reference) {
v8::HandleScope handle_scope(v8_isolate());
v8::Local<v8::Context> context = v8::Context::New(v8_isolate());
v8::Context::Scope context_scope(context);
auto* wrappable_object =
cppgc::MakeGarbageCollected<Wrappable>(allocation_handle());
{
v8::HandleScope inner_handle_scope(v8_isolate());
auto local = v8::Object::New(v8_isolate());
EXPECT_TRUE(local->IsObject());
wrappable_object->SetWrapper(v8_isolate(), local);
}
CollectYoungGarbageWithEmbedderStack(cppgc::Heap::SweepingType::kAtomic);
auto local = wrappable_object->wrapper().Get(v8_isolate());
EXPECT_TRUE(local->IsObject());
}
} // namespace internal
} // namespace v8