@@ -25,6 +25,14 @@ struct napi_env__ {
25
25
CHECK_NOT_NULL (node_env ());
26
26
}
27
27
28
+ virtual ~napi_env__ () {
29
+ if (instance_data.finalize_cb != nullptr ) {
30
+ CallIntoModuleThrow ([&](napi_env env) {
31
+ instance_data.finalize_cb (env, instance_data.data , instance_data.hint );
32
+ });
33
+ }
34
+ }
35
+
28
36
v8::Isolate* const isolate; // Shortcut for context()->GetIsolate()
29
37
node::Persistent<v8::Context> context_persistent;
30
38
@@ -39,11 +47,37 @@ struct napi_env__ {
39
47
inline void Ref () { refs++; }
40
48
inline void Unref () { if (--refs == 0 ) delete this ; }
41
49
50
+ template <typename T, typename U>
51
+ void CallIntoModule (T&& call, U&& handle_exception) {
52
+ int open_handle_scopes_before = open_handle_scopes;
53
+ int open_callback_scopes_before = open_callback_scopes;
54
+ napi_clear_last_error (this );
55
+ call (this );
56
+ CHECK_EQ (open_handle_scopes, open_handle_scopes_before);
57
+ CHECK_EQ (open_callback_scopes, open_callback_scopes_before);
58
+ if (!last_exception.IsEmpty ()) {
59
+ handle_exception (this , last_exception.Get (this ->isolate ));
60
+ last_exception.Reset ();
61
+ }
62
+ }
63
+
64
+ template <typename T>
65
+ void CallIntoModuleThrow (T&& call) {
66
+ CallIntoModule (call, [&](napi_env env, v8::Local<v8::Value> value) {
67
+ env->isolate ->ThrowException (value);
68
+ });
69
+ }
70
+
42
71
node::Persistent<v8::Value> last_exception;
43
72
napi_extended_error_info last_error;
44
73
int open_handle_scopes = 0 ;
45
74
int open_callback_scopes = 0 ;
46
75
int refs = 1 ;
76
+ struct {
77
+ void * data = nullptr ;
78
+ void * hint = nullptr ;
79
+ napi_finalize finalize_cb = nullptr ;
80
+ } instance_data;
47
81
};
48
82
49
83
#define NAPI_PRIVATE_KEY (context, suffix ) \
@@ -158,27 +192,6 @@ struct napi_env__ {
158
192
(out) = v8::type::New ((buffer), (byte_offset), (length)); \
159
193
} while (0 )
160
194
161
- template <typename T, typename U>
162
- void NapiCallIntoModule (napi_env env, T&& call, U&& handle_exception) {
163
- int open_handle_scopes = env->open_handle_scopes ;
164
- int open_callback_scopes = env->open_callback_scopes ;
165
- napi_clear_last_error (env);
166
- call ();
167
- CHECK_EQ (env->open_handle_scopes , open_handle_scopes);
168
- CHECK_EQ (env->open_callback_scopes , open_callback_scopes);
169
- if (!env->last_exception .IsEmpty ()) {
170
- handle_exception (env->last_exception .Get (env->isolate ));
171
- env->last_exception .Reset ();
172
- }
173
- }
174
-
175
- template <typename T>
176
- void NapiCallIntoModuleThrow (napi_env env, T&& call) {
177
- NapiCallIntoModule (env, call, [&](v8::Local<v8::Value> value) {
178
- env->isolate ->ThrowException (value);
179
- });
180
- }
181
-
182
195
namespace {
183
196
namespace v8impl {
184
197
@@ -357,11 +370,8 @@ class Finalizer {
357
370
static void FinalizeBufferCallback (char * data, void * hint) {
358
371
Finalizer* finalizer = static_cast <Finalizer*>(hint);
359
372
if (finalizer->_finalize_callback != nullptr ) {
360
- NapiCallIntoModuleThrow (finalizer->_env , [&]() {
361
- finalizer->_finalize_callback (
362
- finalizer->_env ,
363
- data,
364
- finalizer->_finalize_hint );
373
+ finalizer->_env ->CallIntoModuleThrow ([&](napi_env env) {
374
+ finalizer->_finalize_callback (env, data, finalizer->_finalize_hint );
365
375
});
366
376
}
367
377
@@ -494,12 +504,10 @@ class Reference : private Finalizer {
494
504
static void SecondPassCallback (const v8::WeakCallbackInfo<Reference>& data) {
495
505
Reference* reference = data.GetParameter ();
496
506
497
- napi_env env = reference->_env ;
498
-
499
507
if (reference->_finalize_callback != nullptr ) {
500
- NapiCallIntoModuleThrow (env, [&]() {
508
+ reference-> _env -> CallIntoModuleThrow ( [&](napi_env env ) {
501
509
reference->_finalize_callback (
502
- reference-> _env ,
510
+ env ,
503
511
reference->_finalize_data ,
504
512
reference->_finalize_hint );
505
513
});
@@ -617,7 +625,9 @@ class CallbackWrapperBase : public CallbackWrapper {
617
625
napi_callback cb = _bundle->*FunctionField;
618
626
619
627
napi_value result;
620
- NapiCallIntoModuleThrow (env, [&]() { result = cb (env, cbinfo_wrapper); });
628
+ env->CallIntoModuleThrow ([&](napi_env env) {
629
+ result = cb (env, cbinfo_wrapper);
630
+ });
621
631
622
632
if (result != nullptr ) {
623
633
this ->SetReturnValue (result);
@@ -781,44 +791,22 @@ v8::Local<v8::Value> CreateAccessorCallbackData(napi_env env,
781
791
}
782
792
783
793
static
784
- napi_env GetEnv (v8::Local<v8::Context> context) {
794
+ napi_env NewEnv (v8::Local<v8::Context> context) {
785
795
napi_env result;
786
796
787
- auto isolate = context->GetIsolate ();
788
- auto global = context->Global ();
789
-
790
- // In the case of the string for which we grab the private and the value of
791
- // the private on the global object we can call .ToLocalChecked() directly
792
- // because we need to stop hard if either of them is empty.
793
- //
794
- // Re https://github.com/nodejs/node/pull/14217#discussion_r128775149
795
- auto value = global->GetPrivate (context, NAPI_PRIVATE_KEY (context, env))
796
- .ToLocalChecked ();
797
-
798
- if (value->IsExternal ()) {
799
- result = static_cast <napi_env>(value.As <v8::External>()->Value ());
800
- } else {
801
- result = new napi_env__ (context);
802
- auto external = v8::External::New (isolate, result);
803
-
804
- // We must also stop hard if the result of assigning the env to the global
805
- // is either nothing or false.
806
- CHECK (global->SetPrivate (context, NAPI_PRIVATE_KEY (context, env), external)
807
- .FromJust ());
808
-
809
- // TODO(addaleax): There was previously code that tried to delete the
810
- // napi_env when its v8::Context was garbage collected;
811
- // However, as long as N-API addons using this napi_env are in place,
812
- // the Context needs to be accessible and alive.
813
- // Ideally, we’d want an on-addon-unload hook that takes care of this
814
- // once all N-API addons using this napi_env are unloaded.
815
- // For now, a per-Environment cleanup hook is the best we can do.
816
- result->node_env ()->AddCleanupHook (
817
- [](void * arg) {
818
- static_cast <napi_env>(arg)->Unref ();
819
- },
820
- static_cast <void *>(result));
821
- }
797
+ result = new napi_env__ (context);
798
+ // TODO(addaleax): There was previously code that tried to delete the
799
+ // napi_env when its v8::Context was garbage collected;
800
+ // However, as long as N-API addons using this napi_env are in place,
801
+ // the Context needs to be accessible and alive.
802
+ // Ideally, we'd want an on-addon-unload hook that takes care of this
803
+ // once all N-API addons using this napi_env are unloaded.
804
+ // For now, a per-Environment cleanup hook is the best we can do.
805
+ result->node_env ()->AddCleanupHook (
806
+ [](void * arg) {
807
+ static_cast <napi_env>(arg)->Unref ();
808
+ },
809
+ static_cast <void *>(result));
822
810
823
811
return result;
824
812
}
@@ -1311,10 +1299,10 @@ void napi_module_register_by_symbol(v8::Local<v8::Object> exports,
1311
1299
1312
1300
// Create a new napi_env for this module or reference one if a pre-existing
1313
1301
// one is found.
1314
- napi_env env = v8impl::GetEnv (context);
1302
+ napi_env env = v8impl::NewEnv (context);
1315
1303
1316
1304
napi_value _exports;
1317
- NapiCallIntoModuleThrow ( env, [&]() {
1305
+ env-> CallIntoModuleThrow ( [&](napi_env env ) {
1318
1306
_exports = init (env, v8impl::JsValueFromV8LocalValue (exports));
1319
1307
});
1320
1308
@@ -3941,15 +3929,9 @@ class Work : public node::AsyncResource, public node::ThreadPoolWork {
3941
3929
3942
3930
CallbackScope callback_scope (this );
3943
3931
3944
- // We have to back up the env here because the `NAPI_CALL_INTO_MODULE` macro
3945
- // makes use of it after the call into the module completes, but the module
3946
- // may have deallocated **this**, and along with it the place where _env is
3947
- // stored.
3948
- napi_env env = _env;
3949
-
3950
- NapiCallIntoModule (env, [&]() {
3951
- _complete (_env, ConvertUVErrorCode (status), _data);
3952
- }, [env](v8::Local<v8::Value> local_err) {
3932
+ _env->CallIntoModule ([&](napi_env env) {
3933
+ _complete (env, ConvertUVErrorCode (status), _data);
3934
+ }, [](napi_env env, v8::Local<v8::Value> local_err) {
3953
3935
// If there was an unhandled exception in the complete callback,
3954
3936
// report it as a fatal exception. (There is no JavaScript on the
3955
3937
// callstack that can possibly handle it.)
@@ -4287,3 +4269,26 @@ napi_status napi_add_finalizer(napi_env env,
4287
4269
finalize_hint,
4288
4270
result);
4289
4271
}
4272
+
4273
+ napi_status napi_set_instance_data (napi_env env,
4274
+ void * data,
4275
+ napi_finalize finalize_cb,
4276
+ void * finalize_hint) {
4277
+ CHECK_ENV (env);
4278
+
4279
+ env->instance_data .data = data;
4280
+ env->instance_data .finalize_cb = finalize_cb;
4281
+ env->instance_data .hint = finalize_hint;
4282
+
4283
+ return napi_clear_last_error (env);
4284
+ }
4285
+
4286
+ napi_status napi_get_instance_data (napi_env env,
4287
+ void ** data) {
4288
+ CHECK_ENV (env);
4289
+ CHECK_ARG (env, data);
4290
+
4291
+ *data = env->instance_data .data ;
4292
+
4293
+ return napi_clear_last_error (env);
4294
+ }
0 commit comments