20
20
#include " node_internals.h"
21
21
#include " env-inl.h"
22
22
#include " node_api_backport.h"
23
- #include " util.h"
24
23
25
24
static
26
25
napi_status napi_set_last_error (napi_env env, napi_status error_code,
@@ -53,6 +52,9 @@ struct napi_env__ {
53
52
uv_loop_t * loop = nullptr ;
54
53
};
55
54
55
+ #define NAPI_PRIVATE_KEY (context, suffix ) \
56
+ (node::Environment::GetCurrent((context))->napi_ ## suffix())
57
+
56
58
#define ENV_OBJECT_TEMPLATE (env, prefix, destination, field_count ) \
57
59
do { \
58
60
if ((env)->prefix ## _template.IsEmpty ()) { \
@@ -383,6 +385,10 @@ class Reference : private Finalizer {
383
385
}
384
386
385
387
public:
388
+ void * Data () {
389
+ return _finalize_data;
390
+ }
391
+
386
392
static Reference* New (napi_env env,
387
393
v8::Local<v8::Value> value,
388
394
uint32_t initial_refcount,
@@ -742,45 +748,6 @@ v8::Local<v8::Object> CreateAccessorCallbackData(napi_env env,
742
748
return cbdata;
743
749
}
744
750
745
- int kWrapperFields = 3 ;
746
-
747
- // Pointer used to identify items wrapped by N-API. Used by FindWrapper and
748
- // napi_wrap().
749
- const char napi_wrap_name[] = " N-API Wrapper" ;
750
-
751
- // Search the object's prototype chain for the wrapper object. Usually the
752
- // wrapper would be the first in the chain, but it is OK for other objects to
753
- // be inserted in the prototype chain.
754
- static
755
- bool FindWrapper (v8::Local<v8::Object> obj,
756
- v8::Local<v8::Object>* result = nullptr ,
757
- v8::Local<v8::Object>* parent = nullptr ) {
758
- v8::Local<v8::Object> wrapper = obj;
759
-
760
- do {
761
- v8::Local<v8::Value> proto = wrapper->GetPrototype ();
762
- if (proto.IsEmpty () || !proto->IsObject ()) {
763
- return false ;
764
- }
765
- if (parent != nullptr ) {
766
- *parent = wrapper;
767
- }
768
- wrapper = proto.As <v8::Object>();
769
- if (wrapper->InternalFieldCount () == kWrapperFields ) {
770
- v8::Local<v8::Value> external = wrapper->GetInternalField (1 );
771
- if (external->IsExternal () &&
772
- external.As <v8::External>()->Value () == v8impl::napi_wrap_name) {
773
- break ;
774
- }
775
- }
776
- } while (true );
777
-
778
- if (result != nullptr ) {
779
- *result = wrapper;
780
- }
781
- return true ;
782
- }
783
-
784
751
static void DeleteEnv (napi_env env, void * data, void * hint) {
785
752
delete env;
786
753
}
@@ -797,11 +764,8 @@ napi_env GetEnv(v8::Local<v8::Context> context) {
797
764
// because we need to stop hard if either of them is empty.
798
765
//
799
766
// Re https://github.com/nodejs/node/pull/14217#discussion_r128775149
800
- auto key = v8::Private::ForApi (isolate,
801
- v8::String::NewFromOneByte (isolate,
802
- reinterpret_cast <const uint8_t *>(" N-API Environment" ),
803
- v8::NewStringType::kInternalized ).ToLocalChecked ());
804
- auto value = global->GetPrivate (context, key).ToLocalChecked ();
767
+ auto value = global->GetPrivate (context, NAPI_PRIVATE_KEY (context, env))
768
+ .ToLocalChecked ();
805
769
806
770
if (value->IsExternal ()) {
807
771
result = static_cast <napi_env>(value.As <v8::External>()->Value ());
@@ -811,7 +775,8 @@ napi_env GetEnv(v8::Local<v8::Context> context) {
811
775
812
776
// We must also stop hard if the result of assigning the env to the global
813
777
// is either nothing or false.
814
- CHECK (global->SetPrivate (context, key, external).FromJust ());
778
+ CHECK (global->SetPrivate (context, NAPI_PRIVATE_KEY (context, env), external)
779
+ .FromJust ());
815
780
816
781
// Create a self-destructing reference to external that will get rid of the
817
782
// napi_env when external goes out of scope.
@@ -821,28 +786,46 @@ napi_env GetEnv(v8::Local<v8::Context> context) {
821
786
return result;
822
787
}
823
788
789
+ enum UnwrapAction {
790
+ KeepWrap,
791
+ RemoveWrap
792
+ };
793
+
824
794
static
825
795
napi_status Unwrap (napi_env env,
826
796
napi_value js_object,
827
797
void ** result,
828
- v8::Local<v8::Object>* wrapper,
829
- v8::Local<v8::Object>* parent = nullptr ) {
798
+ UnwrapAction action) {
799
+ NAPI_PREAMBLE (env);
830
800
CHECK_ARG (env, js_object);
831
- CHECK_ARG (env, result);
801
+ if (action == KeepWrap) {
802
+ CHECK_ARG (env, result);
803
+ }
804
+
805
+ v8::Isolate* isolate = env->isolate ;
806
+ v8::Local<v8::Context> context = isolate->GetCurrentContext ();
832
807
833
808
v8::Local<v8::Value> value = v8impl::V8LocalValueFromJsValue (js_object);
834
809
RETURN_STATUS_IF_FALSE (env, value->IsObject (), napi_invalid_arg);
835
810
v8::Local<v8::Object> obj = value.As <v8::Object>();
836
811
837
- RETURN_STATUS_IF_FALSE (
838
- env, v8impl::FindWrapper (obj, wrapper, parent), napi_invalid_arg);
812
+ auto val = obj->GetPrivate (context, NAPI_PRIVATE_KEY (context, wrapper))
813
+ .ToLocalChecked ();
814
+ RETURN_STATUS_IF_FALSE (env, val->IsExternal (), napi_invalid_arg);
815
+ Reference* reference =
816
+ static_cast <v8impl::Reference*>(val.As <v8::External>()->Value ());
839
817
840
- v8::Local<v8::Value> unwrappedValue = (*wrapper)->GetInternalField (0 );
841
- RETURN_STATUS_IF_FALSE (env, unwrappedValue->IsExternal (), napi_invalid_arg);
818
+ if (result) {
819
+ *result = reference->Data ();
820
+ }
842
821
843
- *result = unwrappedValue.As <v8::External>()->Value ();
822
+ if (action == RemoveWrap) {
823
+ CHECK (obj->DeletePrivate (context, NAPI_PRIVATE_KEY (context, wrapper))
824
+ .FromJust ());
825
+ Reference::Delete (reference);
826
+ }
844
827
845
- return napi_ok ;
828
+ return GET_RETURN_STATUS (env) ;
846
829
}
847
830
848
831
static
@@ -2399,26 +2382,9 @@ napi_status napi_wrap(napi_env env,
2399
2382
v8::Local<v8::Object> obj = value.As <v8::Object>();
2400
2383
2401
2384
// If we've already wrapped this object, we error out.
2402
- RETURN_STATUS_IF_FALSE (env, !v8impl::FindWrapper (obj), napi_invalid_arg);
2403
-
2404
- // Create a wrapper object with an internal field to hold the wrapped pointer
2405
- // and a second internal field to identify the owner as N-API.
2406
- v8::Local<v8::ObjectTemplate> wrapper_template;
2407
- ENV_OBJECT_TEMPLATE (env, wrap, wrapper_template, v8impl::kWrapperFields );
2408
-
2409
- auto maybe_object = wrapper_template->NewInstance (context);
2410
- CHECK_MAYBE_EMPTY (env, maybe_object, napi_generic_failure);
2411
- v8::Local<v8::Object> wrapper = maybe_object.ToLocalChecked ();
2412
-
2413
- // Store the pointer as an external in the wrapper.
2414
- wrapper->SetInternalField (0 , v8::External::New (isolate, native_object));
2415
- wrapper->SetInternalField (1 , v8::External::New (isolate,
2416
- reinterpret_cast <void *>(const_cast <char *>(v8impl::napi_wrap_name))));
2417
-
2418
- // Insert the wrapper into the object's prototype chain.
2419
- v8::Local<v8::Value> proto = obj->GetPrototype ();
2420
- CHECK (wrapper->SetPrototype (context, proto).FromJust ());
2421
- CHECK (obj->SetPrototype (context, wrapper).FromJust ());
2385
+ RETURN_STATUS_IF_FALSE (env,
2386
+ !obj->HasPrivate (context, NAPI_PRIVATE_KEY (context, wrapper)).FromJust (),
2387
+ napi_invalid_arg);
2422
2388
2423
2389
v8impl::Reference* reference = nullptr ;
2424
2390
if (result != nullptr ) {
@@ -2430,52 +2396,24 @@ napi_status napi_wrap(napi_env env,
2430
2396
reference = v8impl::Reference::New (
2431
2397
env, obj, 0 , false , finalize_cb, native_object, finalize_hint);
2432
2398
*result = reinterpret_cast <napi_ref>(reference);
2433
- } else if (finalize_cb != nullptr ) {
2434
- // Create a self-deleting reference just for the finalize callback .
2435
- reference = v8impl::Reference::New (
2436
- env, obj, 0 , true , finalize_cb, native_object, finalize_hint);
2399
+ } else {
2400
+ // Create a self-deleting reference.
2401
+ reference = v8impl::Reference::New (env, obj, 0 , true , finalize_cb,
2402
+ native_object, finalize_cb == nullptr ? nullptr : finalize_hint);
2437
2403
}
2438
2404
2439
- if (reference != nullptr ) {
2440
- wrapper->SetInternalField (2 , v8::External::New (isolate, reference));
2441
- }
2405
+ CHECK (obj->SetPrivate (context, NAPI_PRIVATE_KEY (context, wrapper),
2406
+ v8::External::New (isolate, reference)).FromJust ());
2442
2407
2443
2408
return GET_RETURN_STATUS (env);
2444
2409
}
2445
2410
2446
2411
napi_status napi_unwrap (napi_env env, napi_value obj, void ** result) {
2447
- // Omit NAPI_PREAMBLE and GET_RETURN_STATUS because V8 calls here cannot throw
2448
- // JS exceptions.
2449
- CHECK_ENV (env);
2450
- v8::Local<v8::Object> wrapper;
2451
- return napi_set_last_error (env, v8impl::Unwrap (env, obj, result, &wrapper));
2412
+ return v8impl::Unwrap (env, obj, result, v8impl::KeepWrap);
2452
2413
}
2453
2414
2454
2415
napi_status napi_remove_wrap (napi_env env, napi_value obj, void ** result) {
2455
- NAPI_PREAMBLE (env);
2456
- v8::Local<v8::Object> wrapper;
2457
- v8::Local<v8::Object> parent;
2458
- napi_status status = v8impl::Unwrap (env, obj, result, &wrapper, &parent);
2459
- if (status != napi_ok) {
2460
- return napi_set_last_error (env, status);
2461
- }
2462
-
2463
- v8::Local<v8::Value> external = wrapper->GetInternalField (2 );
2464
- if (external->IsExternal ()) {
2465
- v8impl::Reference::Delete (
2466
- static_cast <v8impl::Reference*>(external.As <v8::External>()->Value ()));
2467
- }
2468
-
2469
- if (!parent.IsEmpty ()) {
2470
- v8::Maybe<bool > maybe = parent->SetPrototype (
2471
- env->isolate ->GetCurrentContext (), wrapper->GetPrototype ());
2472
- CHECK_MAYBE_NOTHING (env, maybe, napi_generic_failure);
2473
- if (!maybe.FromMaybe (false )) {
2474
- return napi_set_last_error (env, napi_generic_failure);
2475
- }
2476
- }
2477
-
2478
- return GET_RETURN_STATUS (env);
2416
+ return v8impl::Unwrap (env, obj, result, v8impl::RemoveWrap);
2479
2417
}
2480
2418
2481
2419
napi_status napi_create_external (napi_env env,
0 commit comments