@@ -32,6 +32,70 @@ class napi_env__ {
3232 napi_extended_error_info last_error;
3333};
3434
35+ #define RETURN_STATUS_IF_FALSE (env, condition, status ) \
36+ do { \
37+ if (!(condition)) { \
38+ return napi_set_last_error ((env), (status)); \
39+ } \
40+ } while (0 )
41+
42+ #define CHECK_ENV (env ) \
43+ if ((env) == nullptr ) { \
44+ node::FatalError (__func__, " environment(env) must not be null" ); \
45+ }
46+
47+ #define CHECK_ARG (env, arg ) \
48+ RETURN_STATUS_IF_FALSE ((env), ((arg) != nullptr), napi_invalid_arg)
49+
50+ #define CHECK_MAYBE_EMPTY (env, maybe, status ) \
51+ RETURN_STATUS_IF_FALSE ((env), !((maybe).IsEmpty()), (status))
52+
53+ #define CHECK_MAYBE_NOTHING (env, maybe, status ) \
54+ RETURN_STATUS_IF_FALSE ((env), !((maybe).IsNothing()), (status))
55+
56+ // NAPI_PREAMBLE is not wrapped in do..while: try_catch must have function scope
57+ #define NAPI_PREAMBLE (env ) \
58+ CHECK_ENV ((env)); \
59+ RETURN_STATUS_IF_FALSE ((env), (env)->last_exception.IsEmpty(), \
60+ napi_pending_exception); \
61+ napi_clear_last_error ((env)); \
62+ v8impl::TryCatch try_catch ((env))
63+
64+ #define CHECK_TO_TYPE (env, type, context, result, src, status ) \
65+ do { \
66+ auto maybe = v8impl::V8LocalValueFromJsValue ((src))->To ##type ((context)); \
67+ CHECK_MAYBE_EMPTY ((env), maybe, (status)); \
68+ (result) = maybe.ToLocalChecked (); \
69+ } while (0 )
70+
71+ #define CHECK_TO_OBJECT (env, context, result, src ) \
72+ CHECK_TO_TYPE ((env), Object, (context), (result), (src), napi_object_expected)
73+
74+ #define CHECK_TO_STRING (env, context, result, src ) \
75+ CHECK_TO_TYPE ((env), String, (context), (result), (src), napi_string_expected)
76+
77+ #define CHECK_TO_NUMBER (env, context, result, src ) \
78+ CHECK_TO_TYPE ((env), Number, (context), (result), (src), napi_number_expected)
79+
80+ #define CHECK_TO_BOOL (env, context, result, src ) \
81+ CHECK_TO_TYPE ((env), Boolean, (context), (result), (src), \
82+ napi_boolean_expected)
83+
84+ #define CHECK_NEW_FROM_UTF8_LEN (env, result, str, len ) \
85+ do { \
86+ auto str_maybe = v8::String::NewFromUtf8 ( \
87+ (env)->isolate , (str), v8::NewStringType::kInternalized , (len)); \
88+ CHECK_MAYBE_EMPTY ((env), str_maybe, napi_generic_failure); \
89+ result = str_maybe.ToLocalChecked (); \
90+ } while (0 )
91+
92+ #define CHECK_NEW_FROM_UTF8 (env, result, str ) \
93+ CHECK_NEW_FROM_UTF8_LEN ((env), (result), (str), -1)
94+
95+ #define GET_RETURN_STATUS (env ) \
96+ (!try_catch.HasCaught() ? napi_ok \
97+ : napi_set_last_error((env), napi_pending_exception))
98+
3599namespace v8impl {
36100
37101// convert from n-api property attributes to v8::PropertyAttribute
@@ -123,6 +187,22 @@ v8::Local<v8::Value> V8LocalValueFromJsValue(napi_value v) {
123187 return local;
124188}
125189
190+ napi_status V8NameFromPropertyDescriptor (napi_env env,
191+ const napi_property_descriptor* p,
192+ v8::Local<v8::Name>* result) {
193+ if (p->utf8name != nullptr ) {
194+ CHECK_NEW_FROM_UTF8 (env, *result, p->utf8name );
195+ } else {
196+ v8::Local<v8::Value> property_value =
197+ v8impl::V8LocalValueFromJsValue (p->name );
198+
199+ RETURN_STATUS_IF_FALSE (env, property_value->IsName (), napi_name_expected);
200+ *result = property_value.As <v8::Name>();
201+ }
202+
203+ return napi_ok;
204+ }
205+
126206// Adapter for napi_finalize callbacks.
127207class Finalizer {
128208 protected:
@@ -357,13 +437,19 @@ class CallbackWrapperBase : public CallbackWrapper {
357437 v8::Local<v8::External>::Cast (
358438 _cbdata->GetInternalField (kInternalFieldIndex ))->Value ());
359439 v8::Isolate* isolate = _cbinfo.GetIsolate ();
440+
360441 napi_env env = static_cast <napi_env>(
361442 v8::Local<v8::External>::Cast (
362443 _cbdata->GetInternalField (kEnvIndex ))->Value ());
363444
364445 // Make sure any errors encountered last time we were in N-API are gone.
365446 napi_clear_last_error (env);
366- cb (env, cbinfo_wrapper);
447+
448+ napi_value result = cb (env, cbinfo_wrapper);
449+
450+ if (result != nullptr ) {
451+ this ->SetReturnValue (result);
452+ }
367453
368454 if (!env->last_exception .IsEmpty ()) {
369455 isolate->ThrowException (
@@ -604,75 +690,12 @@ void napi_module_register(napi_module* mod) {
604690 node::node_module_register (nm);
605691}
606692
607- #define RETURN_STATUS_IF_FALSE (env, condition, status ) \
608- do { \
609- if (!(condition)) { \
610- return napi_set_last_error ((env), (status)); \
611- } \
612- } while (0 )
613-
614- #define CHECK_ENV (env ) \
615- if ((env) == nullptr ) { \
616- node::FatalError (__func__, " environment(env) must not be null" ); \
617- }
618-
619- #define CHECK_ARG (env, arg ) \
620- RETURN_STATUS_IF_FALSE ((env), ((arg) != nullptr ), napi_invalid_arg)
621-
622- #define CHECK_MAYBE_EMPTY (env, maybe, status ) \
623- RETURN_STATUS_IF_FALSE ((env), !((maybe).IsEmpty()), (status))
624-
625- #define CHECK_MAYBE_NOTHING (env, maybe, status ) \
626- RETURN_STATUS_IF_FALSE ((env), !((maybe).IsNothing()), (status))
627-
628- // NAPI_PREAMBLE is not wrapped in do..while: try_catch must have function scope
629- #define NAPI_PREAMBLE (env ) \
630- CHECK_ENV ((env)); \
631- RETURN_STATUS_IF_FALSE ((env), (env)->last_exception.IsEmpty(), \
632- napi_pending_exception); \
633- napi_clear_last_error ((env)); \
634- v8impl::TryCatch try_catch ((env))
635-
636- #define CHECK_TO_TYPE (env, type, context, result, src, status ) \
637- do { \
638- auto maybe = v8impl::V8LocalValueFromJsValue ((src))->To ##type ((context)); \
639- CHECK_MAYBE_EMPTY ((env), maybe, (status)); \
640- (result) = maybe.ToLocalChecked (); \
641- } while (0 )
642-
643- #define CHECK_TO_OBJECT (env, context, result, src ) \
644- CHECK_TO_TYPE ((env), Object, (context), (result), (src), napi_object_expected)
645-
646- #define CHECK_TO_STRING (env, context, result, src ) \
647- CHECK_TO_TYPE ((env), String, (context), (result), (src), napi_string_expected)
648-
649- #define CHECK_TO_NUMBER (env, context, result, src ) \
650- CHECK_TO_TYPE ((env), Number, (context), (result), (src), napi_number_expected)
651-
652- #define CHECK_TO_BOOL (env, context, result, src ) \
653- CHECK_TO_TYPE ((env), Boolean, (context), (result), (src), \
654- napi_boolean_expected)
655-
656- #define CHECK_NEW_FROM_UTF8_LEN (env, result, str, len ) \
657- do { \
658- auto str_maybe = v8::String::NewFromUtf8 ( \
659- (env)->isolate , (str), v8::NewStringType::kInternalized , (len)); \
660- CHECK_MAYBE_EMPTY ((env), str_maybe, napi_generic_failure); \
661- result = str_maybe.ToLocalChecked (); \
662- } while (0 )
663-
664- #define CHECK_NEW_FROM_UTF8 (env, result, str ) \
665- CHECK_NEW_FROM_UTF8_LEN ((env), (result), (str), -1 )
666-
667- #define GET_RETURN_STATUS (env ) \
668- (!try_catch.HasCaught() ? napi_ok \
669- : napi_set_last_error((env), napi_pending_exception))
670-
671693// Warning: Keep in-sync with napi_status enum
672694const char * error_messages[] = {nullptr ,
673695 " Invalid pointer passed as argument" ,
674696 " An object was expected" ,
675697 " A string was expected" ,
698+ " A string or symbol was expected" ,
676699 " A function was expected" ,
677700 " A number was expected" ,
678701 " A boolean was expected" ,
@@ -789,10 +812,16 @@ napi_status napi_define_class(napi_env env,
789812 continue ;
790813 }
791814
792- v8::Local<v8::String> property_name;
793- CHECK_NEW_FROM_UTF8 (env, property_name, p->utf8name );
815+ v8::Local<v8::Name> property_name;
816+ napi_status status =
817+ v8impl::V8NameFromPropertyDescriptor (env, p, &property_name);
818+
819+ if (status != napi_ok) {
820+ return napi_set_last_error (env, status);
821+ }
822+
794823 v8::PropertyAttribute attributes =
795- v8impl::V8PropertyAttributesFromDescriptor (p);
824+ v8impl::V8PropertyAttributesFromDescriptor (p);
796825
797826 // This code is similar to that in napi_define_properties(); the
798827 // difference is it applies to a template instead of an object.
@@ -809,7 +838,7 @@ napi_status napi_define_class(napi_env env,
809838 attributes);
810839 } else if (p->method != nullptr ) {
811840 v8::Local<v8::Object> cbdata =
812- v8impl::CreateFunctionCallbackData (env, p->method , p->data );
841+ v8impl::CreateFunctionCallbackData (env, p->method , p->data );
813842
814843 RETURN_STATUS_IF_FALSE (env, !cbdata.IsEmpty (), napi_generic_failure);
815844
@@ -818,7 +847,6 @@ napi_status napi_define_class(napi_env env,
818847 v8impl::FunctionCallbackWrapper::Invoke,
819848 cbdata,
820849 v8::Signature::New (isolate, tpl));
821- t->SetClassName (property_name);
822850
823851 tpl->PrototypeTemplate ()->Set (property_name, t, attributes);
824852 } else {
@@ -851,18 +879,6 @@ napi_status napi_define_class(napi_env env,
851879 return GET_RETURN_STATUS (env);
852880}
853881
854- napi_status napi_set_return_value (napi_env env,
855- napi_callback_info cbinfo,
856- napi_value value) {
857- NAPI_PREAMBLE (env);
858-
859- v8impl::CallbackWrapper* info =
860- reinterpret_cast <v8impl::CallbackWrapper*>(cbinfo);
861-
862- info->SetReturnValue (value);
863- return GET_RETURN_STATUS (env);
864- }
865-
866882napi_status napi_get_property_names (napi_env env,
867883 napi_value object,
868884 napi_value* result) {
@@ -1098,8 +1114,13 @@ napi_status napi_define_properties(napi_env env,
10981114 for (size_t i = 0 ; i < property_count; i++) {
10991115 const napi_property_descriptor* p = &properties[i];
11001116
1101- v8::Local<v8::Name> name;
1102- CHECK_NEW_FROM_UTF8 (env, name, p->utf8name );
1117+ v8::Local<v8::Name> property_name;
1118+ napi_status status =
1119+ v8impl::V8NameFromPropertyDescriptor (env, p, &property_name);
1120+
1121+ if (status != napi_ok) {
1122+ return napi_set_last_error (env, status);
1123+ }
11031124
11041125 v8::PropertyAttribute attributes =
11051126 v8impl::V8PropertyAttributesFromDescriptor (p);
@@ -1113,7 +1134,7 @@ napi_status napi_define_properties(napi_env env,
11131134
11141135 auto set_maybe = obj->SetAccessor (
11151136 context,
1116- name ,
1137+ property_name ,
11171138 p->getter ? v8impl::GetterCallbackWrapper::Invoke : nullptr ,
11181139 p->setter ? v8impl::SetterCallbackWrapper::Invoke : nullptr ,
11191140 cbdata,
@@ -1132,8 +1153,8 @@ napi_status napi_define_properties(napi_env env,
11321153 v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New (
11331154 isolate, v8impl::FunctionCallbackWrapper::Invoke, cbdata);
11341155
1135- auto define_maybe =
1136- obj-> DefineOwnProperty ( context, name , t->GetFunction (), attributes);
1156+ auto define_maybe = obj-> DefineOwnProperty (
1157+ context, property_name , t->GetFunction (), attributes);
11371158
11381159 if (!define_maybe.FromMaybe (false )) {
11391160 return napi_set_last_error (env, napi_generic_failure);
@@ -1142,7 +1163,7 @@ napi_status napi_define_properties(napi_env env,
11421163 v8::Local<v8::Value> value = v8impl::V8LocalValueFromJsValue (p->value );
11431164
11441165 auto define_maybe =
1145- obj->DefineOwnProperty (context, name , value, attributes);
1166+ obj->DefineOwnProperty (context, property_name , value, attributes);
11461167
11471168 if (!define_maybe.FromMaybe (false )) {
11481169 return napi_set_last_error (env, napi_invalid_arg);
@@ -1435,33 +1456,24 @@ napi_status napi_get_cb_info(
14351456 napi_value* this_arg, // [out] Receives the JS 'this' arg for the call
14361457 void ** data) { // [out] Receives the data pointer for the callback.
14371458 CHECK_ENV (env);
1438- CHECK_ARG (env, argc);
1439- CHECK_ARG (env, argv);
1440- CHECK_ARG (env, this_arg);
1441- CHECK_ARG (env, data);
14421459
14431460 v8impl::CallbackWrapper* info =
14441461 reinterpret_cast <v8impl::CallbackWrapper*>(cbinfo);
14451462
1446- info->Args (argv, std::min (*argc, info->ArgsLength ()));
1447- *argc = info->ArgsLength ();
1448- *this_arg = info->This ();
1449- *data = info->Data ();
1450-
1451- return napi_ok;
1452- }
1453-
1454- napi_status napi_get_cb_args_length (napi_env env,
1455- napi_callback_info cbinfo,
1456- size_t * result) {
1457- // Omit NAPI_PREAMBLE and GET_RETURN_STATUS because no V8 APIs are called.
1458- CHECK_ENV (env);
1459- CHECK_ARG (env, result);
1460-
1461- v8impl::CallbackWrapper* info =
1462- reinterpret_cast <v8impl::CallbackWrapper*>(cbinfo);
1463+ if (argv != nullptr ) {
1464+ CHECK_ARG (env, argc);
1465+ info->Args (argv, std::min (*argc, info->ArgsLength ()));
1466+ }
1467+ if (argc != nullptr ) {
1468+ *argc = info->ArgsLength ();
1469+ }
1470+ if (this_arg != nullptr ) {
1471+ *this_arg = info->This ();
1472+ }
1473+ if (data != nullptr ) {
1474+ *data = info->Data ();
1475+ }
14631476
1464- *result = info->ArgsLength ();
14651477 return napi_ok;
14661478}
14671479
@@ -1479,51 +1491,6 @@ napi_status napi_is_construct_call(napi_env env,
14791491 return napi_ok;
14801492}
14811493
1482- // copy encoded arguments into provided buffer or return direct pointer to
1483- // encoded arguments array?
1484- napi_status napi_get_cb_args (napi_env env,
1485- napi_callback_info cbinfo,
1486- napi_value* buf,
1487- size_t bufsize) {
1488- // Omit NAPI_PREAMBLE and GET_RETURN_STATUS because no V8 APIs are called.
1489- CHECK_ENV (env);
1490- CHECK_ARG (env, buf);
1491-
1492- v8impl::CallbackWrapper* info =
1493- reinterpret_cast <v8impl::CallbackWrapper*>(cbinfo);
1494-
1495- info->Args (buf, bufsize);
1496- return napi_ok;
1497- }
1498-
1499- napi_status napi_get_cb_this (napi_env env,
1500- napi_callback_info cbinfo,
1501- napi_value* result) {
1502- // Omit NAPI_PREAMBLE and GET_RETURN_STATUS because no V8 APIs are called.
1503- CHECK_ENV (env);
1504- CHECK_ARG (env, result);
1505-
1506- v8impl::CallbackWrapper* info =
1507- reinterpret_cast <v8impl::CallbackWrapper*>(cbinfo);
1508-
1509- *result = info->This ();
1510- return napi_ok;
1511- }
1512-
1513- napi_status napi_get_cb_data (napi_env env,
1514- napi_callback_info cbinfo,
1515- void ** result) {
1516- // Omit NAPI_PREAMBLE and GET_RETURN_STATUS because no V8 APIs are called.
1517- CHECK_ENV (env);
1518- CHECK_ARG (env, result);
1519-
1520- v8impl::CallbackWrapper* info =
1521- reinterpret_cast <v8impl::CallbackWrapper*>(cbinfo);
1522-
1523- *result = info->Data ();
1524- return napi_ok;
1525- }
1526-
15271494napi_status napi_call_function (napi_env env,
15281495 napi_value recv,
15291496 napi_value func,
0 commit comments