@@ -38,6 +38,70 @@ class napi_env__ {
38
38
napi_extended_error_info last_error;
39
39
};
40
40
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
+
41
105
namespace v8impl {
42
106
43
107
// convert from n-api property attributes to v8::PropertyAttribute
@@ -129,6 +193,22 @@ v8::Local<v8::Value> V8LocalValueFromJsValue(napi_value v) {
129
193
return local;
130
194
}
131
195
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
+
132
212
// Adapter for napi_finalize callbacks.
133
213
class Finalizer {
134
214
protected:
@@ -363,13 +443,19 @@ class CallbackWrapperBase : public CallbackWrapper {
363
443
v8::Local<v8::External>::Cast (
364
444
_cbdata->GetInternalField (kInternalFieldIndex ))->Value ());
365
445
v8::Isolate* isolate = _cbinfo.GetIsolate ();
446
+
366
447
napi_env env = static_cast <napi_env>(
367
448
v8::Local<v8::External>::Cast (
368
449
_cbdata->GetInternalField (kEnvIndex ))->Value ());
369
450
370
451
// Make sure any errors encountered last time we were in N-API are gone.
371
452
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
+ }
373
459
374
460
if (!env->last_exception .IsEmpty ()) {
375
461
isolate->ThrowException (
@@ -610,75 +696,12 @@ void napi_module_register(napi_module* mod) {
610
696
node::node_module_register (nm);
611
697
}
612
698
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
-
677
699
// Warning: Keep in-sync with napi_status enum
678
700
const char * error_messages[] = {nullptr ,
679
701
" Invalid pointer passed as argument" ,
680
702
" An object was expected" ,
681
703
" A string was expected" ,
704
+ " A string or symbol was expected" ,
682
705
" A function was expected" ,
683
706
" A number was expected" ,
684
707
" A boolean was expected" ,
@@ -795,8 +818,14 @@ napi_status napi_define_class(napi_env env,
795
818
continue ;
796
819
}
797
820
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
+
800
829
v8::PropertyAttribute attributes =
801
830
v8impl::V8PropertyAttributesFromDescriptor (p);
802
831
@@ -824,7 +853,6 @@ napi_status napi_define_class(napi_env env,
824
853
v8impl::FunctionCallbackWrapper::Invoke,
825
854
cbdata,
826
855
v8::Signature::New (isolate, tpl));
827
- t->SetClassName (property_name);
828
856
829
857
tpl->PrototypeTemplate ()->Set (property_name, t, attributes);
830
858
} else {
@@ -857,18 +885,6 @@ napi_status napi_define_class(napi_env env,
857
885
return GET_RETURN_STATUS (env);
858
886
}
859
887
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
-
872
888
napi_status napi_get_property_names (napi_env env,
873
889
napi_value object,
874
890
napi_value* result) {
@@ -1104,11 +1120,16 @@ napi_status napi_define_properties(napi_env env,
1104
1120
for (size_t i = 0 ; i < property_count; i++) {
1105
1121
const napi_property_descriptor* p = &properties[i];
1106
1122
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
+ }
1109
1130
1110
1131
v8::PropertyAttribute attributes =
1111
- v8impl::V8PropertyAttributesFromDescriptor (p);
1132
+ v8impl::V8PropertyAttributesFromDescriptor (p);
1112
1133
1113
1134
if (p->getter != nullptr || p->setter != nullptr ) {
1114
1135
v8::Local<v8::Object> cbdata = v8impl::CreateAccessorCallbackData (
@@ -1119,7 +1140,7 @@ napi_status napi_define_properties(napi_env env,
1119
1140
1120
1141
auto set_maybe = obj->SetAccessor (
1121
1142
context,
1122
- name ,
1143
+ property_name ,
1123
1144
p->getter ? v8impl::GetterCallbackWrapper::Invoke : nullptr ,
1124
1145
p->setter ? v8impl::SetterCallbackWrapper::Invoke : nullptr ,
1125
1146
cbdata,
@@ -1138,8 +1159,8 @@ napi_status napi_define_properties(napi_env env,
1138
1159
v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New (
1139
1160
isolate, v8impl::FunctionCallbackWrapper::Invoke, cbdata);
1140
1161
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);
1143
1164
1144
1165
if (!define_maybe.FromMaybe (false )) {
1145
1166
return napi_set_last_error (env, napi_generic_failure);
@@ -1148,7 +1169,7 @@ napi_status napi_define_properties(napi_env env,
1148
1169
v8::Local<v8::Value> value = v8impl::V8LocalValueFromJsValue (p->value );
1149
1170
1150
1171
auto define_maybe =
1151
- obj->DefineOwnProperty (context, name , value, attributes);
1172
+ obj->DefineOwnProperty (context, property_name , value, attributes);
1152
1173
1153
1174
if (!define_maybe.FromMaybe (false )) {
1154
1175
return napi_set_last_error (env, napi_invalid_arg);
@@ -1441,33 +1462,24 @@ napi_status napi_get_cb_info(
1441
1462
napi_value* this_arg, // [out] Receives the JS 'this' arg for the call
1442
1463
void ** data) { // [out] Receives the data pointer for the callback.
1443
1464
CHECK_ENV (env);
1444
- CHECK_ARG (env, argc);
1445
- CHECK_ARG (env, argv);
1446
- CHECK_ARG (env, this_arg);
1447
- CHECK_ARG (env, data);
1448
1465
1449
1466
v8impl::CallbackWrapper* info =
1450
1467
reinterpret_cast <v8impl::CallbackWrapper*>(cbinfo);
1451
1468
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
+ }
1469
1482
1470
- *result = info->ArgsLength ();
1471
1483
return napi_ok;
1472
1484
}
1473
1485
@@ -1485,51 +1497,6 @@ napi_status napi_is_construct_call(napi_env env,
1485
1497
return napi_ok;
1486
1498
}
1487
1499
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
-
1533
1500
napi_status napi_call_function (napi_env env,
1534
1501
napi_value recv,
1535
1502
napi_value func,
0 commit comments