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 @@
#include "src/handles/persistent-handles.h"
#include "src/heap/embedder-tracing.h"
#include "src/heap/heap-inl.h"
#include "src/heap/heap-write-barrier.h"
#include "src/init/bootstrapper.h"
#include "src/init/icu_util.h"
#include "src/init/startup-data-util.h"
......@@ -5980,6 +5981,7 @@ void v8::Object::SetAlignedPointerInInternalField(int index, void* value) {
.store_aligned_pointer(obj->GetIsolate(), value),
location, "Unaligned pointer");
DCHECK_EQ(value, GetAlignedPointerFromInternalField(index));
internal::WriteBarrier::MarkingFromInternalFields(i::JSObject::cast(*obj));
}
void v8::Object::SetAlignedPointerInInternalFields(int argc, int indices[],
......@@ -6001,6 +6003,7 @@ void v8::Object::SetAlignedPointerInInternalFields(int argc, int indices[],
location, "Unaligned pointer");
DCHECK_EQ(value, GetAlignedPointerFromInternalField(index));
}
internal::WriteBarrier::MarkingFromInternalFields(js_obj);
}
static void* ExternalValue(i::Object obj) {
......
......@@ -275,6 +275,14 @@ void WriteBarrier::MarkingFromGlobalHandle(Object 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 v8
......
......@@ -4,9 +4,11 @@
#include "src/heap/heap-write-barrier.h"
#include "src/heap/embedder-tracing.h"
#include "src/heap/heap-write-barrier-inl.h"
#include "src/heap/marking-barrier.h"
#include "src/objects/descriptor-array.h"
#include "src/objects/js-objects.h"
#include "src/objects/maybe-object.h"
#include "src/objects/slots-inl.h"
......@@ -45,6 +47,17 @@ void WriteBarrier::MarkingSlowFromGlobalHandle(Heap* heap, HeapObject 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,
HeapObject value) {
MarkingBarrier* marking_barrier = current_marking_barrier
......
......@@ -8,6 +8,7 @@
#include "include/v8-internal.h"
#include "src/base/optional.h"
#include "src/common/globals.h"
#include "src/objects/heap-object.h"
namespace v8 {
namespace internal {
......@@ -57,6 +58,7 @@ class V8_EXPORT_PRIVATE WriteBarrier {
static int MarkingFromCode(Address raw_host, Address raw_slot);
// Invoked from global handles where no host object is available.
static inline void MarkingFromGlobalHandle(Object value);
static inline void MarkingFromInternalFields(JSObject host);
static void SetForThread(MarkingBarrier*);
static void ClearForThread(MarkingBarrier*);
......@@ -74,6 +76,7 @@ class V8_EXPORT_PRIVATE WriteBarrier {
static void MarkingSlow(Heap* heap, DescriptorArray,
int number_of_own_descriptors);
static void MarkingSlowFromGlobalHandle(Heap* heap, HeapObject value);
static void MarkingSlowFromInternalFields(Heap* heap, JSObject host);
};
} // namespace internal
......
......@@ -77,6 +77,23 @@ TEST_F(UnifiedHeapTest, FindingV8ToBlinkReference) {
}
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;
v8::HandleScope scope(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