1717#include < vector>
1818#include " uv.h"
1919#include " node_api.h"
20+ #include " node_internals.h"
21+
22+ #define NAPI_VERSION 1
2023
2124static
2225napi_status napi_set_last_error (napi_env env, napi_status error_code,
@@ -154,14 +157,20 @@ class HandleScopeWrapper {
154157// across different versions.
155158class EscapableHandleScopeWrapper {
156159 public:
157- explicit EscapableHandleScopeWrapper (v8::Isolate* isolate) : scope(isolate) {}
160+ explicit EscapableHandleScopeWrapper (v8::Isolate* isolate)
161+ : scope(isolate), escape_called_(false ) {}
162+ bool escape_called () const {
163+ return escape_called_;
164+ }
158165 template <typename T>
159166 v8::Local<T> Escape (v8::Local<T> handle) {
167+ escape_called_ = true ;
160168 return scope.Escape (handle);
161169 }
162170
163171 private:
164172 v8::EscapableHandleScope scope;
173+ bool escape_called_;
165174};
166175
167176napi_handle_scope JsHandleScopeFromV8HandleScope (HandleScopeWrapper* s) {
@@ -716,7 +725,8 @@ const char* error_messages[] = {nullptr,
716725 " An array was expected" ,
717726 " Unknown failure" ,
718727 " An exception is pending" ,
719- " The async work item was cancelled" };
728+ " The async work item was cancelled" ,
729+ " napi_escape_handle already called on scope" };
720730
721731static napi_status napi_clear_last_error (napi_env env) {
722732 CHECK_ENV (env);
@@ -744,10 +754,14 @@ napi_status napi_get_last_error_info(napi_env env,
744754 CHECK_ENV (env);
745755 CHECK_ARG (env, result);
746756
757+ // you must update this assert to reference the last message
758+ // in the napi_status enum each time a new error message is added.
759+ // We don't have a napi_status_last as this would result in an ABI
760+ // change each time a message was added.
747761 static_assert (
748- ( sizeof ( error_messages) / sizeof (*error_messages)) == napi_status_last ,
762+ node::arraysize ( error_messages) == napi_escape_called_twice + 1 ,
749763 " Count of error messages must match count of error values" );
750- assert (env->last_error .error_code < napi_status_last );
764+ assert (env->last_error .error_code <= napi_escape_called_twice );
751765
752766 // Wait until someone requests the last error information to fetch the error
753767 // message string
@@ -758,6 +772,11 @@ napi_status napi_get_last_error_info(napi_env env,
758772 return napi_ok;
759773}
760774
775+ NAPI_NO_RETURN void napi_fatal_error (const char * location,
776+ const char * message) {
777+ node::FatalError (location, message);
778+ }
779+
761780napi_status napi_create_function (napi_env env,
762781 const char * utf8name,
763782 napi_callback cb,
@@ -817,9 +836,6 @@ napi_status napi_define_class(napi_env env,
817836 v8::Local<v8::FunctionTemplate> tpl = v8::FunctionTemplate::New (
818837 isolate, v8impl::FunctionCallbackWrapper::Invoke, cbdata);
819838
820- // we need an internal field to stash the wrapped object
821- tpl->InstanceTemplate ()->SetInternalFieldCount (1 );
822-
823839 v8::Local<v8::String> name_string;
824840 CHECK_NEW_FROM_UTF8 (env, name_string, utf8name);
825841 tpl->SetClassName (name_string);
@@ -991,6 +1007,28 @@ napi_status napi_get_property(napi_env env,
9911007 return GET_RETURN_STATUS (env);
9921008}
9931009
1010+ napi_status napi_delete_property (napi_env env,
1011+ napi_value object,
1012+ napi_value key,
1013+ bool * result) {
1014+ NAPI_PREAMBLE (env);
1015+ CHECK_ARG (env, key);
1016+
1017+ v8::Isolate* isolate = env->isolate ;
1018+ v8::Local<v8::Context> context = isolate->GetCurrentContext ();
1019+ v8::Local<v8::Value> k = v8impl::V8LocalValueFromJsValue (key);
1020+ v8::Local<v8::Object> obj;
1021+
1022+ CHECK_TO_OBJECT (env, context, obj, object);
1023+ v8::Maybe<bool > delete_maybe = obj->Delete (context, k);
1024+ CHECK_MAYBE_NOTHING (env, delete_maybe, napi_generic_failure);
1025+
1026+ if (result != NULL )
1027+ *result = delete_maybe.FromMaybe (false );
1028+
1029+ return GET_RETURN_STATUS (env);
1030+ }
1031+
9941032napi_status napi_set_named_property (napi_env env,
9951033 napi_value object,
9961034 const char * utf8name,
@@ -1128,6 +1166,26 @@ napi_status napi_get_element(napi_env env,
11281166 return GET_RETURN_STATUS (env);
11291167}
11301168
1169+ napi_status napi_delete_element (napi_env env,
1170+ napi_value object,
1171+ uint32_t index,
1172+ bool * result) {
1173+ NAPI_PREAMBLE (env);
1174+
1175+ v8::Isolate* isolate = env->isolate ;
1176+ v8::Local<v8::Context> context = isolate->GetCurrentContext ();
1177+ v8::Local<v8::Object> obj;
1178+
1179+ CHECK_TO_OBJECT (env, context, obj, object);
1180+ v8::Maybe<bool > delete_maybe = obj->Delete (context, index);
1181+ CHECK_MAYBE_NOTHING (env, delete_maybe, napi_generic_failure);
1182+
1183+ if (result != NULL )
1184+ *result = delete_maybe.FromMaybe (false );
1185+
1186+ return GET_RETURN_STATUS (env);
1187+ }
1188+
11311189napi_status napi_define_properties (napi_env env,
11321190 napi_value object,
11331191 size_t property_count,
@@ -1948,14 +2006,24 @@ napi_status napi_wrap(napi_env env,
19482006 CHECK_ARG (env, js_object);
19492007
19502008 v8::Isolate* isolate = env->isolate ;
1951- v8::Local<v8::Object> obj =
1952- v8impl::V8LocalValueFromJsValue (js_object).As <v8::Object>();
2009+ v8::Local<v8::Context> context = isolate->GetCurrentContext ();
2010+
2011+ v8::Local<v8::Value> value = v8impl::V8LocalValueFromJsValue (js_object);
2012+ RETURN_STATUS_IF_FALSE (env, value->IsObject (), napi_invalid_arg);
2013+ v8::Local<v8::Object> obj = value.As <v8::Object>();
19532014
1954- // Only objects that were created from a NAPI constructor's prototype
1955- // via napi_define_class() can be (un)wrapped.
1956- RETURN_STATUS_IF_FALSE (env, obj->InternalFieldCount () > 0 , napi_invalid_arg);
2015+ // Create a wrapper object with an internal field to hold the wrapped pointer.
2016+ v8::Local<v8::ObjectTemplate> wrapperTemplate =
2017+ v8::ObjectTemplate::New (isolate);
2018+ wrapperTemplate->SetInternalFieldCount (1 );
2019+ v8::Local<v8::Object> wrapper =
2020+ wrapperTemplate->NewInstance (context).ToLocalChecked ();
2021+ wrapper->SetInternalField (0 , v8::External::New (isolate, native_object));
19572022
1958- obj->SetInternalField (0 , v8::External::New (isolate, native_object));
2023+ // Insert the wrapper into the object's prototype chain.
2024+ v8::Local<v8::Value> proto = obj->GetPrototype ();
2025+ CHECK (wrapper->SetPrototype (context, proto).FromJust ());
2026+ CHECK (obj->SetPrototype (context, wrapper).FromJust ());
19592027
19602028 if (result != nullptr ) {
19612029 // The returned reference should be deleted via napi_delete_reference()
@@ -1986,11 +2054,18 @@ napi_status napi_unwrap(napi_env env, napi_value js_object, void** result) {
19862054 RETURN_STATUS_IF_FALSE (env, value->IsObject (), napi_invalid_arg);
19872055 v8::Local<v8::Object> obj = value.As <v8::Object>();
19882056
1989- // Only objects that were created from a NAPI constructor's prototype
1990- // via napi_define_class() can be (un)wrapped.
1991- RETURN_STATUS_IF_FALSE (env, obj->InternalFieldCount () > 0 , napi_invalid_arg);
1992-
1993- v8::Local<v8::Value> unwrappedValue = obj->GetInternalField (0 );
2057+ // Search the object's prototype chain for the wrapper with an internal field.
2058+ // Usually the wrapper would be the first in the chain, but it is OK for
2059+ // other objects to be inserted in the prototype chain.
2060+ v8::Local<v8::Object> wrapper = obj;
2061+ do {
2062+ v8::Local<v8::Value> proto = wrapper->GetPrototype ();
2063+ RETURN_STATUS_IF_FALSE (
2064+ env, !proto.IsEmpty () && proto->IsObject (), napi_invalid_arg);
2065+ wrapper = proto.As <v8::Object>();
2066+ } while (wrapper->InternalFieldCount () != 1 );
2067+
2068+ v8::Local<v8::Value> unwrappedValue = wrapper->GetInternalField (0 );
19942069 RETURN_STATUS_IF_FALSE (env, unwrappedValue->IsExternal (), napi_invalid_arg);
19952070
19962071 *result = unwrappedValue.As <v8::External>()->Value ();
@@ -2195,9 +2270,12 @@ napi_status napi_escape_handle(napi_env env,
21952270
21962271 v8impl::EscapableHandleScopeWrapper* s =
21972272 v8impl::V8EscapableHandleScopeFromJsEscapableHandleScope (scope);
2198- *result = v8impl::JsValueFromV8LocalValue (
2199- s->Escape (v8impl::V8LocalValueFromJsValue (escapee)));
2200- return napi_clear_last_error (env);
2273+ if (!s->escape_called ()) {
2274+ *result = v8impl::JsValueFromV8LocalValue (
2275+ s->Escape (v8impl::V8LocalValueFromJsValue (escapee)));
2276+ return napi_clear_last_error (env);
2277+ }
2278+ return napi_set_last_error (env, napi_escape_called_twice);
22012279}
22022280
22032281napi_status napi_new_instance (napi_env env,
@@ -2250,7 +2328,7 @@ napi_status napi_instanceof(napi_env env,
22502328 }
22512329
22522330 if (env->has_instance_available ) {
2253- napi_value value, js_result, has_instance = nullptr ;
2331+ napi_value value, js_result = nullptr , has_instance = nullptr ;
22542332 napi_status status = napi_generic_failure;
22552333 napi_valuetype value_type;
22562334
@@ -2530,7 +2608,7 @@ napi_status napi_create_arraybuffer(napi_env env,
25302608 v8::ArrayBuffer::New (isolate, byte_length);
25312609
25322610 // Optionally return a pointer to the buffer's data, to avoid another call to
2533- // retreive it.
2611+ // retrieve it.
25342612 if (data != nullptr ) {
25352613 *data = buffer->GetContents ().Data ();
25362614 }
@@ -2713,6 +2791,13 @@ napi_status napi_get_typedarray_info(napi_env env,
27132791 return napi_clear_last_error (env);
27142792}
27152793
2794+ napi_status napi_get_version (napi_env env, uint32_t * result) {
2795+ CHECK_ENV (env);
2796+ CHECK_ARG (env, result);
2797+ *result = NAPI_VERSION;
2798+ return napi_clear_last_error (env);
2799+ }
2800+
27162801namespace uvimpl {
27172802
27182803static napi_status ConvertUVErrorCode (int code) {
@@ -2781,7 +2866,7 @@ class Work {
27812866 // report it as a fatal exception. (There is no JavaScript on the
27822867 // callstack that can possibly handle it.)
27832868 if (!env->last_exception .IsEmpty ()) {
2784- v8::TryCatch try_catch;
2869+ v8::TryCatch try_catch (env-> isolate ) ;
27852870 env->isolate ->ThrowException (
27862871 v8::Local<v8::Value>::New (env->isolate , env->last_exception ));
27872872 node::FatalException (env->isolate , try_catch);
0 commit comments