Skip to content

Commit ea5be29

Browse files
addaleaxtargos
authored andcommitted
doc: avoid using v8::Persistent in addon docs
Use `v8::Global` where possible. For examples where it applies, also clean up the code and make the code multi-threading-ready, for those where that isn’t easily possible, add a warning about that. PR-URL: #31018 Reviewed-By: Colin Ihrig <[email protected]> Reviewed-By: Richard Lau <[email protected]> Reviewed-By: James M Snell <[email protected]> Reviewed-By: David Carlier <[email protected]> Reviewed-By: Rich Trott <[email protected]> Reviewed-By: Gus Caplan <[email protected]> Reviewed-By: Joyee Cheung <[email protected]> Reviewed-By: Ben Noordhuis <[email protected]> Reviewed-By: Stephen Belanger <[email protected]>
1 parent 5622543 commit ea5be29

File tree

1 file changed

+37
-26
lines changed

1 file changed

+37
-26
lines changed

doc/api/addons.md

+37-26
Original file line numberDiff line numberDiff line change
@@ -157,11 +157,11 @@ The context-aware addon can be structured to avoid global static data by
157157
performing the following steps:
158158
159159
* defining a class which will hold per-addon-instance data. Such
160-
a class should include a `v8::Persistent<v8::Object>` which will hold a weak
160+
a class should include a `v8::Global<v8::Object>` which will hold a weak
161161
reference to the addon's `exports` object. The callback associated with the weak
162162
reference will then destroy the instance of the class.
163163
* constructing an instance of this class in the addon initializer such that the
164-
`v8::Persistent<v8::Object>` is set to the `exports` object.
164+
`v8::Global<v8::Object>` is set to the `exports` object.
165165
* storing the instance of the class in a `v8::External`, and
166166
* passing the `v8::External` to all methods exposed to JavaScript by passing it
167167
to the `v8::FunctionTemplate` constructor which creates the native-backed
@@ -188,14 +188,6 @@ class AddonData {
188188
exports_.SetWeak(this, DeleteMe, WeakCallbackType::kParameter);
189189
}
190190
191-
~AddonData() {
192-
if (!exports_.IsEmpty()) {
193-
// Reset the reference to avoid leaking data.
194-
exports_.ClearWeak();
195-
exports_.Reset();
196-
}
197-
}
198-
199191
// Per-addon data.
200192
int call_count;
201193
@@ -207,7 +199,7 @@ class AddonData {
207199
208200
// Weak handle to the "exports" object. An instance of this class will be
209201
// destroyed along with the exports object to which it is weakly bound.
210-
v8::Persistent<v8::Object> exports_;
202+
v8::Global<v8::Object> exports_;
211203
};
212204
213205
static void Method(const v8::FunctionCallbackInfo<v8::Value>& info) {
@@ -830,7 +822,7 @@ class MyObject : public node::ObjectWrap {
830822
831823
static void New(const v8::FunctionCallbackInfo<v8::Value>& args);
832824
static void PlusOne(const v8::FunctionCallbackInfo<v8::Value>& args);
833-
static v8::Persistent<v8::Function> constructor;
825+
834826
double value_;
835827
};
836828
@@ -858,12 +850,10 @@ using v8::Local;
858850
using v8::NewStringType;
859851
using v8::Number;
860852
using v8::Object;
861-
using v8::Persistent;
853+
using v8::ObjectTemplate;
862854
using v8::String;
863855
using v8::Value;
864856

865-
Persistent<Function> MyObject::constructor;
866-
867857
MyObject::MyObject(double value) : value_(value) {
868858
}
869859

@@ -872,21 +862,27 @@ MyObject::~MyObject() {
872862

873863
void MyObject::Init(Local<Object> exports) {
874864
Isolate* isolate = exports->GetIsolate();
865+
Local<Context> context = isolate->GetCurrentContext();
866+
867+
Local<ObjectTemplate> addon_data_tpl = ObjectTemplate::New(isolate);
868+
addon_data_tpl->SetInternalFieldCount(1); // 1 field for the MyObject::New()
869+
Local<Object> addon_data =
870+
addon_data_tpl->NewInstance(context).ToLocalChecked();
875871

876872
// Prepare constructor template
877-
Local<FunctionTemplate> tpl = FunctionTemplate::New(isolate, New);
873+
Local<FunctionTemplate> tpl = FunctionTemplate::New(isolate, New, addon_data);
878874
tpl->SetClassName(String::NewFromUtf8(
879875
isolate, "MyObject", NewStringType::kNormal).ToLocalChecked());
880876
tpl->InstanceTemplate()->SetInternalFieldCount(1);
881877

882878
// Prototype
883879
NODE_SET_PROTOTYPE_METHOD(tpl, "plusOne", PlusOne);
884880

885-
Local<Context> context = isolate->GetCurrentContext();
886-
constructor.Reset(isolate, tpl->GetFunction(context).ToLocalChecked());
881+
Local<Function> constructor = tpl->GetFunction(context).ToLocalChecked();
882+
addon_data->SetInternalField(0, constructor);
887883
exports->Set(context, String::NewFromUtf8(
888884
isolate, "MyObject", NewStringType::kNormal).ToLocalChecked(),
889-
tpl->GetFunction(context).ToLocalChecked()).FromJust();
885+
constructor).FromJust();
890886
}
891887

892888
void MyObject::New(const FunctionCallbackInfo<Value>& args) {
@@ -904,7 +900,8 @@ void MyObject::New(const FunctionCallbackInfo<Value>& args) {
904900
// Invoked as plain function `MyObject(...)`, turn into construct call.
905901
const int argc = 1;
906902
Local<Value> argv[argc] = { args[0] };
907-
Local<Function> cons = Local<Function>::New(isolate, constructor);
903+
Local<Function> cons =
904+
args.Data().As<Object>()->GetInternalField(0).As<Function>();
908905
Local<Object> result =
909906
cons->NewInstance(context, argc, argv).ToLocalChecked();
910907
args.GetReturnValue().Set(result);
@@ -1029,7 +1026,7 @@ class MyObject : public node::ObjectWrap {
10291026
10301027
static void New(const v8::FunctionCallbackInfo<v8::Value>& args);
10311028
static void PlusOne(const v8::FunctionCallbackInfo<v8::Value>& args);
1032-
static v8::Persistent<v8::Function> constructor;
1029+
static v8::Global<v8::Function> constructor;
10331030
double value_;
10341031
};
10351032
@@ -1047,20 +1044,23 @@ The implementation in `myobject.cc` is similar to the previous example:
10471044

10481045
namespace demo {
10491046

1047+
using node::AddEnvironmentCleanupHook;
10501048
using v8::Context;
10511049
using v8::Function;
10521050
using v8::FunctionCallbackInfo;
10531051
using v8::FunctionTemplate;
1052+
using v8::Global;
10541053
using v8::Isolate;
10551054
using v8::Local;
10561055
using v8::NewStringType;
10571056
using v8::Number;
10581057
using v8::Object;
1059-
using v8::Persistent;
10601058
using v8::String;
10611059
using v8::Value;
10621060

1063-
Persistent<Function> MyObject::constructor;
1061+
// Warning! This is not thread-safe, this addon cannot be used for worker
1062+
// threads.
1063+
Global<Function> MyObject::constructor;
10641064

10651065
MyObject::MyObject(double value) : value_(value) {
10661066
}
@@ -1080,6 +1080,10 @@ void MyObject::Init(Isolate* isolate) {
10801080

10811081
Local<Context> context = isolate->GetCurrentContext();
10821082
constructor.Reset(isolate, tpl->GetFunction(context).ToLocalChecked());
1083+
1084+
AddEnvironmentCleanupHook(isolate, [](void*) {
1085+
constructor.Reset();
1086+
}, nullptr);
10831087
}
10841088

10851089
void MyObject::New(const FunctionCallbackInfo<Value>& args) {
@@ -1246,7 +1250,7 @@ class MyObject : public node::ObjectWrap {
12461250
~MyObject();
12471251
12481252
static void New(const v8::FunctionCallbackInfo<v8::Value>& args);
1249-
static v8::Persistent<v8::Function> constructor;
1253+
static v8::Global<v8::Function> constructor;
12501254
double value_;
12511255
};
12521256
@@ -1264,19 +1268,22 @@ The implementation of `myobject.cc` is similar to before:
12641268

12651269
namespace demo {
12661270

1271+
using node::AddEnvironmentCleanupHook;
12671272
using v8::Context;
12681273
using v8::Function;
12691274
using v8::FunctionCallbackInfo;
12701275
using v8::FunctionTemplate;
1276+
using v8::Global;
12711277
using v8::Isolate;
12721278
using v8::Local;
12731279
using v8::NewStringType;
12741280
using v8::Object;
1275-
using v8::Persistent;
12761281
using v8::String;
12771282
using v8::Value;
12781283

1279-
Persistent<Function> MyObject::constructor;
1284+
// Warning! This is not thread-safe, this addon cannot be used for worker
1285+
// threads.
1286+
Global<Function> MyObject::constructor;
12801287

12811288
MyObject::MyObject(double value) : value_(value) {
12821289
}
@@ -1293,6 +1300,10 @@ void MyObject::Init(Isolate* isolate) {
12931300

12941301
Local<Context> context = isolate->GetCurrentContext();
12951302
constructor.Reset(isolate, tpl->GetFunction(context).ToLocalChecked());
1303+
1304+
AddEnvironmentCleanupHook(isolate, [](void*) {
1305+
constructor.Reset();
1306+
}, nullptr);
12961307
}
12971308

12981309
void MyObject::New(const FunctionCallbackInfo<Value>& args) {

0 commit comments

Comments
 (0)