Commit 057ffb82 authored by Michael Lippautz's avatar Michael Lippautz Committed by V8 LUCI CQ

heap: Emit write barrier when setting internal fields

Internal fields are used for implementing edges to C++ objects in
Oilpan. When setting the fields on a JS API object, we should also
emit a write barrier for this edge.

This mechanism replaces the explicit write barrier in V8's API which
is provided through `JSHeapConsistency::*`.

The internal barrier should also be slightly faster as it doesn't
require any API calls.

Bug: v8:12356
Change-Id: I639d18141acfb910d0ded8d987d8a0916e25431d
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3257709
Commit-Queue: Michael Lippautz <mlippautz@chromium.org>
Reviewed-by: 's avatarDominik Inführ <dinfuehr@chromium.org>
Cr-Commit-Position: refs/heads/main@{#77749}
parent 1ec4c334
...@@ -59,6 +59,7 @@ ...@@ -59,6 +59,7 @@
#include "src/handles/persistent-handles.h" #include "src/handles/persistent-handles.h"
#include "src/heap/embedder-tracing.h" #include "src/heap/embedder-tracing.h"
#include "src/heap/heap-inl.h" #include "src/heap/heap-inl.h"
#include "src/heap/heap-write-barrier.h"
#include "src/init/bootstrapper.h" #include "src/init/bootstrapper.h"
#include "src/init/icu_util.h" #include "src/init/icu_util.h"
#include "src/init/startup-data-util.h" #include "src/init/startup-data-util.h"
...@@ -5980,6 +5981,7 @@ void v8::Object::SetAlignedPointerInInternalField(int index, void* value) { ...@@ -5980,6 +5981,7 @@ void v8::Object::SetAlignedPointerInInternalField(int index, void* value) {
.store_aligned_pointer(obj->GetIsolate(), value), .store_aligned_pointer(obj->GetIsolate(), value),
location, "Unaligned pointer"); location, "Unaligned pointer");
DCHECK_EQ(value, GetAlignedPointerFromInternalField(index)); DCHECK_EQ(value, GetAlignedPointerFromInternalField(index));
internal::WriteBarrier::MarkingFromInternalFields(i::JSObject::cast(*obj));
} }
void v8::Object::SetAlignedPointerInInternalFields(int argc, int indices[], void v8::Object::SetAlignedPointerInInternalFields(int argc, int indices[],
...@@ -6001,6 +6003,7 @@ void v8::Object::SetAlignedPointerInInternalFields(int argc, int indices[], ...@@ -6001,6 +6003,7 @@ void v8::Object::SetAlignedPointerInInternalFields(int argc, int indices[],
location, "Unaligned pointer"); location, "Unaligned pointer");
DCHECK_EQ(value, GetAlignedPointerFromInternalField(index)); DCHECK_EQ(value, GetAlignedPointerFromInternalField(index));
} }
internal::WriteBarrier::MarkingFromInternalFields(js_obj);
} }
static void* ExternalValue(i::Object obj) { static void* ExternalValue(i::Object obj) {
......
...@@ -275,6 +275,14 @@ void WriteBarrier::MarkingFromGlobalHandle(Object value) { ...@@ -275,6 +275,14 @@ void WriteBarrier::MarkingFromGlobalHandle(Object value) {
MarkingSlowFromGlobalHandle(*heap, heap_value); MarkingSlowFromGlobalHandle(*heap, heap_value);
} }
// static
void WriteBarrier::MarkingFromInternalFields(JSObject host) {
if (V8_ENABLE_THIRD_PARTY_HEAP_BOOL) return;
auto heap = GetHeapIfMarking(host);
if (!heap) return;
MarkingSlowFromInternalFields(*heap, host);
}
} // namespace internal } // namespace internal
} // namespace v8 } // namespace v8
......
...@@ -4,9 +4,11 @@ ...@@ -4,9 +4,11 @@
#include "src/heap/heap-write-barrier.h" #include "src/heap/heap-write-barrier.h"
#include "src/heap/embedder-tracing.h"
#include "src/heap/heap-write-barrier-inl.h" #include "src/heap/heap-write-barrier-inl.h"
#include "src/heap/marking-barrier.h" #include "src/heap/marking-barrier.h"
#include "src/objects/descriptor-array.h" #include "src/objects/descriptor-array.h"
#include "src/objects/js-objects.h"
#include "src/objects/maybe-object.h" #include "src/objects/maybe-object.h"
#include "src/objects/slots-inl.h" #include "src/objects/slots-inl.h"
...@@ -45,6 +47,17 @@ void WriteBarrier::MarkingSlowFromGlobalHandle(Heap* heap, HeapObject value) { ...@@ -45,6 +47,17 @@ void WriteBarrier::MarkingSlowFromGlobalHandle(Heap* heap, HeapObject value) {
heap->marking_barrier()->WriteWithoutHost(value); heap->marking_barrier()->WriteWithoutHost(value);
} }
// static
void WriteBarrier::MarkingSlowFromInternalFields(Heap* heap, JSObject host) {
// We are not checking the mark bits of host here as (a) there's no
// synchronization with the marker and (b) we are writing into a live object
// (independent of the mark bits).
if (!heap->local_embedder_heap_tracer()->InUse()) return;
LocalEmbedderHeapTracer::ProcessingScope scope(
heap->local_embedder_heap_tracer());
scope.TracePossibleWrapper(host);
}
void WriteBarrier::MarkingSlow(Heap* heap, Code host, RelocInfo* reloc_info, void WriteBarrier::MarkingSlow(Heap* heap, Code host, RelocInfo* reloc_info,
HeapObject value) { HeapObject value) {
MarkingBarrier* marking_barrier = current_marking_barrier MarkingBarrier* marking_barrier = current_marking_barrier
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
#include "include/v8-internal.h" #include "include/v8-internal.h"
#include "src/base/optional.h" #include "src/base/optional.h"
#include "src/common/globals.h" #include "src/common/globals.h"
#include "src/objects/heap-object.h"
namespace v8 { namespace v8 {
namespace internal { namespace internal {
...@@ -57,6 +58,7 @@ class V8_EXPORT_PRIVATE WriteBarrier { ...@@ -57,6 +58,7 @@ class V8_EXPORT_PRIVATE WriteBarrier {
static int MarkingFromCode(Address raw_host, Address raw_slot); static int MarkingFromCode(Address raw_host, Address raw_slot);
// Invoked from global handles where no host object is available. // Invoked from global handles where no host object is available.
static inline void MarkingFromGlobalHandle(Object value); static inline void MarkingFromGlobalHandle(Object value);
static inline void MarkingFromInternalFields(JSObject host);
static void SetForThread(MarkingBarrier*); static void SetForThread(MarkingBarrier*);
static void ClearForThread(MarkingBarrier*); static void ClearForThread(MarkingBarrier*);
...@@ -74,6 +76,7 @@ class V8_EXPORT_PRIVATE WriteBarrier { ...@@ -74,6 +76,7 @@ class V8_EXPORT_PRIVATE WriteBarrier {
static void MarkingSlow(Heap* heap, DescriptorArray, static void MarkingSlow(Heap* heap, DescriptorArray,
int number_of_own_descriptors); int number_of_own_descriptors);
static void MarkingSlowFromGlobalHandle(Heap* heap, HeapObject value); static void MarkingSlowFromGlobalHandle(Heap* heap, HeapObject value);
static void MarkingSlowFromInternalFields(Heap* heap, JSObject host);
}; };
} // namespace internal } // namespace internal
......
...@@ -77,6 +77,23 @@ TEST_F(UnifiedHeapTest, FindingV8ToBlinkReference) { ...@@ -77,6 +77,23 @@ TEST_F(UnifiedHeapTest, FindingV8ToBlinkReference) {
} }
TEST_F(UnifiedHeapTest, WriteBarrierV8ToCppReference) { TEST_F(UnifiedHeapTest, WriteBarrierV8ToCppReference) {
if (!FLAG_incremental_marking) return;
v8::HandleScope scope(v8_isolate());
v8::Local<v8::Context> context = v8::Context::New(v8_isolate());
v8::Context::Scope context_scope(context);
void* wrappable = cppgc::MakeGarbageCollected<Wrappable>(allocation_handle());
v8::Local<v8::Object> api_object =
WrapperHelper::CreateWrapper(context, nullptr, nullptr);
Wrappable::destructor_callcount = 0;
WrapperHelper::ResetWrappableConnection(api_object);
SimulateIncrementalMarking();
uint16_t type_info = WrapperHelper::kTracedEmbedderId;
WrapperHelper::SetWrappableConnection(api_object, &type_info, wrappable);
CollectGarbageWithoutEmbedderStack(cppgc::Heap::SweepingType::kAtomic);
EXPECT_EQ(0u, Wrappable::destructor_callcount);
}
TEST_F(UnifiedHeapTest, WriteBarrierV8ToCppReferenceWithExplicitAPI) {
if (!FLAG_incremental_marking) return; if (!FLAG_incremental_marking) return;
v8::HandleScope scope(v8_isolate()); v8::HandleScope scope(v8_isolate());
v8::Local<v8::Context> context = v8::Context::New(v8_isolate()); v8::Local<v8::Context> context = v8::Context::New(v8_isolate());
......
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