@@ -157,11 +157,11 @@ The context-aware addon can be structured to avoid global static data by
157
157
performing the following steps:
158
158
159
159
* 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
161
161
reference to the addon's `exports` object. The callback associated with the weak
162
162
reference will then destroy the instance of the class.
163
163
* 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.
165
165
* storing the instance of the class in a `v8::External`, and
166
166
* passing the `v8::External` to all methods exposed to JavaScript by passing it
167
167
to the `v8::FunctionTemplate` constructor which creates the native-backed
@@ -188,14 +188,6 @@ class AddonData {
188
188
exports_.SetWeak(this, DeleteMe, WeakCallbackType::kParameter);
189
189
}
190
190
191
- ~AddonData() {
192
- if (!exports_.IsEmpty()) {
193
- // Reset the reference to avoid leaking data.
194
- exports_.ClearWeak();
195
- exports_.Reset();
196
- }
197
- }
198
-
199
191
// Per-addon data.
200
192
int call_count;
201
193
@@ -207,7 +199,7 @@ class AddonData {
207
199
208
200
// Weak handle to the "exports" object. An instance of this class will be
209
201
// destroyed along with the exports object to which it is weakly bound.
210
- v8::Persistent <v8::Object> exports_;
202
+ v8::Global <v8::Object> exports_;
211
203
};
212
204
213
205
static void Method(const v8::FunctionCallbackInfo<v8::Value>& info) {
@@ -830,7 +822,7 @@ class MyObject : public node::ObjectWrap {
830
822
831
823
static void New(const v8::FunctionCallbackInfo<v8::Value>& args);
832
824
static void PlusOne(const v8::FunctionCallbackInfo<v8::Value>& args);
833
- static v8::Persistent<v8::Function> constructor;
825
+
834
826
double value_;
835
827
};
836
828
@@ -858,12 +850,10 @@ using v8::Local;
858
850
using v8::NewStringType;
859
851
using v8::Number;
860
852
using v8::Object;
861
- using v8::Persistent ;
853
+ using v8::ObjectTemplate ;
862
854
using v8::String;
863
855
using v8::Value;
864
856
865
- Persistent<Function > MyObject::constructor;
866
-
867
857
MyObject::MyObject(double value) : value_ (value) {
868
858
}
869
859
@@ -872,21 +862,27 @@ MyObject::~MyObject() {
872
862
873
863
void MyObject::Init(Local<Object > exports) {
874
864
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();
875
871
876
872
// Prepare constructor template
877
- Local<FunctionTemplate > tpl = FunctionTemplate::New(isolate, New);
873
+ Local<FunctionTemplate > tpl = FunctionTemplate::New(isolate, New, addon_data );
878
874
tpl->SetClassName(String::NewFromUtf8(
879
875
isolate, "MyObject", NewStringType::kNormal).ToLocalChecked());
880
876
tpl->InstanceTemplate()->SetInternalFieldCount(1);
881
877
882
878
// Prototype
883
879
NODE_SET_PROTOTYPE_METHOD(tpl, "plusOne", PlusOne);
884
880
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 );
887
883
exports->Set(context, String::NewFromUtf8(
888
884
isolate, "MyObject", NewStringType::kNormal).ToLocalChecked(),
889
- tpl->GetFunction(context).ToLocalChecked() ).FromJust();
885
+ constructor ).FromJust();
890
886
}
891
887
892
888
void MyObject::New(const FunctionCallbackInfo<Value >& args) {
@@ -904,7 +900,8 @@ void MyObject::New(const FunctionCallbackInfo<Value>& args) {
904
900
// Invoked as plain function ` MyObject(...) ` , turn into construct call.
905
901
const int argc = 1;
906
902
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 >();
908
905
Local<Object > result =
909
906
cons->NewInstance(context, argc, argv).ToLocalChecked();
910
907
args.GetReturnValue().Set(result);
@@ -1029,7 +1026,7 @@ class MyObject : public node::ObjectWrap {
1029
1026
1030
1027
static void New(const v8::FunctionCallbackInfo<v8::Value>& args);
1031
1028
static void PlusOne(const v8::FunctionCallbackInfo<v8::Value>& args);
1032
- static v8::Persistent <v8::Function> constructor;
1029
+ static v8::Global <v8::Function> constructor;
1033
1030
double value_;
1034
1031
};
1035
1032
@@ -1047,20 +1044,23 @@ The implementation in `myobject.cc` is similar to the previous example:
1047
1044
1048
1045
namespace demo {
1049
1046
1047
+ using node::AddEnvironmentCleanupHook;
1050
1048
using v8::Context;
1051
1049
using v8::Function;
1052
1050
using v8::FunctionCallbackInfo;
1053
1051
using v8::FunctionTemplate;
1052
+ using v8::Global;
1054
1053
using v8::Isolate;
1055
1054
using v8::Local;
1056
1055
using v8::NewStringType;
1057
1056
using v8::Number;
1058
1057
using v8::Object;
1059
- using v8::Persistent;
1060
1058
using v8::String;
1061
1059
using v8::Value;
1062
1060
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;
1064
1064
1065
1065
MyObject::MyObject(double value) : value_ (value) {
1066
1066
}
@@ -1080,6 +1080,10 @@ void MyObject::Init(Isolate* isolate) {
1080
1080
1081
1081
Local<Context > context = isolate->GetCurrentContext();
1082
1082
constructor.Reset(isolate, tpl->GetFunction(context).ToLocalChecked());
1083
+
1084
+ AddEnvironmentCleanupHook(isolate, [ ] ( void* ) {
1085
+ constructor.Reset();
1086
+ }, nullptr);
1083
1087
}
1084
1088
1085
1089
void MyObject::New(const FunctionCallbackInfo<Value >& args) {
@@ -1246,7 +1250,7 @@ class MyObject : public node::ObjectWrap {
1246
1250
~MyObject();
1247
1251
1248
1252
static void New(const v8::FunctionCallbackInfo<v8::Value>& args);
1249
- static v8::Persistent <v8::Function> constructor;
1253
+ static v8::Global <v8::Function> constructor;
1250
1254
double value_;
1251
1255
};
1252
1256
@@ -1264,19 +1268,22 @@ The implementation of `myobject.cc` is similar to before:
1264
1268
1265
1269
namespace demo {
1266
1270
1271
+ using node::AddEnvironmentCleanupHook;
1267
1272
using v8::Context;
1268
1273
using v8::Function;
1269
1274
using v8::FunctionCallbackInfo;
1270
1275
using v8::FunctionTemplate;
1276
+ using v8::Global;
1271
1277
using v8::Isolate;
1272
1278
using v8::Local;
1273
1279
using v8::NewStringType;
1274
1280
using v8::Object;
1275
- using v8::Persistent;
1276
1281
using v8::String;
1277
1282
using v8::Value;
1278
1283
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;
1280
1287
1281
1288
MyObject::MyObject(double value) : value_ (value) {
1282
1289
}
@@ -1293,6 +1300,10 @@ void MyObject::Init(Isolate* isolate) {
1293
1300
1294
1301
Local<Context > context = isolate->GetCurrentContext();
1295
1302
constructor.Reset(isolate, tpl->GetFunction(context).ToLocalChecked());
1303
+
1304
+ AddEnvironmentCleanupHook(isolate, [ ] ( void* ) {
1305
+ constructor.Reset();
1306
+ }, nullptr);
1296
1307
}
1297
1308
1298
1309
void MyObject::New(const FunctionCallbackInfo<Value >& args) {
0 commit comments