cppgc-js: Add WrapperDescriptor
WrapperDescriptor is used to describe how JS wrapper objects can be inspected to find C++ wrappable objects. In addition, to specifying which embedder fields are used to find type and instance, the descriptor also provides and embedder id that identifies garbage-collected objects. It is expected that the first field of the type is a uint16_t with that id. Bug: chromium:1056170 Change-Id: I9cf8d79db972f2dea023114fd5a567e89a3bf373 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2688399 Reviewed-by: Ulan Degenbaev <ulan@chromium.org> Reviewed-by: Omer Katz <omerkatz@chromium.org> Commit-Queue: Michael Lippautz <mlippautz@chromium.org> Cr-Commit-Position: refs/heads/master@{#72657}
This commit is contained in:
parent
b1c36b2305
commit
78ffd6e875
@ -5,6 +5,7 @@
|
||||
#ifndef INCLUDE_V8_CPPGC_H_
|
||||
#define INCLUDE_V8_CPPGC_H_
|
||||
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
@ -26,8 +27,53 @@ namespace internal {
|
||||
class CppHeap;
|
||||
} // namespace internal
|
||||
|
||||
/**
|
||||
* Describes how V8 wrapper objects maintain references to garbage-collected C++
|
||||
* objects.
|
||||
*/
|
||||
struct WrapperDescriptor final {
|
||||
/**
|
||||
* The index used on `v8::Ojbect::SetAlignedPointerFromInternalField()` and
|
||||
* related APIs to add additional data to an object which is used to identify
|
||||
* JS->C++ references.
|
||||
*/
|
||||
using InternalFieldIndex = int;
|
||||
|
||||
/**
|
||||
* Unknown embedder id. The value is reserved for internal usages and must not
|
||||
* be used with `CppHeap`.
|
||||
*/
|
||||
static constexpr uint16_t kUnknownEmbedderId = UINT16_MAX;
|
||||
|
||||
constexpr WrapperDescriptor(InternalFieldIndex wrappable_type_index,
|
||||
InternalFieldIndex wrappable_instance_index,
|
||||
uint16_t embedder_id_for_garbage_collected)
|
||||
: wrappable_type_index(wrappable_type_index),
|
||||
wrappable_instance_index(wrappable_instance_index),
|
||||
embedder_id_for_garbage_collected(embedder_id_for_garbage_collected) {}
|
||||
|
||||
/**
|
||||
* Index of the wrappable type.
|
||||
*/
|
||||
InternalFieldIndex wrappable_type_index;
|
||||
|
||||
/**
|
||||
* Index of the wrappable instance.
|
||||
*/
|
||||
InternalFieldIndex wrappable_instance_index;
|
||||
|
||||
/**
|
||||
* Embedder id identifying instances of garbage-collected objects. It is
|
||||
* expected that the first field of the wrappable type is a uint16_t holding
|
||||
* the id. Only references to instances of wrappables types with an id of
|
||||
* `embedder_id_for_garbage_collected` will be considered by CppHeap.
|
||||
*/
|
||||
uint16_t embedder_id_for_garbage_collected;
|
||||
};
|
||||
|
||||
struct V8_EXPORT CppHeapCreateParams {
|
||||
std::vector<std::unique_ptr<cppgc::CustomSpaceBase>> custom_spaces;
|
||||
WrapperDescriptor wrapper_descriptor;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -30,6 +30,7 @@
|
||||
#include "src/heap/cppgc/prefinalizer-handler.h"
|
||||
#include "src/heap/cppgc/stats-collector.h"
|
||||
#include "src/heap/cppgc/sweeper.h"
|
||||
#include "src/heap/embedder-tracing.h"
|
||||
#include "src/heap/marking-worklist.h"
|
||||
#include "src/heap/sweeper.h"
|
||||
#include "src/init/v8.h"
|
||||
@ -37,10 +38,14 @@
|
||||
|
||||
namespace v8 {
|
||||
|
||||
// static
|
||||
constexpr uint16_t WrapperDescriptor::kUnknownEmbedderId;
|
||||
|
||||
// static
|
||||
std::unique_ptr<CppHeap> CppHeap::Create(v8::Platform* platform,
|
||||
const CppHeapCreateParams& params) {
|
||||
return std::make_unique<internal::CppHeap>(platform, params.custom_spaces);
|
||||
return std::make_unique<internal::CppHeap>(platform, params.custom_spaces,
|
||||
params.wrapper_descriptor);
|
||||
}
|
||||
|
||||
cppgc::AllocationHandle& CppHeap::GetAllocationHandle() {
|
||||
@ -180,12 +185,16 @@ void UnifiedHeapMarker::AddObject(void* object) {
|
||||
CppHeap::CppHeap(
|
||||
v8::Platform* platform,
|
||||
const std::vector<std::unique_ptr<cppgc::CustomSpaceBase>>& custom_spaces,
|
||||
const v8::WrapperDescriptor& wrapper_descriptor,
|
||||
std::unique_ptr<cppgc::internal::MetricRecorder> metric_recorder)
|
||||
: cppgc::internal::HeapBase(
|
||||
std::make_shared<CppgcPlatformAdapter>(platform), custom_spaces,
|
||||
cppgc::internal::HeapBase::StackSupport::
|
||||
kSupportsConservativeStackScan,
|
||||
std::move(metric_recorder)) {
|
||||
std::move(metric_recorder)),
|
||||
wrapper_descriptor_(wrapper_descriptor) {
|
||||
CHECK_NE(WrapperDescriptor::kUnknownEmbedderId,
|
||||
wrapper_descriptor_.embedder_id_for_garbage_collected);
|
||||
// Enter no GC scope. `AttachIsolate()` removes this and allows triggering
|
||||
// garbage collections.
|
||||
no_gc_scope_++;
|
||||
@ -215,6 +224,8 @@ void CppHeap::AttachIsolate(Isolate* isolate) {
|
||||
&CppGraphBuilder::Run, this);
|
||||
}
|
||||
isolate_->heap()->SetEmbedderHeapTracer(this);
|
||||
isolate_->heap()->local_embedder_heap_tracer()->SetWrapperDescriptor(
|
||||
wrapper_descriptor_);
|
||||
no_gc_scope_--;
|
||||
}
|
||||
|
||||
|
@ -34,6 +34,7 @@ class V8_EXPORT_PRIVATE CppHeap final
|
||||
CppHeap(
|
||||
v8::Platform* platform,
|
||||
const std::vector<std::unique_ptr<cppgc::CustomSpaceBase>>& custom_spaces,
|
||||
const v8::WrapperDescriptor& wrapper_descriptor,
|
||||
std::unique_ptr<cppgc::internal::MetricRecorder> metric_recorder =
|
||||
nullptr);
|
||||
~CppHeap() final;
|
||||
@ -79,6 +80,8 @@ class V8_EXPORT_PRIVATE CppHeap final
|
||||
// atomic pause. Allocated bytes are buffer in case this is temporarily
|
||||
// prohibited.
|
||||
int64_t buffered_allocated_bytes_ = 0;
|
||||
|
||||
v8::WrapperDescriptor wrapper_descriptor_;
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
|
@ -308,10 +308,10 @@ bool HasEmbedderDataBackref(Isolate* isolate, v8::Local<v8::Value> v8_value,
|
||||
return false;
|
||||
|
||||
JSObject js_object = JSObject::cast(*v8_object);
|
||||
return js_object.GetEmbedderFieldCount() >= 2 &&
|
||||
LocalEmbedderHeapTracer::VerboseWrapperInfo(
|
||||
LocalEmbedderHeapTracer::ExtractWrapperInfo(isolate, js_object))
|
||||
.instance() == expected_backref;
|
||||
return LocalEmbedderHeapTracer::VerboseWrapperInfo(
|
||||
isolate->heap()->local_embedder_heap_tracer()->ExtractWrapperInfo(
|
||||
isolate, js_object))
|
||||
.instance() == expected_backref;
|
||||
}
|
||||
|
||||
// The following implements a snapshotting algorithm for C++ objects that also
|
||||
|
@ -4,6 +4,7 @@
|
||||
|
||||
#include "src/heap/embedder-tracing.h"
|
||||
|
||||
#include "include/v8-cppgc.h"
|
||||
#include "src/base/logging.h"
|
||||
#include "src/heap/gc-tracer.h"
|
||||
#include "src/objects/embedder-data-slot.h"
|
||||
@ -74,9 +75,33 @@ void LocalEmbedderHeapTracer::SetEmbedderStackStateForNextFinalization(
|
||||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
bool ExtractWrappableInfo(Isolate* isolate, JSObject js_object,
|
||||
const WrapperDescriptor& wrapper_descriptor,
|
||||
LocalEmbedderHeapTracer::WrapperInfo* info) {
|
||||
DCHECK(js_object.IsApiWrapper());
|
||||
if (js_object.GetEmbedderFieldCount() < 2) return false;
|
||||
|
||||
if (EmbedderDataSlot(js_object, wrapper_descriptor.wrappable_type_index)
|
||||
.ToAlignedPointerSafe(isolate, &info->first) &&
|
||||
info->first &&
|
||||
EmbedderDataSlot(js_object, wrapper_descriptor.wrappable_instance_index)
|
||||
.ToAlignedPointerSafe(isolate, &info->second) &&
|
||||
info->second) {
|
||||
return (wrapper_descriptor.embedder_id_for_garbage_collected ==
|
||||
WrapperDescriptor::kUnknownEmbedderId) ||
|
||||
(*static_cast<uint16_t*>(info->first) ==
|
||||
wrapper_descriptor.embedder_id_for_garbage_collected);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
LocalEmbedderHeapTracer::ProcessingScope::ProcessingScope(
|
||||
LocalEmbedderHeapTracer* tracer)
|
||||
: tracer_(tracer) {
|
||||
: tracer_(tracer), wrapper_descriptor_(tracer->wrapper_descriptor_) {
|
||||
wrapper_cache_.reserve(kWrapperCacheSize);
|
||||
}
|
||||
|
||||
@ -86,19 +111,11 @@ LocalEmbedderHeapTracer::ProcessingScope::~ProcessingScope() {
|
||||
}
|
||||
}
|
||||
|
||||
// static
|
||||
LocalEmbedderHeapTracer::WrapperInfo
|
||||
LocalEmbedderHeapTracer::ExtractWrapperInfo(Isolate* isolate,
|
||||
JSObject js_object) {
|
||||
DCHECK_GE(js_object.GetEmbedderFieldCount(), 2);
|
||||
DCHECK(js_object.IsApiWrapper());
|
||||
|
||||
WrapperInfo info;
|
||||
if (EmbedderDataSlot(js_object, 0)
|
||||
.ToAlignedPointerSafe(isolate, &info.first) &&
|
||||
info.first &&
|
||||
EmbedderDataSlot(js_object, 1)
|
||||
.ToAlignedPointerSafe(isolate, &info.second)) {
|
||||
if (ExtractWrappableInfo(isolate, js_object, wrapper_descriptor_, &info)) {
|
||||
return info;
|
||||
}
|
||||
return {nullptr, nullptr};
|
||||
@ -107,14 +124,12 @@ LocalEmbedderHeapTracer::ExtractWrapperInfo(Isolate* isolate,
|
||||
void LocalEmbedderHeapTracer::ProcessingScope::TracePossibleWrapper(
|
||||
JSObject js_object) {
|
||||
DCHECK(js_object.IsApiWrapper());
|
||||
if (js_object.GetEmbedderFieldCount() < 2) return;
|
||||
|
||||
WrapperInfo info =
|
||||
LocalEmbedderHeapTracer::ExtractWrapperInfo(tracer_->isolate_, js_object);
|
||||
if (!VerboseWrapperInfo(info).is_empty()) {
|
||||
WrapperInfo info;
|
||||
if (ExtractWrappableInfo(tracer_->isolate_, js_object, wrapper_descriptor_,
|
||||
&info)) {
|
||||
wrapper_cache_.push_back(std::move(info));
|
||||
FlushWrapperCacheIfFull();
|
||||
}
|
||||
FlushWrapperCacheIfFull();
|
||||
}
|
||||
|
||||
void LocalEmbedderHeapTracer::ProcessingScope::FlushWrapperCacheIfFull() {
|
||||
|
@ -5,6 +5,7 @@
|
||||
#ifndef V8_HEAP_EMBEDDER_TRACING_H_
|
||||
#define V8_HEAP_EMBEDDER_TRACING_H_
|
||||
|
||||
#include "include/v8-cppgc.h"
|
||||
#include "include/v8.h"
|
||||
#include "src/common/globals.h"
|
||||
#include "src/flags/flags.h"
|
||||
@ -53,11 +54,10 @@ class V8_EXPORT_PRIVATE LocalEmbedderHeapTracer final {
|
||||
void FlushWrapperCacheIfFull();
|
||||
|
||||
LocalEmbedderHeapTracer* const tracer_;
|
||||
const WrapperDescriptor wrapper_descriptor_;
|
||||
WrapperCache wrapper_cache_;
|
||||
};
|
||||
|
||||
static WrapperInfo ExtractWrapperInfo(Isolate* isolate, JSObject js_object);
|
||||
|
||||
explicit LocalEmbedderHeapTracer(Isolate* isolate) : isolate_(isolate) {}
|
||||
|
||||
~LocalEmbedderHeapTracer() {
|
||||
@ -122,9 +122,27 @@ class V8_EXPORT_PRIVATE LocalEmbedderHeapTracer final {
|
||||
size_t used_size() const { return remote_stats_.used_size; }
|
||||
size_t allocated_size() const { return remote_stats_.allocated_size; }
|
||||
|
||||
WrapperInfo ExtractWrapperInfo(Isolate* isolate, JSObject js_object);
|
||||
|
||||
void SetWrapperDescriptor(const WrapperDescriptor& wrapper_descriptor) {
|
||||
wrapper_descriptor_ = wrapper_descriptor;
|
||||
}
|
||||
|
||||
private:
|
||||
static constexpr size_t kEmbedderAllocatedThreshold = 128 * KB;
|
||||
|
||||
static constexpr WrapperDescriptor::InternalFieldIndex
|
||||
kDefaultWrapperTypeEmbedderIndex = 0;
|
||||
static constexpr WrapperDescriptor::InternalFieldIndex
|
||||
kDefaultWrapperInstanceEmbedderIndex = 1;
|
||||
|
||||
static constexpr WrapperDescriptor GetDefaultWrapperDescriptor() {
|
||||
// The default descriptor assumes the indices that known embedders use.
|
||||
return WrapperDescriptor(kDefaultWrapperTypeEmbedderIndex,
|
||||
kDefaultWrapperInstanceEmbedderIndex,
|
||||
WrapperDescriptor::kUnknownEmbedderId);
|
||||
}
|
||||
|
||||
Isolate* const isolate_;
|
||||
EmbedderHeapTracer* remote_tracer_ = nullptr;
|
||||
|
||||
@ -148,6 +166,11 @@ class V8_EXPORT_PRIVATE LocalEmbedderHeapTracer final {
|
||||
size_t allocated_size_limit_for_check = 0;
|
||||
} remote_stats_;
|
||||
|
||||
// Default descriptor only used when the embedder is using EmbedderHeapTracer.
|
||||
// The value is overriden by CppHeap with values that the embedder provided
|
||||
// upon initialization.
|
||||
WrapperDescriptor wrapper_descriptor_ = GetDefaultWrapperDescriptor();
|
||||
|
||||
friend class EmbedderStackStateScope;
|
||||
};
|
||||
|
||||
|
@ -265,6 +265,7 @@ namespace {
|
||||
|
||||
class GCedWithJSRef : public cppgc::GarbageCollected<GCedWithJSRef> {
|
||||
public:
|
||||
static uint16_t kWrappableType;
|
||||
static constexpr const char kExpectedName[] =
|
||||
"v8::internal::(anonymous namespace)::GCedWithJSRef";
|
||||
|
||||
@ -285,8 +286,12 @@ class GCedWithJSRef : public cppgc::GarbageCollected<GCedWithJSRef> {
|
||||
private:
|
||||
TracedReference<v8::Object> v8_object_;
|
||||
};
|
||||
|
||||
constexpr const char GCedWithJSRef::kExpectedName[];
|
||||
|
||||
// static
|
||||
uint16_t GCedWithJSRef::kWrappableType = WrapperHelper::kTracedEmbedderId;
|
||||
|
||||
class V8_NODISCARD JsTestingScope {
|
||||
public:
|
||||
explicit JsTestingScope(v8::Isolate* isolate)
|
||||
@ -311,7 +316,8 @@ cppgc::Persistent<GCedWithJSRef> SetupWrapperWrappablePair(
|
||||
cppgc::Persistent<GCedWithJSRef> gc_w_js_ref =
|
||||
cppgc::MakeGarbageCollected<GCedWithJSRef>(allocation_handle);
|
||||
v8::Local<v8::Object> wrapper_object = WrapperHelper::CreateWrapper(
|
||||
testing_scope.context(), gc_w_js_ref.Get(), name);
|
||||
testing_scope.context(), &GCedWithJSRef::kWrappableType,
|
||||
gc_w_js_ref.Get(), name);
|
||||
gc_w_js_ref->SetV8Object(testing_scope.isolate(), wrapper_object);
|
||||
return std::move(gc_w_js_ref);
|
||||
}
|
||||
@ -356,7 +362,7 @@ TEST_F(UnifiedHeapSnapshotTest, MergedWrapperNode) {
|
||||
testing_scope, allocation_handle(), "MergedObject");
|
||||
gc_w_js_ref->SetWrapperClassId(1); // Any class id will do.
|
||||
v8::Local<v8::Object> next_object = WrapperHelper::CreateWrapper(
|
||||
testing_scope.context(), nullptr, "NextObject");
|
||||
testing_scope.context(), nullptr, nullptr, "NextObject");
|
||||
v8::Local<v8::Object> wrapper_object =
|
||||
gc_w_js_ref->wrapper().Get(v8_isolate());
|
||||
// Chain another object to `wrapper_object`. Since `wrapper_object` should be
|
||||
|
@ -50,8 +50,10 @@ TEST_F(UnifiedHeapTest, FindingV8ToBlinkReference) {
|
||||
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;
|
||||
v8::Local<v8::Object> api_object = WrapperHelper::CreateWrapper(
|
||||
context, cppgc::MakeGarbageCollected<Wrappable>(allocation_handle()));
|
||||
context, &wrappable_type,
|
||||
cppgc::MakeGarbageCollected<Wrappable>(allocation_handle()));
|
||||
Wrappable::destructor_callcount = 0;
|
||||
EXPECT_FALSE(api_object.IsEmpty());
|
||||
EXPECT_EQ(0u, Wrappable::destructor_callcount);
|
||||
@ -68,7 +70,7 @@ TEST_F(UnifiedHeapTest, WriteBarrierV8ToCppReference) {
|
||||
v8::Context::Scope context_scope(context);
|
||||
void* wrappable = cppgc::MakeGarbageCollected<Wrappable>(allocation_handle());
|
||||
v8::Local<v8::Object> api_object =
|
||||
WrapperHelper::CreateWrapper(context, wrappable);
|
||||
WrapperHelper::CreateWrapper(context, nullptr, nullptr);
|
||||
Wrappable::destructor_callcount = 0;
|
||||
WrapperHelper::ResetWrappableConnection(api_object);
|
||||
SimulateIncrementalMarking();
|
||||
@ -103,7 +105,7 @@ TEST_F(UnifiedHeapTest, WriteBarrierCppToV8Reference) {
|
||||
// setter for C++ to JS references.
|
||||
v8::HandleScope nested_scope(v8_isolate());
|
||||
v8::Local<v8::Object> api_object =
|
||||
WrapperHelper::CreateWrapper(context, nullptr);
|
||||
WrapperHelper::CreateWrapper(context, nullptr, nullptr);
|
||||
// Setting only one field to avoid treating this as wrappable backref, see
|
||||
// `LocalEmbedderHeapTracer::ExtractWrapperInfo`.
|
||||
api_object->SetAlignedPointerInInternalField(1, kMagicAddress);
|
||||
@ -123,8 +125,9 @@ TEST_F(UnifiedHeapTest, WriteBarrierCppToV8Reference) {
|
||||
}
|
||||
|
||||
TEST_F(UnifiedHeapDetachedTest, AllocationBeforeConfigureHeap) {
|
||||
auto heap =
|
||||
v8::CppHeap::Create(V8::GetCurrentPlatform(), CppHeapCreateParams{});
|
||||
auto heap = v8::CppHeap::Create(
|
||||
V8::GetCurrentPlatform(),
|
||||
CppHeapCreateParams{{}, WrapperHelper::DefaultWrapperDescriptor()});
|
||||
auto* object =
|
||||
cppgc::MakeGarbageCollected<Wrappable>(heap->GetAllocationHandle());
|
||||
cppgc::WeakPersistent<Wrappable> weak_holder{object};
|
||||
|
@ -15,8 +15,9 @@ namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
UnifiedHeapTest::UnifiedHeapTest()
|
||||
: cpp_heap_(v8::CppHeap::Create(V8::GetCurrentPlatform(),
|
||||
CppHeapCreateParams{})) {
|
||||
: cpp_heap_(v8::CppHeap::Create(
|
||||
V8::GetCurrentPlatform(),
|
||||
CppHeapCreateParams{{}, WrapperHelper::DefaultWrapperDescriptor()})) {
|
||||
isolate()->heap()->AttachCppHeap(cpp_heap_.get());
|
||||
}
|
||||
|
||||
@ -50,8 +51,8 @@ cppgc::AllocationHandle& UnifiedHeapTest::allocation_handle() {
|
||||
|
||||
// static
|
||||
v8::Local<v8::Object> WrapperHelper::CreateWrapper(
|
||||
v8::Local<v8::Context> context, void* wrappable_object,
|
||||
const char* class_name) {
|
||||
v8::Local<v8::Context> context, void* wrappable_type,
|
||||
void* wrappable_object, const char* class_name) {
|
||||
v8::EscapableHandleScope scope(context->GetIsolate());
|
||||
v8::Local<v8::FunctionTemplate> function_t =
|
||||
v8::FunctionTemplate::New(context->GetIsolate());
|
||||
@ -66,8 +67,7 @@ v8::Local<v8::Object> WrapperHelper::CreateWrapper(
|
||||
function_t->GetFunction(context).ToLocalChecked();
|
||||
v8::Local<v8::Object> instance =
|
||||
function->NewInstance(context).ToLocalChecked();
|
||||
instance->SetAlignedPointerInInternalField(0, wrappable_object);
|
||||
instance->SetAlignedPointerInInternalField(1, wrappable_object);
|
||||
SetWrappableConnection(instance, wrappable_type, wrappable_object);
|
||||
CHECK(!instance.IsEmpty());
|
||||
i::Handle<i::JSReceiver> js_obj = v8::Utils::OpenHandle(*instance);
|
||||
CHECK_EQ(i::JS_API_OBJECT_TYPE, js_obj->map().instance_type());
|
||||
@ -76,15 +76,19 @@ v8::Local<v8::Object> WrapperHelper::CreateWrapper(
|
||||
|
||||
// static
|
||||
void WrapperHelper::ResetWrappableConnection(v8::Local<v8::Object> api_object) {
|
||||
api_object->SetAlignedPointerInInternalField(0, nullptr);
|
||||
api_object->SetAlignedPointerInInternalField(1, nullptr);
|
||||
api_object->SetAlignedPointerInInternalField(kWrappableTypeEmbedderIndex,
|
||||
nullptr);
|
||||
api_object->SetAlignedPointerInInternalField(kWrappableInstanceEmbedderIndex,
|
||||
nullptr);
|
||||
}
|
||||
|
||||
// static
|
||||
void WrapperHelper::SetWrappableConnection(v8::Local<v8::Object> api_object,
|
||||
void* field1, void* field2) {
|
||||
api_object->SetAlignedPointerInInternalField(0, field1);
|
||||
api_object->SetAlignedPointerInInternalField(1, field2);
|
||||
void* type, void* instance) {
|
||||
api_object->SetAlignedPointerInInternalField(kWrappableTypeEmbedderIndex,
|
||||
type);
|
||||
api_object->SetAlignedPointerInInternalField(kWrappableInstanceEmbedderIndex,
|
||||
instance);
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
|
@ -6,6 +6,7 @@
|
||||
#define V8_UNITTESTS_HEAP_UNIFIED_HEAP_UTILS_H_
|
||||
|
||||
#include "include/cppgc/heap.h"
|
||||
#include "include/v8-cppgc.h"
|
||||
#include "include/v8.h"
|
||||
#include "test/unittests/heap/heap-utils.h"
|
||||
|
||||
@ -37,10 +38,22 @@ class UnifiedHeapTest : public TestWithHeapInternals {
|
||||
|
||||
class WrapperHelper {
|
||||
public:
|
||||
static constexpr size_t kWrappableTypeEmbedderIndex = 0;
|
||||
static constexpr size_t kWrappableInstanceEmbedderIndex = 1;
|
||||
// Id that identifies types that should be traced.
|
||||
static constexpr uint16_t kTracedEmbedderId = uint16_t{0xA50F};
|
||||
|
||||
static constexpr WrapperDescriptor DefaultWrapperDescriptor() {
|
||||
return WrapperDescriptor(kWrappableTypeEmbedderIndex,
|
||||
kWrappableInstanceEmbedderIndex,
|
||||
kTracedEmbedderId);
|
||||
}
|
||||
|
||||
// Sets up a V8 API object so that it points back to a C++ object. The setup
|
||||
// used is recognized by the GC and references will be followed for liveness
|
||||
// analysis (marking) as well as tooling (snapshot).
|
||||
static v8::Local<v8::Object> CreateWrapper(v8::Local<v8::Context> context,
|
||||
void* wrappable_type,
|
||||
void* wrappable_object,
|
||||
const char* class_name = "");
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user