@@ -679,6 +679,8 @@ v8::Local<v8::Object> CreateAccessorCallbackData(napi_env env,
679
679
return cbdata;
680
680
}
681
681
682
+ int kWrapperFields = 3 ;
683
+
682
684
// Pointer used to identify items wrapped by N-API. Used by FindWrapper and
683
685
// napi_wrap().
684
686
const char napi_wrap_name[] = " N-API Wrapper" ;
@@ -687,16 +689,20 @@ const char napi_wrap_name[] = "N-API Wrapper";
687
689
// wrapper would be the first in the chain, but it is OK for other objects to
688
690
// be inserted in the prototype chain.
689
691
bool FindWrapper (v8::Local<v8::Object> obj,
690
- v8::Local<v8::Object>* result = nullptr ) {
692
+ v8::Local<v8::Object>* result = nullptr ,
693
+ v8::Local<v8::Object>* parent = nullptr ) {
691
694
v8::Local<v8::Object> wrapper = obj;
692
695
693
696
do {
694
697
v8::Local<v8::Value> proto = wrapper->GetPrototype ();
695
698
if (proto.IsEmpty () || !proto->IsObject ()) {
696
699
return false ;
697
700
}
701
+ if (parent != nullptr ) {
702
+ *parent = wrapper;
703
+ }
698
704
wrapper = proto.As <v8::Object>();
699
- if (wrapper->InternalFieldCount () == 2 ) {
705
+ if (wrapper->InternalFieldCount () == kWrapperFields ) {
700
706
v8::Local<v8::Value> external = wrapper->GetInternalField (1 );
701
707
if (external->IsExternal () &&
702
708
external.As <v8::External>()->Value () == v8impl::napi_wrap_name) {
@@ -750,6 +756,29 @@ napi_env GetEnv(v8::Local<v8::Context> context) {
750
756
return result;
751
757
}
752
758
759
+ napi_status Unwrap (napi_env env,
760
+ napi_value js_object,
761
+ void ** result,
762
+ v8::Local<v8::Object>* wrapper,
763
+ v8::Local<v8::Object>* parent = nullptr ) {
764
+ CHECK_ARG (env, js_object);
765
+ CHECK_ARG (env, result);
766
+
767
+ v8::Local<v8::Value> value = v8impl::V8LocalValueFromJsValue (js_object);
768
+ RETURN_STATUS_IF_FALSE (env, value->IsObject (), napi_invalid_arg);
769
+ v8::Local<v8::Object> obj = value.As <v8::Object>();
770
+
771
+ RETURN_STATUS_IF_FALSE (
772
+ env, v8impl::FindWrapper (obj, wrapper, parent), napi_invalid_arg);
773
+
774
+ v8::Local<v8::Value> unwrappedValue = (*wrapper)->GetInternalField (0 );
775
+ RETURN_STATUS_IF_FALSE (env, unwrappedValue->IsExternal (), napi_invalid_arg);
776
+
777
+ *result = unwrappedValue.As <v8::External>()->Value ();
778
+
779
+ return napi_ok;
780
+ }
781
+
753
782
} // end of namespace v8impl
754
783
755
784
// Intercepts the Node-V8 module registration callback. Converts parameters
@@ -2269,62 +2298,78 @@ napi_status napi_wrap(napi_env env,
2269
2298
// Create a wrapper object with an internal field to hold the wrapped pointer
2270
2299
// and a second internal field to identify the owner as N-API.
2271
2300
v8::Local<v8::ObjectTemplate> wrapper_template;
2272
- ENV_OBJECT_TEMPLATE (env, wrap, wrapper_template, 2 );
2301
+ ENV_OBJECT_TEMPLATE (env, wrap, wrapper_template, v8impl:: kWrapperFields );
2273
2302
2274
2303
auto maybe_object = wrapper_template->NewInstance (context);
2275
2304
CHECK_MAYBE_EMPTY (env, maybe_object, napi_generic_failure);
2276
-
2277
2305
v8::Local<v8::Object> wrapper = maybe_object.ToLocalChecked ();
2278
- wrapper->SetInternalField (1 , v8::External::New (isolate,
2279
- reinterpret_cast <void *>(const_cast <char *>(v8impl::napi_wrap_name))));
2280
2306
2281
2307
// Store the pointer as an external in the wrapper.
2282
2308
wrapper->SetInternalField (0 , v8::External::New (isolate, native_object));
2309
+ wrapper->SetInternalField (1 , v8::External::New (isolate,
2310
+ reinterpret_cast <void *>(const_cast <char *>(v8impl::napi_wrap_name))));
2283
2311
2284
2312
// Insert the wrapper into the object's prototype chain.
2285
2313
v8::Local<v8::Value> proto = obj->GetPrototype ();
2286
2314
CHECK (wrapper->SetPrototype (context, proto).FromJust ());
2287
2315
CHECK (obj->SetPrototype (context, wrapper).FromJust ());
2288
2316
2317
+ v8impl::Reference* reference = nullptr ;
2289
2318
if (result != nullptr ) {
2290
2319
// The returned reference should be deleted via napi_delete_reference()
2291
2320
// ONLY in response to the finalize callback invocation. (If it is deleted
2292
2321
// before then, then the finalize callback will never be invoked.)
2293
2322
// Therefore a finalize callback is required when returning a reference.
2294
2323
CHECK_ARG (env, finalize_cb);
2295
- v8impl::Reference* reference = v8impl::Reference::New (
2324
+ reference = v8impl::Reference::New (
2296
2325
env, obj, 0 , false , finalize_cb, native_object, finalize_hint);
2297
2326
*result = reinterpret_cast <napi_ref>(reference);
2298
2327
} else if (finalize_cb != nullptr ) {
2299
2328
// Create a self-deleting reference just for the finalize callback.
2300
- v8impl::Reference::New (
2329
+ reference = v8impl::Reference::New (
2301
2330
env, obj, 0 , true , finalize_cb, native_object, finalize_hint);
2302
2331
}
2303
2332
2333
+ if (reference != nullptr ) {
2334
+ wrapper->SetInternalField (2 , v8::External::New (isolate, reference));
2335
+ }
2336
+
2304
2337
return GET_RETURN_STATUS (env);
2305
2338
}
2306
2339
2307
- napi_status napi_unwrap (napi_env env, napi_value js_object , void ** result) {
2340
+ napi_status napi_unwrap (napi_env env, napi_value obj , void ** result) {
2308
2341
// Omit NAPI_PREAMBLE and GET_RETURN_STATUS because V8 calls here cannot throw
2309
2342
// JS exceptions.
2310
2343
CHECK_ENV (env);
2311
- CHECK_ARG (env, js_object);
2312
- CHECK_ARG (env, result);
2313
-
2314
- v8::Local<v8::Value> value = v8impl::V8LocalValueFromJsValue (js_object);
2315
- RETURN_STATUS_IF_FALSE (env, value->IsObject (), napi_invalid_arg);
2316
- v8::Local<v8::Object> obj = value.As <v8::Object>();
2344
+ v8::Local<v8::Object> wrapper;
2345
+ return napi_set_last_error (env, v8impl::Unwrap (env, obj, result, &wrapper));
2346
+ }
2317
2347
2348
+ napi_status napi_remove_wrap (napi_env env, napi_value obj, void ** result) {
2349
+ NAPI_PREAMBLE (env);
2318
2350
v8::Local<v8::Object> wrapper;
2319
- RETURN_STATUS_IF_FALSE (
2320
- env, v8impl::FindWrapper (obj, &wrapper), napi_invalid_arg);
2351
+ v8::Local<v8::Object> parent;
2352
+ napi_status status = v8impl::Unwrap (env, obj, result, &wrapper, &parent);
2353
+ if (status != napi_ok) {
2354
+ return napi_set_last_error (env, status);
2355
+ }
2321
2356
2322
- v8::Local<v8::Value> unwrappedValue = wrapper->GetInternalField (0 );
2323
- RETURN_STATUS_IF_FALSE (env, unwrappedValue->IsExternal (), napi_invalid_arg);
2357
+ v8::Local<v8::Value> external = wrapper->GetInternalField (2 );
2358
+ if (external->IsExternal ()) {
2359
+ v8impl::Reference::Delete (
2360
+ static_cast <v8impl::Reference*>(external.As <v8::External>()->Value ()));
2361
+ }
2324
2362
2325
- *result = unwrappedValue.As <v8::External>()->Value ();
2363
+ if (!parent.IsEmpty ()) {
2364
+ v8::Maybe<bool > maybe = parent->SetPrototype (
2365
+ env->isolate ->GetCurrentContext (), wrapper->GetPrototype ());
2366
+ CHECK_MAYBE_NOTHING (env, maybe, napi_generic_failure);
2367
+ if (!maybe.FromMaybe (false )) {
2368
+ return napi_set_last_error (env, napi_generic_failure);
2369
+ }
2370
+ }
2326
2371
2327
- return napi_clear_last_error (env);
2372
+ return GET_RETURN_STATUS (env);
2328
2373
}
2329
2374
2330
2375
napi_status napi_create_external (napi_env env,
0 commit comments