Skip to content

Commit 0be79f4

Browse files
joyeecheungtargos
authored andcommitted
src: remove dependency on wrapper-descriptor-based CppHeap
As V8 has moved away from wrapper-descriptor-based CppHeap, this patch: 1. Create the CppHeap without using wrapper descirptors. 2. Deprecates node::SetCppgcReference() in favor of v8::Object::Wrap() since the wrapper descriptor is no longer relevant. It is still kept as a compatibility layer for addons that need to also work on Node.js versions without v8::Object::Wrap(). PR-URL: #54077 Reviewed-By: Jiawen Geng <technicalcute@gmail.com> Reviewed-By: Richard Lau <rlau@redhat.com> Reviewed-By: Joyee Cheung <joyeec9h3@gmail.com> Reviewed-By: Marco Ippolito <marcoippolito54@gmail.com>
1 parent 8044051 commit 0be79f4

File tree

6 files changed

+45
-104
lines changed

6 files changed

+45
-104
lines changed

src/env-inl.h

Lines changed: 0 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -62,31 +62,6 @@ inline uv_loop_t* IsolateData::event_loop() const {
6262
return event_loop_;
6363
}
6464

65-
inline void IsolateData::SetCppgcReference(v8::Isolate* isolate,
66-
v8::Local<v8::Object> object,
67-
void* wrappable) {
68-
v8::CppHeap* heap = isolate->GetCppHeap();
69-
CHECK_NOT_NULL(heap);
70-
v8::WrapperDescriptor descriptor = heap->wrapper_descriptor();
71-
uint16_t required_size = std::max(descriptor.wrappable_instance_index,
72-
descriptor.wrappable_type_index);
73-
CHECK_GT(object->InternalFieldCount(), required_size);
74-
75-
uint16_t* id_ptr = nullptr;
76-
{
77-
Mutex::ScopedLock lock(isolate_data_mutex_);
78-
auto it =
79-
wrapper_data_map_.find(descriptor.embedder_id_for_garbage_collected);
80-
CHECK_NE(it, wrapper_data_map_.end());
81-
id_ptr = &(it->second->cppgc_id);
82-
}
83-
84-
object->SetAlignedPointerInInternalField(descriptor.wrappable_type_index,
85-
id_ptr);
86-
object->SetAlignedPointerInInternalField(descriptor.wrappable_instance_index,
87-
wrappable);
88-
}
89-
9065
inline uint16_t* IsolateData::embedder_id_for_cppgc() const {
9166
return &(wrapper_data_->cppgc_id);
9267
}

src/env.cc

Lines changed: 19 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#include "util-inl.h"
2424
#include "v8-cppgc.h"
2525
#include "v8-profiler.h"
26+
#include "v8-sandbox.h" // v8::Object::Wrap(), v8::Object::Unwrap()
2627

2728
#include <algorithm>
2829
#include <atomic>
@@ -71,7 +72,6 @@ using v8::TryCatch;
7172
using v8::Uint32;
7273
using v8::Undefined;
7374
using v8::Value;
74-
using v8::WrapperDescriptor;
7575
using worker::Worker;
7676

7777
int const ContextEmbedderTag::kNodeContextTag = 0x6e6f64;
@@ -533,6 +533,14 @@ void IsolateData::CreateProperties() {
533533
CreateEnvProxyTemplate(this);
534534
}
535535

536+
// Previously, the general convention of the wrappable layout for cppgc in
537+
// the ecosystem is:
538+
// [ 0 ] -> embedder id
539+
// [ 1 ] -> wrappable instance
540+
// Now V8 has deprecated this layout-based tracing enablement, embedders
541+
// should simply use v8::Object::Wrap() and v8::Object::Unwrap(). We preserve
542+
// this layout only to distinguish internally how the memory of a Node.js
543+
// wrapper is managed or whether a wrapper is managed by Node.js.
536544
constexpr uint16_t kDefaultCppGCEmbedderID = 0x90de;
537545
Mutex IsolateData::isolate_data_mutex_;
538546
std::unordered_map<uint16_t, std::unique_ptr<PerIsolateWrapperData>>
@@ -570,36 +578,16 @@ IsolateData::IsolateData(Isolate* isolate,
570578
v8::CppHeap* cpp_heap = isolate->GetCppHeap();
571579

572580
uint16_t cppgc_id = kDefaultCppGCEmbedderID;
573-
if (cpp_heap != nullptr) {
574-
// The general convention of the wrappable layout for cppgc in the
575-
// ecosystem is:
576-
// [ 0 ] -> embedder id
577-
// [ 1 ] -> wrappable instance
578-
// If the Isolate includes a CppHeap attached by another embedder,
579-
// And if they also use the field 0 for the ID, we DCHECK that
580-
// the layout matches our layout, and record the embedder ID for cppgc
581-
// to avoid accidentally enabling cppgc on non-cppgc-managed wrappers .
582-
v8::WrapperDescriptor descriptor = cpp_heap->wrapper_descriptor();
583-
if (descriptor.wrappable_type_index == BaseObject::kEmbedderType) {
584-
cppgc_id = descriptor.embedder_id_for_garbage_collected;
585-
DCHECK_EQ(descriptor.wrappable_instance_index, BaseObject::kSlot);
586-
}
587-
// If the CppHeap uses the slot we use to put non-cppgc-traced BaseObject
588-
// for embedder ID, V8 could accidentally enable cppgc on them. So
589-
// safe guard against this.
590-
DCHECK_NE(descriptor.wrappable_type_index, BaseObject::kSlot);
591-
} else {
592-
cpp_heap_ = CppHeap::Create(
593-
platform,
594-
CppHeapCreateParams{
595-
{},
596-
WrapperDescriptor(
597-
BaseObject::kEmbedderType, BaseObject::kSlot, cppgc_id)});
598-
isolate->AttachCppHeap(cpp_heap_.get());
599-
}
600581
// We do not care about overflow since we just want this to be different
601582
// from the cppgc id.
602583
uint16_t non_cppgc_id = cppgc_id + 1;
584+
if (cpp_heap == nullptr) {
585+
cpp_heap_ = CppHeap::Create(platform, v8::CppHeapCreateParams{{}});
586+
// TODO(joyeecheung): pass it into v8::Isolate::CreateParams and let V8
587+
// own it when we can keep the isolate registered/task runner discoverable
588+
// during isolate disposal.
589+
isolate->AttachCppHeap(cpp_heap_.get());
590+
}
603591

604592
{
605593
// GC could still be run after the IsolateData is destroyed, so we store
@@ -631,11 +619,12 @@ IsolateData::~IsolateData() {
631619
}
632620
}
633621

634-
// Public API
622+
// Deprecated API, embedders should use v8::Object::Wrap() directly instead.
635623
void SetCppgcReference(Isolate* isolate,
636624
Local<Object> object,
637625
void* wrappable) {
638-
IsolateData::SetCppgcReference(isolate, object, wrappable);
626+
v8::Object::Wrap<v8::CppHeapPointerTag::kDefaultTag>(
627+
isolate, object, wrappable);
639628
}
640629

641630
void IsolateData::MemoryInfo(MemoryTracker* tracker) const {

src/env.h

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -175,10 +175,6 @@ class NODE_EXTERN_PRIVATE IsolateData : public MemoryRetainer {
175175
uint16_t* embedder_id_for_cppgc() const;
176176
uint16_t* embedder_id_for_non_cppgc() const;
177177

178-
static inline void SetCppgcReference(v8::Isolate* isolate,
179-
v8::Local<v8::Object> object,
180-
void* wrappable);
181-
182178
inline uv_loop_t* event_loop() const;
183179
inline MultiIsolatePlatform* platform() const;
184180
inline const SnapshotData* snapshot_data() const;

src/node.h

Lines changed: 8 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1552,24 +1552,14 @@ void RegisterSignalHandler(int signal,
15521552
bool reset_handler = false);
15531553
#endif // _WIN32
15541554

1555-
// Configure the layout of the JavaScript object with a cppgc::GarbageCollected
1556-
// instance so that when the JavaScript object is reachable, the garbage
1557-
// collected instance would have its Trace() method invoked per the cppgc
1558-
// contract. To make it work, the process must have called
1559-
// cppgc::InitializeProcess() before, which is usually the case for addons
1560-
// loaded by the stand-alone Node.js executable. Embedders of Node.js can use
1561-
// either need to call it themselves or make sure that
1562-
// ProcessInitializationFlags::kNoInitializeCppgc is *not* set for cppgc to
1563-
// work.
1564-
// If the CppHeap is owned by Node.js, which is usually the case for addon,
1565-
// the object must be created with at least two internal fields available,
1566-
// and the first two internal fields would be configured by Node.js.
1567-
// This may be superseded by a V8 API in the future, see
1568-
// https://bugs.chromium.org/p/v8/issues/detail?id=13960. Until then this
1569-
// serves as a helper for Node.js isolates.
1570-
NODE_EXTERN void SetCppgcReference(v8::Isolate* isolate,
1571-
v8::Local<v8::Object> object,
1572-
void* wrappable);
1555+
// This is kept as a compatibility layer for addons to wrap cppgc-managed
1556+
// objects on Node.js versions without v8::Object::Wrap(). Addons created to
1557+
// work with only Node.js versions with v8::Object::Wrap() should use that
1558+
// instead.
1559+
NODE_DEPRECATED("Use v8::Object::Wrap()",
1560+
NODE_EXTERN void SetCppgcReference(v8::Isolate* isolate,
1561+
v8::Local<v8::Object> object,
1562+
void* wrappable));
15731563

15741564
} // namespace node
15751565

test/addons/cppgc-object/binding.cc

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
1+
#include <assert.h>
12
#include <cppgc/allocation.h>
23
#include <cppgc/garbage-collected.h>
34
#include <cppgc/heap.h>
45
#include <node.h>
56
#include <v8-cppgc.h>
7+
#include <v8-sandbox.h>
68
#include <v8.h>
79
#include <algorithm>
810

@@ -15,21 +17,17 @@ class CppGCed : public cppgc::GarbageCollected<CppGCed> {
1517
static void New(const v8::FunctionCallbackInfo<v8::Value>& args) {
1618
v8::Isolate* isolate = args.GetIsolate();
1719
v8::Local<v8::Object> js_object = args.This();
18-
CppGCed* gc_object = cppgc::MakeGarbageCollected<CppGCed>(
19-
isolate->GetCppHeap()->GetAllocationHandle());
20+
auto* heap = isolate->GetCppHeap();
21+
assert(heap != nullptr);
22+
CppGCed* gc_object =
23+
cppgc::MakeGarbageCollected<CppGCed>(heap->GetAllocationHandle());
2024
node::SetCppgcReference(isolate, js_object, gc_object);
2125
args.GetReturnValue().Set(js_object);
2226
}
2327

2428
static v8::Local<v8::Function> GetConstructor(
2529
v8::Local<v8::Context> context) {
2630
auto ft = v8::FunctionTemplate::New(context->GetIsolate(), New);
27-
auto ot = ft->InstanceTemplate();
28-
v8::WrapperDescriptor descriptor =
29-
context->GetIsolate()->GetCppHeap()->wrapper_descriptor();
30-
uint16_t required_size = std::max(descriptor.wrappable_instance_index,
31-
descriptor.wrappable_type_index);
32-
ot->SetInternalFieldCount(required_size + 1);
3331
return ft->GetFunction(context).ToLocalChecked();
3432
}
3533

test/cctest/test_cppgc.cc

Lines changed: 12 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,12 @@
33
#include <cppgc/heap.h>
44
#include <node.h>
55
#include <v8-cppgc.h>
6+
#include <v8-sandbox.h>
67
#include <v8.h>
78
#include "node_test_fixture.h"
89

910
// This tests that Node.js can work with an existing CppHeap.
1011

11-
// Mimic the Blink layout.
12-
static int kWrappableTypeIndex = 0;
13-
static int kWrappableInstanceIndex = 1;
14-
static uint16_t kEmbedderID = 0x1;
15-
1612
// Mimic a class that does not know about Node.js.
1713
class CppGCed : public cppgc::GarbageCollected<CppGCed> {
1814
public:
@@ -23,21 +19,18 @@ class CppGCed : public cppgc::GarbageCollected<CppGCed> {
2319
static void New(const v8::FunctionCallbackInfo<v8::Value>& args) {
2420
v8::Isolate* isolate = args.GetIsolate();
2521
v8::Local<v8::Object> js_object = args.This();
26-
CppGCed* gc_object = cppgc::MakeGarbageCollected<CppGCed>(
27-
isolate->GetCppHeap()->GetAllocationHandle());
28-
js_object->SetAlignedPointerInInternalField(kWrappableTypeIndex,
29-
&kEmbedderID);
30-
js_object->SetAlignedPointerInInternalField(kWrappableInstanceIndex,
31-
gc_object);
22+
auto* heap = isolate->GetCppHeap();
23+
CHECK_NOT_NULL(heap);
24+
CppGCed* gc_object =
25+
cppgc::MakeGarbageCollected<CppGCed>(heap->GetAllocationHandle());
26+
node::SetCppgcReference(isolate, js_object, gc_object);
3227
kConstructCount++;
3328
args.GetReturnValue().Set(js_object);
3429
}
3530

3631
static v8::Local<v8::Function> GetConstructor(
3732
v8::Local<v8::Context> context) {
3833
auto ft = v8::FunctionTemplate::New(context->GetIsolate(), New);
39-
auto ot = ft->InstanceTemplate();
40-
ot->SetInternalFieldCount(2);
4134
return ft->GetFunction(context).ToLocalChecked();
4235
}
4336

@@ -58,12 +51,12 @@ TEST_F(NodeZeroIsolateTestFixture, ExistingCppHeapTest) {
5851

5952
// Create and attach the CppHeap before we set up the IsolateData so that
6053
// it recognizes the existing heap.
61-
std::unique_ptr<v8::CppHeap> cpp_heap = v8::CppHeap::Create(
62-
platform.get(),
63-
v8::CppHeapCreateParams(
64-
{},
65-
v8::WrapperDescriptor(
66-
kWrappableTypeIndex, kWrappableInstanceIndex, kEmbedderID)));
54+
std::unique_ptr<v8::CppHeap> cpp_heap =
55+
v8::CppHeap::Create(platform.get(), v8::CppHeapCreateParams{{}});
56+
57+
// TODO(joyeecheung): pass it into v8::Isolate::CreateParams and let V8
58+
// own it when we can keep the isolate registered/task runner discoverable
59+
// during isolate disposal.
6760
isolate->AttachCppHeap(cpp_heap.get());
6861

6962
// Try creating Context + IsolateData + Environment.

0 commit comments

Comments
 (0)