@@ -38,6 +38,70 @@ class napi_env__ {
3838 napi_extended_error_info last_error;
3939};
4040
41+ #define RETURN_STATUS_IF_FALSE (env, condition, status ) \
42+ do { \
43+ if (!(condition)) { \
44+ return napi_set_last_error ((env), (status)); \
45+ } \
46+ } while (0 )
47+
48+ #define CHECK_ENV (env ) \
49+ if ((env) == nullptr ) { \
50+ node::FatalError (__func__, " environment(env) must not be null" ); \
51+ }
52+
53+ #define CHECK_ARG (env, arg ) \
54+ RETURN_STATUS_IF_FALSE ((env), ((arg) != nullptr), napi_invalid_arg)
55+
56+ #define CHECK_MAYBE_EMPTY (env, maybe, status ) \
57+ RETURN_STATUS_IF_FALSE ((env), !((maybe).IsEmpty()), (status))
58+
59+ #define CHECK_MAYBE_NOTHING (env, maybe, status ) \
60+ RETURN_STATUS_IF_FALSE ((env), !((maybe).IsNothing()), (status))
61+
62+ // NAPI_PREAMBLE is not wrapped in do..while: try_catch must have function scope
63+ #define NAPI_PREAMBLE (env ) \
64+ CHECK_ENV ((env)); \
65+ RETURN_STATUS_IF_FALSE ((env), (env)->last_exception.IsEmpty(), \
66+ napi_pending_exception); \
67+ napi_clear_last_error ((env)); \
68+ v8impl::TryCatch try_catch ((env))
69+
70+ #define CHECK_TO_TYPE (env, type, context, result, src, status ) \
71+ do { \
72+ auto maybe = v8impl::V8LocalValueFromJsValue ((src))->To ##type ((context)); \
73+ CHECK_MAYBE_EMPTY ((env), maybe, (status)); \
74+ (result) = maybe.ToLocalChecked (); \
75+ } while (0 )
76+
77+ #define CHECK_TO_OBJECT (env, context, result, src ) \
78+ CHECK_TO_TYPE ((env), Object, (context), (result), (src), napi_object_expected)
79+
80+ #define CHECK_TO_STRING (env, context, result, src ) \
81+ CHECK_TO_TYPE ((env), String, (context), (result), (src), napi_string_expected)
82+
83+ #define CHECK_TO_NUMBER (env, context, result, src ) \
84+ CHECK_TO_TYPE ((env), Number, (context), (result), (src), napi_number_expected)
85+
86+ #define CHECK_TO_BOOL (env, context, result, src ) \
87+ CHECK_TO_TYPE ((env), Boolean, (context), (result), (src), \
88+ napi_boolean_expected)
89+
90+ #define CHECK_NEW_FROM_UTF8_LEN (env, result, str, len ) \
91+ do { \
92+ auto str_maybe = v8::String::NewFromUtf8 ( \
93+ (env)->isolate , (str), v8::NewStringType::kInternalized , (len)); \
94+ CHECK_MAYBE_EMPTY ((env), str_maybe, napi_generic_failure); \
95+ (result) = str_maybe.ToLocalChecked (); \
96+ } while (0 )
97+
98+ #define CHECK_NEW_FROM_UTF8 (env, result, str ) \
99+ CHECK_NEW_FROM_UTF8_LEN ((env), (result), (str), -1)
100+
101+ #define GET_RETURN_STATUS (env ) \
102+ (!try_catch.HasCaught() ? napi_ok \
103+ : napi_set_last_error((env), napi_pending_exception))
104+
41105namespace v8impl {
42106
43107// convert from n-api property attributes to v8::PropertyAttribute
@@ -129,6 +193,22 @@ v8::Local<v8::Value> V8LocalValueFromJsValue(napi_value v) {
129193 return local;
130194}
131195
196+ static inline napi_status V8NameFromPropertyDescriptor (napi_env env,
197+ const napi_property_descriptor* p,
198+ v8::Local<v8::Name>* result) {
199+ if (p->utf8name != nullptr ) {
200+ CHECK_NEW_FROM_UTF8 (env, *result, p->utf8name );
201+ } else {
202+ v8::Local<v8::Value> property_value =
203+ v8impl::V8LocalValueFromJsValue (p->name );
204+
205+ RETURN_STATUS_IF_FALSE (env, property_value->IsName (), napi_name_expected);
206+ *result = property_value.As <v8::Name>();
207+ }
208+
209+ return napi_ok;
210+ }
211+
132212// Adapter for napi_finalize callbacks.
133213class Finalizer {
134214 protected:
@@ -363,13 +443,19 @@ class CallbackWrapperBase : public CallbackWrapper {
363443 v8::Local<v8::External>::Cast (
364444 _cbdata->GetInternalField (kInternalFieldIndex ))->Value ());
365445 v8::Isolate* isolate = _cbinfo.GetIsolate ();
446+
366447 napi_env env = static_cast <napi_env>(
367448 v8::Local<v8::External>::Cast (
368449 _cbdata->GetInternalField (kEnvIndex ))->Value ());
369450
370451 // Make sure any errors encountered last time we were in N-API are gone.
371452 napi_clear_last_error (env);
372- cb (env, cbinfo_wrapper);
453+
454+ napi_value result = cb (env, cbinfo_wrapper);
455+
456+ if (result != nullptr ) {
457+ this ->SetReturnValue (result);
458+ }
373459
374460 if (!env->last_exception .IsEmpty ()) {
375461 isolate->ThrowException (
@@ -610,75 +696,12 @@ void napi_module_register(napi_module* mod) {
610696 node::node_module_register (nm);
611697}
612698
613- #define RETURN_STATUS_IF_FALSE (env, condition, status ) \
614- do { \
615- if (!(condition)) { \
616- return napi_set_last_error ((env), (status)); \
617- } \
618- } while (0 )
619-
620- #define CHECK_ENV (env ) \
621- if ((env) == nullptr ) { \
622- node::FatalError (__func__, " environment(env) must not be null" ); \
623- }
624-
625- #define CHECK_ARG (env, arg ) \
626- RETURN_STATUS_IF_FALSE ((env), ((arg) != nullptr ), napi_invalid_arg)
627-
628- #define CHECK_MAYBE_EMPTY (env, maybe, status ) \
629- RETURN_STATUS_IF_FALSE ((env), !((maybe).IsEmpty()), (status))
630-
631- #define CHECK_MAYBE_NOTHING (env, maybe, status ) \
632- RETURN_STATUS_IF_FALSE ((env), !((maybe).IsNothing()), (status))
633-
634- // NAPI_PREAMBLE is not wrapped in do..while: try_catch must have function scope
635- #define NAPI_PREAMBLE (env ) \
636- CHECK_ENV ((env)); \
637- RETURN_STATUS_IF_FALSE ((env), (env)->last_exception.IsEmpty(), \
638- napi_pending_exception); \
639- napi_clear_last_error ((env)); \
640- v8impl::TryCatch try_catch ((env))
641-
642- #define CHECK_TO_TYPE (env, type, context, result, src, status ) \
643- do { \
644- auto maybe = v8impl::V8LocalValueFromJsValue ((src))->To ##type ((context)); \
645- CHECK_MAYBE_EMPTY ((env), maybe, (status)); \
646- (result) = maybe.ToLocalChecked (); \
647- } while (0 )
648-
649- #define CHECK_TO_OBJECT (env, context, result, src ) \
650- CHECK_TO_TYPE ((env), Object, (context), (result), (src), napi_object_expected)
651-
652- #define CHECK_TO_STRING (env, context, result, src ) \
653- CHECK_TO_TYPE ((env), String, (context), (result), (src), napi_string_expected)
654-
655- #define CHECK_TO_NUMBER (env, context, result, src ) \
656- CHECK_TO_TYPE ((env), Number, (context), (result), (src), napi_number_expected)
657-
658- #define CHECK_TO_BOOL (env, context, result, src ) \
659- CHECK_TO_TYPE ((env), Boolean, (context), (result), (src), \
660- napi_boolean_expected)
661-
662- #define CHECK_NEW_FROM_UTF8_LEN (env, result, str, len ) \
663- do { \
664- auto str_maybe = v8::String::NewFromUtf8 ( \
665- (env)->isolate , (str), v8::NewStringType::kInternalized , (len)); \
666- CHECK_MAYBE_EMPTY ((env), str_maybe, napi_generic_failure); \
667- result = str_maybe.ToLocalChecked (); \
668- } while (0 )
669-
670- #define CHECK_NEW_FROM_UTF8 (env, result, str ) \
671- CHECK_NEW_FROM_UTF8_LEN ((env), (result), (str), -1 )
672-
673- #define GET_RETURN_STATUS (env ) \
674- (!try_catch.HasCaught() ? napi_ok \
675- : napi_set_last_error((env), napi_pending_exception))
676-
677699// Warning: Keep in-sync with napi_status enum
678700const char * error_messages[] = {nullptr ,
679701 " Invalid pointer passed as argument" ,
680702 " An object was expected" ,
681703 " A string was expected" ,
704+ " A string or symbol was expected" ,
682705 " A function was expected" ,
683706 " A number was expected" ,
684707 " A boolean was expected" ,
@@ -795,8 +818,14 @@ napi_status napi_define_class(napi_env env,
795818 continue ;
796819 }
797820
798- v8::Local<v8::String> property_name;
799- CHECK_NEW_FROM_UTF8 (env, property_name, p->utf8name );
821+ v8::Local<v8::Name> property_name;
822+ napi_status status =
823+ v8impl::V8NameFromPropertyDescriptor (env, p, &property_name);
824+
825+ if (status != napi_ok) {
826+ return napi_set_last_error (env, status);
827+ }
828+
800829 v8::PropertyAttribute attributes =
801830 v8impl::V8PropertyAttributesFromDescriptor (p);
802831
@@ -824,7 +853,6 @@ napi_status napi_define_class(napi_env env,
824853 v8impl::FunctionCallbackWrapper::Invoke,
825854 cbdata,
826855 v8::Signature::New (isolate, tpl));
827- t->SetClassName (property_name);
828856
829857 tpl->PrototypeTemplate ()->Set (property_name, t, attributes);
830858 } else {
@@ -857,18 +885,6 @@ napi_status napi_define_class(napi_env env,
857885 return GET_RETURN_STATUS (env);
858886}
859887
860- napi_status napi_set_return_value (napi_env env,
861- napi_callback_info cbinfo,
862- napi_value value) {
863- NAPI_PREAMBLE (env);
864-
865- v8impl::CallbackWrapper* info =
866- reinterpret_cast <v8impl::CallbackWrapper*>(cbinfo);
867-
868- info->SetReturnValue (value);
869- return GET_RETURN_STATUS (env);
870- }
871-
872888napi_status napi_get_property_names (napi_env env,
873889 napi_value object,
874890 napi_value* result) {
@@ -1104,11 +1120,16 @@ napi_status napi_define_properties(napi_env env,
11041120 for (size_t i = 0 ; i < property_count; i++) {
11051121 const napi_property_descriptor* p = &properties[i];
11061122
1107- v8::Local<v8::Name> name;
1108- CHECK_NEW_FROM_UTF8 (env, name, p->utf8name );
1123+ v8::Local<v8::Name> property_name;
1124+ napi_status status =
1125+ v8impl::V8NameFromPropertyDescriptor (env, p, &property_name);
1126+
1127+ if (status != napi_ok) {
1128+ return napi_set_last_error (env, status);
1129+ }
11091130
11101131 v8::PropertyAttribute attributes =
1111- v8impl::V8PropertyAttributesFromDescriptor (p);
1132+ v8impl::V8PropertyAttributesFromDescriptor (p);
11121133
11131134 if (p->getter != nullptr || p->setter != nullptr ) {
11141135 v8::Local<v8::Object> cbdata = v8impl::CreateAccessorCallbackData (
@@ -1119,7 +1140,7 @@ napi_status napi_define_properties(napi_env env,
11191140
11201141 auto set_maybe = obj->SetAccessor (
11211142 context,
1122- name ,
1143+ property_name ,
11231144 p->getter ? v8impl::GetterCallbackWrapper::Invoke : nullptr ,
11241145 p->setter ? v8impl::SetterCallbackWrapper::Invoke : nullptr ,
11251146 cbdata,
@@ -1138,8 +1159,8 @@ napi_status napi_define_properties(napi_env env,
11381159 v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New (
11391160 isolate, v8impl::FunctionCallbackWrapper::Invoke, cbdata);
11401161
1141- auto define_maybe =
1142- obj-> DefineOwnProperty ( context, name , t->GetFunction (), attributes);
1162+ auto define_maybe = obj-> DefineOwnProperty (
1163+ context, property_name , t->GetFunction (), attributes);
11431164
11441165 if (!define_maybe.FromMaybe (false )) {
11451166 return napi_set_last_error (env, napi_generic_failure);
@@ -1148,7 +1169,7 @@ napi_status napi_define_properties(napi_env env,
11481169 v8::Local<v8::Value> value = v8impl::V8LocalValueFromJsValue (p->value );
11491170
11501171 auto define_maybe =
1151- obj->DefineOwnProperty (context, name , value, attributes);
1172+ obj->DefineOwnProperty (context, property_name , value, attributes);
11521173
11531174 if (!define_maybe.FromMaybe (false )) {
11541175 return napi_set_last_error (env, napi_invalid_arg);
@@ -1441,33 +1462,24 @@ napi_status napi_get_cb_info(
14411462 napi_value* this_arg, // [out] Receives the JS 'this' arg for the call
14421463 void ** data) { // [out] Receives the data pointer for the callback.
14431464 CHECK_ENV (env);
1444- CHECK_ARG (env, argc);
1445- CHECK_ARG (env, argv);
1446- CHECK_ARG (env, this_arg);
1447- CHECK_ARG (env, data);
14481465
14491466 v8impl::CallbackWrapper* info =
14501467 reinterpret_cast <v8impl::CallbackWrapper*>(cbinfo);
14511468
1452- info->Args (argv, std::min (*argc, info->ArgsLength ()));
1453- *argc = info->ArgsLength ();
1454- *this_arg = info->This ();
1455- *data = info->Data ();
1456-
1457- return napi_ok;
1458- }
1459-
1460- napi_status napi_get_cb_args_length (napi_env env,
1461- napi_callback_info cbinfo,
1462- size_t * result) {
1463- // Omit NAPI_PREAMBLE and GET_RETURN_STATUS because no V8 APIs are called.
1464- CHECK_ENV (env);
1465- CHECK_ARG (env, result);
1466-
1467- v8impl::CallbackWrapper* info =
1468- reinterpret_cast <v8impl::CallbackWrapper*>(cbinfo);
1469+ if (argv != nullptr ) {
1470+ CHECK_ARG (env, argc);
1471+ info->Args (argv, std::min (*argc, info->ArgsLength ()));
1472+ }
1473+ if (argc != nullptr ) {
1474+ *argc = info->ArgsLength ();
1475+ }
1476+ if (this_arg != nullptr ) {
1477+ *this_arg = info->This ();
1478+ }
1479+ if (data != nullptr ) {
1480+ *data = info->Data ();
1481+ }
14691482
1470- *result = info->ArgsLength ();
14711483 return napi_ok;
14721484}
14731485
@@ -1485,51 +1497,6 @@ napi_status napi_is_construct_call(napi_env env,
14851497 return napi_ok;
14861498}
14871499
1488- // copy encoded arguments into provided buffer or return direct pointer to
1489- // encoded arguments array?
1490- napi_status napi_get_cb_args (napi_env env,
1491- napi_callback_info cbinfo,
1492- napi_value* buf,
1493- size_t bufsize) {
1494- // Omit NAPI_PREAMBLE and GET_RETURN_STATUS because no V8 APIs are called.
1495- CHECK_ENV (env);
1496- CHECK_ARG (env, buf);
1497-
1498- v8impl::CallbackWrapper* info =
1499- reinterpret_cast <v8impl::CallbackWrapper*>(cbinfo);
1500-
1501- info->Args (buf, bufsize);
1502- return napi_ok;
1503- }
1504-
1505- napi_status napi_get_cb_this (napi_env env,
1506- napi_callback_info cbinfo,
1507- napi_value* result) {
1508- // Omit NAPI_PREAMBLE and GET_RETURN_STATUS because no V8 APIs are called.
1509- CHECK_ENV (env);
1510- CHECK_ARG (env, result);
1511-
1512- v8impl::CallbackWrapper* info =
1513- reinterpret_cast <v8impl::CallbackWrapper*>(cbinfo);
1514-
1515- *result = info->This ();
1516- return napi_ok;
1517- }
1518-
1519- napi_status napi_get_cb_data (napi_env env,
1520- napi_callback_info cbinfo,
1521- void ** result) {
1522- // Omit NAPI_PREAMBLE and GET_RETURN_STATUS because no V8 APIs are called.
1523- CHECK_ENV (env);
1524- CHECK_ARG (env, result);
1525-
1526- v8impl::CallbackWrapper* info =
1527- reinterpret_cast <v8impl::CallbackWrapper*>(cbinfo);
1528-
1529- *result = info->Data ();
1530- return napi_ok;
1531- }
1532-
15331500napi_status napi_call_function (napi_env env,
15341501 napi_value recv,
15351502 napi_value func,
0 commit comments