@@ -674,6 +674,8 @@ v8::Local<v8::Object> CreateAccessorCallbackData(napi_env env,
674674 return cbdata;
675675}
676676
677+ int kWrapperFields = 3 ;
678+
677679// Pointer used to identify items wrapped by N-API. Used by FindWrapper and
678680// napi_wrap().
679681const char napi_wrap_name[] = " N-API Wrapper" ;
@@ -682,16 +684,20 @@ const char napi_wrap_name[] = "N-API Wrapper";
682684// wrapper would be the first in the chain, but it is OK for other objects to
683685// be inserted in the prototype chain.
684686bool 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 ) {
686689 v8::Local<v8::Object> wrapper = obj;
687690
688691 do {
689692 v8::Local<v8::Value> proto = wrapper->GetPrototype ();
690693 if (proto.IsEmpty () || !proto->IsObject ()) {
691694 return false ;
692695 }
696+ if (parent != nullptr ) {
697+ *parent = wrapper;
698+ }
693699 wrapper = proto.As <v8::Object>();
694- if (wrapper->InternalFieldCount () == 2 ) {
700+ if (wrapper->InternalFieldCount () == kWrapperFields ) {
695701 v8::Local<v8::Value> external = wrapper->GetInternalField (1 );
696702 if (external->IsExternal () &&
697703 external.As <v8::External>()->Value () == v8impl::napi_wrap_name) {
@@ -745,6 +751,29 @@ napi_env GetEnv(v8::Local<v8::Context> context) {
745751 return result;
746752}
747753
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+
748777} // end of namespace v8impl
749778
750779// Intercepts the Node-V8 module registration callback. Converts parameters
@@ -2266,62 +2295,78 @@ napi_status napi_wrap(napi_env env,
22662295 // Create a wrapper object with an internal field to hold the wrapped pointer
22672296 // and a second internal field to identify the owner as N-API.
22682297 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 );
22702299
22712300 auto maybe_object = wrapper_template->NewInstance (context);
22722301 CHECK_MAYBE_EMPTY (env, maybe_object, napi_generic_failure);
2273-
22742302 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))));
22772303
22782304 // Store the pointer as an external in the wrapper.
22792305 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))));
22802308
22812309 // Insert the wrapper into the object's prototype chain.
22822310 v8::Local<v8::Value> proto = obj->GetPrototype ();
22832311 CHECK (wrapper->SetPrototype (context, proto).FromJust ());
22842312 CHECK (obj->SetPrototype (context, wrapper).FromJust ());
22852313
2314+ v8impl::Reference* reference = nullptr ;
22862315 if (result != nullptr ) {
22872316 // The returned reference should be deleted via napi_delete_reference()
22882317 // ONLY in response to the finalize callback invocation. (If it is deleted
22892318 // before then, then the finalize callback will never be invoked.)
22902319 // Therefore a finalize callback is required when returning a reference.
22912320 CHECK_ARG (env, finalize_cb);
2292- v8impl::Reference* reference = v8impl::Reference::New (
2321+ reference = v8impl::Reference::New (
22932322 env, obj, 0 , false , finalize_cb, native_object, finalize_hint);
22942323 *result = reinterpret_cast <napi_ref>(reference);
22952324 } else if (finalize_cb != nullptr ) {
22962325 // Create a self-deleting reference just for the finalize callback.
2297- v8impl::Reference::New (
2326+ reference = v8impl::Reference::New (
22982327 env, obj, 0 , true , finalize_cb, native_object, finalize_hint);
22992328 }
23002329
2330+ if (reference != nullptr ) {
2331+ wrapper->SetInternalField (2 , v8::External::New (isolate, reference));
2332+ }
2333+
23012334 return GET_RETURN_STATUS (env);
23022335}
23032336
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) {
23052338 // Omit NAPI_PREAMBLE and GET_RETURN_STATUS because V8 calls here cannot throw
23062339 // JS exceptions.
23072340 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+ }
23142344
2345+ napi_status napi_remove_wrap (napi_env env, napi_value obj, void ** result) {
2346+ NAPI_PREAMBLE (env);
23152347 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+ }
23182353
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+ }
23212359
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+ }
23232368
2324- return napi_clear_last_error (env);
2369+ return GET_RETURN_STATUS (env);
23252370}
23262371
23272372napi_status napi_create_external (napi_env env,
0 commit comments