@@ -418,18 +418,36 @@ inline static napi_status Unwrap(napi_env env,
418
418
// calling through N-API.
419
419
// Ref: benchmark/misc/function_call
420
420
// Discussion (incl. perf. data): https://github.com/nodejs/node/pull/21072
421
- struct CallbackBundle {
421
+ class CallbackBundle {
422
+ public:
423
+ // Creates an object to be made available to the static function callback
424
+ // wrapper, used to retrieve the native callback function and data pointer.
425
+ static inline v8::Local<v8::Value>
426
+ New (napi_env env, napi_callback cb, void * data) {
427
+ CallbackBundle* bundle = new CallbackBundle ();
428
+ bundle->cb = cb;
429
+ bundle->cb_data = data;
430
+ bundle->env = env;
431
+
432
+ v8::Local<v8::Value> cbdata = v8::External::New (env->isolate , bundle);
433
+ Reference::New (env, cbdata, 0 , true , Delete, bundle, nullptr );
434
+ return cbdata;
435
+ }
422
436
napi_env env; // Necessary to invoke C++ NAPI callback
423
437
void * cb_data; // The user provided callback data
424
- napi_callback function_or_getter;
425
- napi_callback setter;
438
+ napi_callback cb;
439
+ private:
440
+ static void Delete (napi_env env, void * data, void * hint) {
441
+ CallbackBundle* bundle = static_cast <CallbackBundle*>(data);
442
+ delete bundle;
443
+ }
426
444
};
427
445
428
446
// Base class extended by classes that wrap V8 function and property callback
429
447
// info.
430
448
class CallbackWrapper {
431
449
public:
432
- CallbackWrapper (napi_value this_arg, size_t args_length, void * data)
450
+ inline CallbackWrapper (napi_value this_arg, size_t args_length, void * data)
433
451
: _this(this_arg), _args_length(args_length), _data(data) {}
434
452
435
453
virtual napi_value GetNewTarget () = 0;
@@ -448,10 +466,10 @@ class CallbackWrapper {
448
466
void * _data;
449
467
};
450
468
451
- template <typename Info, napi_callback CallbackBundle::*FunctionField>
452
469
class CallbackWrapperBase : public CallbackWrapper {
453
470
public:
454
- CallbackWrapperBase (const Info& cbinfo, const size_t args_length)
471
+ inline CallbackWrapperBase (const v8::FunctionCallbackInfo<v8::Value>& cbinfo,
472
+ const size_t args_length)
455
473
: CallbackWrapper(JsValueFromV8LocalValue(cbinfo.This()),
456
474
args_length,
457
475
nullptr),
@@ -461,16 +479,14 @@ class CallbackWrapperBase : public CallbackWrapper {
461
479
_data = _bundle->cb_data ;
462
480
}
463
481
464
- napi_value GetNewTarget () override { return nullptr ; }
465
-
466
482
protected:
467
- void InvokeCallback () {
483
+ inline void InvokeCallback () {
468
484
napi_callback_info cbinfo_wrapper = reinterpret_cast <napi_callback_info>(
469
485
static_cast <CallbackWrapper*>(this ));
470
486
471
487
// All other pointers we need are stored in `_bundle`
472
488
napi_env env = _bundle->env ;
473
- napi_callback cb = _bundle->*FunctionField ;
489
+ napi_callback cb = _bundle->cb ;
474
490
475
491
napi_value result;
476
492
env->CallIntoModule ([&](napi_env env) {
@@ -482,19 +498,45 @@ class CallbackWrapperBase : public CallbackWrapper {
482
498
}
483
499
}
484
500
485
- const Info & _cbinfo;
501
+ const v8::FunctionCallbackInfo<v8::Value> & _cbinfo;
486
502
CallbackBundle* _bundle;
487
503
};
488
504
489
505
class FunctionCallbackWrapper
490
- : public CallbackWrapperBase<v8::FunctionCallbackInfo<v8::Value>,
491
- &CallbackBundle::function_or_getter> {
506
+ : public CallbackWrapperBase {
492
507
public:
493
508
static void Invoke (const v8::FunctionCallbackInfo<v8::Value>& info) {
494
509
FunctionCallbackWrapper cbwrapper (info);
495
510
cbwrapper.InvokeCallback ();
496
511
}
497
512
513
+ static inline napi_status NewFunction (napi_env env,
514
+ napi_callback cb,
515
+ void * cb_data,
516
+ v8::Local<v8::Function>* result) {
517
+ v8::Local<v8::Value> cbdata = v8impl::CallbackBundle::New (env, cb, cb_data);
518
+ RETURN_STATUS_IF_FALSE (env, !cbdata.IsEmpty (), napi_generic_failure);
519
+
520
+ v8::MaybeLocal<v8::Function> maybe_function =
521
+ v8::Function::New (env->context (), Invoke, cbdata);
522
+ CHECK_MAYBE_EMPTY (env, maybe_function, napi_generic_failure);
523
+
524
+ *result = maybe_function.ToLocalChecked ();
525
+ return napi_clear_last_error (env);
526
+ }
527
+
528
+ static inline napi_status NewTemplate (napi_env env,
529
+ napi_callback cb,
530
+ void * cb_data,
531
+ v8::Local<v8::FunctionTemplate>* result,
532
+ v8::Local<v8::Signature> sig = v8::Local<v8::Signature>()) {
533
+ v8::Local<v8::Value> cbdata = v8impl::CallbackBundle::New (env, cb, cb_data);
534
+ RETURN_STATUS_IF_FALSE (env, !cbdata.IsEmpty (), napi_generic_failure);
535
+
536
+ *result = v8::FunctionTemplate::New (env->isolate , Invoke, cbdata, sig);
537
+ return napi_clear_last_error (env);
538
+ }
539
+
498
540
explicit FunctionCallbackWrapper (
499
541
const v8::FunctionCallbackInfo<v8::Value>& cbinfo)
500
542
: CallbackWrapperBase(cbinfo, cbinfo.Length()) {}
@@ -532,98 +574,6 @@ class FunctionCallbackWrapper
532
574
}
533
575
};
534
576
535
- class GetterCallbackWrapper
536
- : public CallbackWrapperBase<v8::PropertyCallbackInfo<v8::Value>,
537
- &CallbackBundle::function_or_getter> {
538
- public:
539
- static void Invoke (v8::Local<v8::Name> property,
540
- const v8::PropertyCallbackInfo<v8::Value>& info) {
541
- GetterCallbackWrapper cbwrapper (info);
542
- cbwrapper.InvokeCallback ();
543
- }
544
-
545
- explicit GetterCallbackWrapper (
546
- const v8::PropertyCallbackInfo<v8::Value>& cbinfo)
547
- : CallbackWrapperBase(cbinfo, 0 ) {}
548
-
549
- /* virtual*/
550
- void Args (napi_value* buffer, size_t buffer_length) override {
551
- if (buffer_length > 0 ) {
552
- napi_value undefined =
553
- v8impl::JsValueFromV8LocalValue (v8::Undefined (_cbinfo.GetIsolate ()));
554
- for (size_t i = 0 ; i < buffer_length; i += 1 ) {
555
- buffer[i] = undefined;
556
- }
557
- }
558
- }
559
-
560
- /* virtual*/
561
- void SetReturnValue (napi_value value) override {
562
- v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue (value);
563
- _cbinfo.GetReturnValue ().Set (val);
564
- }
565
- };
566
-
567
- class SetterCallbackWrapper
568
- : public CallbackWrapperBase<v8::PropertyCallbackInfo<void >,
569
- &CallbackBundle::setter> {
570
- public:
571
- static void Invoke (v8::Local<v8::Name> property,
572
- v8::Local<v8::Value> value,
573
- const v8::PropertyCallbackInfo<void >& info) {
574
- SetterCallbackWrapper cbwrapper (info, value);
575
- cbwrapper.InvokeCallback ();
576
- }
577
-
578
- SetterCallbackWrapper (const v8::PropertyCallbackInfo<void >& cbinfo,
579
- const v8::Local<v8::Value>& value)
580
- : CallbackWrapperBase(cbinfo, 1 ), _value(value) {}
581
-
582
- /* virtual*/
583
- void Args (napi_value* buffer, size_t buffer_length) override {
584
- if (buffer_length > 0 ) {
585
- buffer[0 ] = v8impl::JsValueFromV8LocalValue (_value);
586
-
587
- if (buffer_length > 1 ) {
588
- napi_value undefined = v8impl::JsValueFromV8LocalValue (
589
- v8::Undefined (_cbinfo.GetIsolate ()));
590
- for (size_t i = 1 ; i < buffer_length; i += 1 ) {
591
- buffer[i] = undefined;
592
- }
593
- }
594
- }
595
- }
596
-
597
- /* virtual*/
598
- void SetReturnValue (napi_value value) override {
599
- // Ignore any value returned from a setter callback.
600
- }
601
-
602
- private:
603
- const v8::Local<v8::Value>& _value;
604
- };
605
-
606
- static void DeleteCallbackBundle (napi_env env, void * data, void * hint) {
607
- CallbackBundle* bundle = static_cast <CallbackBundle*>(data);
608
- delete bundle;
609
- }
610
-
611
- // Creates an object to be made available to the static function callback
612
- // wrapper, used to retrieve the native callback function and data pointer.
613
- static
614
- v8::Local<v8::Value> CreateFunctionCallbackData (napi_env env,
615
- napi_callback cb,
616
- void * data) {
617
- CallbackBundle* bundle = new CallbackBundle ();
618
- bundle->function_or_getter = cb;
619
- bundle->cb_data = data;
620
- bundle->env = env;
621
- v8::Local<v8::Value> cbdata = v8::External::New (env->isolate , bundle);
622
- Reference::New (env, cbdata, 0 , true , DeleteCallbackBundle, bundle, nullptr );
623
-
624
- return cbdata;
625
- }
626
-
627
577
enum WrapType {
628
578
retrievable,
629
579
anonymous
@@ -745,22 +695,12 @@ napi_status napi_create_function(napi_env env,
745
695
CHECK_ARG (env, result);
746
696
CHECK_ARG (env, cb);
747
697
748
- v8::Isolate* isolate = env->isolate ;
749
698
v8::Local<v8::Function> return_value;
750
- v8::EscapableHandleScope scope (isolate);
751
- v8::Local<v8::Value> cbdata =
752
- v8impl::CreateFunctionCallbackData (env, cb, callback_data);
753
-
754
- RETURN_STATUS_IF_FALSE (env, !cbdata.IsEmpty (), napi_generic_failure);
755
-
756
- v8::Local<v8::Context> context = env->context ();
757
- v8::MaybeLocal<v8::Function> maybe_function =
758
- v8::Function::New (context,
759
- v8impl::FunctionCallbackWrapper::Invoke,
760
- cbdata);
761
- CHECK_MAYBE_EMPTY (env, maybe_function, napi_generic_failure);
762
-
763
- return_value = scope.Escape (maybe_function.ToLocalChecked ());
699
+ v8::EscapableHandleScope scope (env->isolate );
700
+ v8::Local<v8::Function> fn;
701
+ STATUS_CALL (v8impl::FunctionCallbackWrapper::NewFunction (
702
+ env, cb, callback_data, &fn));
703
+ return_value = scope.Escape (fn);
764
704
765
705
if (utf8name != nullptr ) {
766
706
v8::Local<v8::String> name_string;
@@ -792,13 +732,9 @@ napi_status napi_define_class(napi_env env,
792
732
v8::Isolate* isolate = env->isolate ;
793
733
794
734
v8::EscapableHandleScope scope (isolate);
795
- v8::Local<v8::Value> cbdata =
796
- v8impl::CreateFunctionCallbackData (env, constructor, callback_data);
797
-
798
- RETURN_STATUS_IF_FALSE (env, !cbdata.IsEmpty (), napi_generic_failure);
799
-
800
- v8::Local<v8::FunctionTemplate> tpl = v8::FunctionTemplate::New (
801
- isolate, v8impl::FunctionCallbackWrapper::Invoke, cbdata);
735
+ v8::Local<v8::FunctionTemplate> tpl;
736
+ STATUS_CALL (v8impl::FunctionCallbackWrapper::NewTemplate (
737
+ env, constructor, callback_data, &tpl));
802
738
803
739
v8::Local<v8::String> name_string;
804
740
CHECK_NEW_FROM_UTF8_LEN (env, name_string, utf8name, length);
@@ -828,18 +764,12 @@ napi_status napi_define_class(napi_env env,
828
764
v8::Local<v8::FunctionTemplate> getter_tpl;
829
765
v8::Local<v8::FunctionTemplate> setter_tpl;
830
766
if (p->getter != nullptr ) {
831
- v8::Local<v8::Value> getter_data =
832
- v8impl::CreateFunctionCallbackData (env, p->getter , p->data );
833
-
834
- getter_tpl = v8::FunctionTemplate::New (
835
- isolate, v8impl::FunctionCallbackWrapper::Invoke, getter_data);
767
+ STATUS_CALL (v8impl::FunctionCallbackWrapper::NewTemplate (
768
+ env, p->getter , p->data , &getter_tpl));
836
769
}
837
770
if (p->setter != nullptr ) {
838
- v8::Local<v8::Value> setter_data =
839
- v8impl::CreateFunctionCallbackData (env, p->setter , p->data );
840
-
841
- setter_tpl = v8::FunctionTemplate::New (
842
- isolate, v8impl::FunctionCallbackWrapper::Invoke, setter_data);
771
+ STATUS_CALL (v8impl::FunctionCallbackWrapper::NewTemplate (
772
+ env, p->setter , p->data , &setter_tpl));
843
773
}
844
774
845
775
tpl->PrototypeTemplate ()->SetAccessorProperty (
@@ -849,16 +779,9 @@ napi_status napi_define_class(napi_env env,
849
779
attributes,
850
780
v8::AccessControl::DEFAULT);
851
781
} else if (p->method != nullptr ) {
852
- v8::Local<v8::Value> cbdata =
853
- v8impl::CreateFunctionCallbackData (env, p->method , p->data );
854
-
855
- RETURN_STATUS_IF_FALSE (env, !cbdata.IsEmpty (), napi_generic_failure);
856
-
857
- v8::Local<v8::FunctionTemplate> t =
858
- v8::FunctionTemplate::New (isolate,
859
- v8impl::FunctionCallbackWrapper::Invoke,
860
- cbdata,
861
- v8::Signature::New (isolate, tpl));
782
+ v8::Local<v8::FunctionTemplate> t;
783
+ STATUS_CALL (v8impl::FunctionCallbackWrapper::NewTemplate (
784
+ env, p->method , p->data , &t, v8::Signature::New (isolate, tpl)));
862
785
863
786
tpl->PrototypeTemplate ()->Set (property_name, t, attributes);
864
787
} else {
@@ -1263,33 +1186,16 @@ napi_status napi_define_properties(napi_env env,
1263
1186
STATUS_CALL (v8impl::V8NameFromPropertyDescriptor (env, p, &property_name));
1264
1187
1265
1188
if (p->getter != nullptr || p->setter != nullptr ) {
1266
- v8::Local<v8::Value > local_getter;
1267
- v8::Local<v8::Value > local_setter;
1189
+ v8::Local<v8::Function > local_getter;
1190
+ v8::Local<v8::Function > local_setter;
1268
1191
1269
1192
if (p->getter != nullptr ) {
1270
- v8::Local<v8::Value> getter_data =
1271
- v8impl::CreateFunctionCallbackData (env, p->getter , p->data );
1272
- CHECK_MAYBE_EMPTY (env, getter_data, napi_generic_failure);
1273
-
1274
- v8::MaybeLocal<v8::Function> maybe_getter =
1275
- v8::Function::New (context,
1276
- v8impl::FunctionCallbackWrapper::Invoke,
1277
- getter_data);
1278
- CHECK_MAYBE_EMPTY (env, maybe_getter, napi_generic_failure);
1279
-
1280
- local_getter = maybe_getter.ToLocalChecked ();
1193
+ STATUS_CALL (v8impl::FunctionCallbackWrapper::NewFunction (
1194
+ env, p->getter , p->data , &local_getter));
1281
1195
}
1282
1196
if (p->setter != nullptr ) {
1283
- v8::Local<v8::Value> setter_data =
1284
- v8impl::CreateFunctionCallbackData (env, p->setter , p->data );
1285
- CHECK_MAYBE_EMPTY (env, setter_data, napi_generic_failure);
1286
-
1287
- v8::MaybeLocal<v8::Function> maybe_setter =
1288
- v8::Function::New (context,
1289
- v8impl::FunctionCallbackWrapper::Invoke,
1290
- setter_data);
1291
- CHECK_MAYBE_EMPTY (env, maybe_setter, napi_generic_failure);
1292
- local_setter = maybe_setter.ToLocalChecked ();
1197
+ STATUS_CALL (v8impl::FunctionCallbackWrapper::NewFunction (
1198
+ env, p->setter , p->data , &local_setter));
1293
1199
}
1294
1200
1295
1201
v8::PropertyDescriptor descriptor (local_getter, local_setter);
@@ -1304,19 +1210,10 @@ napi_status napi_define_properties(napi_env env,
1304
1210
return napi_set_last_error (env, napi_invalid_arg);
1305
1211
}
1306
1212
} else if (p->method != nullptr ) {
1307
- v8::Local<v8::Value> cbdata =
1308
- v8impl::CreateFunctionCallbackData (env, p->method , p->data );
1309
-
1310
- CHECK_MAYBE_EMPTY (env, cbdata, napi_generic_failure);
1311
-
1312
- v8::MaybeLocal<v8::Function> maybe_fn =
1313
- v8::Function::New (context,
1314
- v8impl::FunctionCallbackWrapper::Invoke,
1315
- cbdata);
1316
-
1317
- CHECK_MAYBE_EMPTY (env, maybe_fn, napi_generic_failure);
1318
-
1319
- v8::PropertyDescriptor descriptor (maybe_fn.ToLocalChecked (),
1213
+ v8::Local<v8::Function> method;
1214
+ STATUS_CALL (v8impl::FunctionCallbackWrapper::NewFunction (
1215
+ env, p->method , p->data , &method));
1216
+ v8::PropertyDescriptor descriptor (method,
1320
1217
(p->attributes & napi_writable) != 0 );
1321
1218
descriptor.set_enumerable ((p->attributes & napi_enumerable) != 0 );
1322
1219
descriptor.set_configurable ((p->attributes & napi_configurable) != 0 );
0 commit comments