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