@@ -419,18 +419,36 @@ inline static napi_status Unwrap(napi_env env,
419419// calling through N-API.
420420// Ref: benchmark/misc/function_call
421421// Discussion (incl. perf. data): https://github.com/nodejs/node/pull/21072
422- struct CallbackBundle {
422+ class CallbackBundle {
423+ public:
424+ // Creates an object to be made available to the static function callback
425+ // wrapper, used to retrieve the native callback function and data pointer.
426+ static inline v8::Local<v8::Value>
427+ New (napi_env env, napi_callback cb, void * data) {
428+ CallbackBundle* bundle = new CallbackBundle ();
429+ bundle->cb = cb;
430+ bundle->cb_data = data;
431+ bundle->env = env;
432+
433+ v8::Local<v8::Value> cbdata = v8::External::New (env->isolate , bundle);
434+ Reference::New (env, cbdata, 0 , true , Delete, bundle, nullptr );
435+ return cbdata;
436+ }
423437 napi_env env; // Necessary to invoke C++ NAPI callback
424438 void * cb_data; // The user provided callback data
425- napi_callback function_or_getter;
426- napi_callback setter;
439+ napi_callback cb;
440+ private:
441+ static void Delete (napi_env env, void * data, void * hint) {
442+ CallbackBundle* bundle = static_cast <CallbackBundle*>(data);
443+ delete bundle;
444+ }
427445};
428446
429447// Base class extended by classes that wrap V8 function and property callback
430448// info.
431449class CallbackWrapper {
432450 public:
433- CallbackWrapper (napi_value this_arg, size_t args_length, void * data)
451+ inline CallbackWrapper (napi_value this_arg, size_t args_length, void * data)
434452 : _this(this_arg), _args_length(args_length), _data(data) {}
435453
436454 virtual napi_value GetNewTarget () = 0;
@@ -449,10 +467,10 @@ class CallbackWrapper {
449467 void * _data;
450468};
451469
452- template <typename Info, napi_callback CallbackBundle::*FunctionField>
453470class CallbackWrapperBase : public CallbackWrapper {
454471 public:
455- CallbackWrapperBase (const Info& cbinfo, const size_t args_length)
472+ inline CallbackWrapperBase (const v8::FunctionCallbackInfo<v8::Value>& cbinfo,
473+ const size_t args_length)
456474 : CallbackWrapper(JsValueFromV8LocalValue(cbinfo.This()),
457475 args_length,
458476 nullptr),
@@ -462,16 +480,14 @@ class CallbackWrapperBase : public CallbackWrapper {
462480 _data = _bundle->cb_data ;
463481 }
464482
465- napi_value GetNewTarget () override { return nullptr ; }
466-
467483 protected:
468- void InvokeCallback () {
484+ inline void InvokeCallback () {
469485 napi_callback_info cbinfo_wrapper = reinterpret_cast <napi_callback_info>(
470486 static_cast <CallbackWrapper*>(this ));
471487
472488 // All other pointers we need are stored in `_bundle`
473489 napi_env env = _bundle->env ;
474- napi_callback cb = _bundle->*FunctionField ;
490+ napi_callback cb = _bundle->cb ;
475491
476492 napi_value result;
477493 env->CallIntoModule ([&](napi_env env) {
@@ -483,19 +499,45 @@ class CallbackWrapperBase : public CallbackWrapper {
483499 }
484500 }
485501
486- const Info & _cbinfo;
502+ const v8::FunctionCallbackInfo<v8::Value> & _cbinfo;
487503 CallbackBundle* _bundle;
488504};
489505
490506class FunctionCallbackWrapper
491- : public CallbackWrapperBase<v8::FunctionCallbackInfo<v8::Value>,
492- &CallbackBundle::function_or_getter> {
507+ : public CallbackWrapperBase {
493508 public:
494509 static void Invoke (const v8::FunctionCallbackInfo<v8::Value>& info) {
495510 FunctionCallbackWrapper cbwrapper (info);
496511 cbwrapper.InvokeCallback ();
497512 }
498513
514+ static inline napi_status NewFunction (napi_env env,
515+ napi_callback cb,
516+ void * cb_data,
517+ v8::Local<v8::Function>* result) {
518+ v8::Local<v8::Value> cbdata = v8impl::CallbackBundle::New (env, cb, cb_data);
519+ RETURN_STATUS_IF_FALSE (env, !cbdata.IsEmpty (), napi_generic_failure);
520+
521+ v8::MaybeLocal<v8::Function> maybe_function =
522+ v8::Function::New (env->context (), Invoke, cbdata);
523+ CHECK_MAYBE_EMPTY (env, maybe_function, napi_generic_failure);
524+
525+ *result = maybe_function.ToLocalChecked ();
526+ return napi_clear_last_error (env);
527+ }
528+
529+ static inline napi_status NewTemplate (napi_env env,
530+ napi_callback cb,
531+ void * cb_data,
532+ v8::Local<v8::FunctionTemplate>* result,
533+ v8::Local<v8::Signature> sig = v8::Local<v8::Signature>()) {
534+ v8::Local<v8::Value> cbdata = v8impl::CallbackBundle::New (env, cb, cb_data);
535+ RETURN_STATUS_IF_FALSE (env, !cbdata.IsEmpty (), napi_generic_failure);
536+
537+ *result = v8::FunctionTemplate::New (env->isolate , Invoke, cbdata, sig);
538+ return napi_clear_last_error (env);
539+ }
540+
499541 explicit FunctionCallbackWrapper (
500542 const v8::FunctionCallbackInfo<v8::Value>& cbinfo)
501543 : CallbackWrapperBase(cbinfo, cbinfo.Length()) {}
@@ -533,98 +575,6 @@ class FunctionCallbackWrapper
533575 }
534576};
535577
536- class GetterCallbackWrapper
537- : public CallbackWrapperBase<v8::PropertyCallbackInfo<v8::Value>,
538- &CallbackBundle::function_or_getter> {
539- public:
540- static void Invoke (v8::Local<v8::Name> property,
541- const v8::PropertyCallbackInfo<v8::Value>& info) {
542- GetterCallbackWrapper cbwrapper (info);
543- cbwrapper.InvokeCallback ();
544- }
545-
546- explicit GetterCallbackWrapper (
547- const v8::PropertyCallbackInfo<v8::Value>& cbinfo)
548- : CallbackWrapperBase(cbinfo, 0 ) {}
549-
550- /* virtual*/
551- void Args (napi_value* buffer, size_t buffer_length) override {
552- if (buffer_length > 0 ) {
553- napi_value undefined =
554- v8impl::JsValueFromV8LocalValue (v8::Undefined (_cbinfo.GetIsolate ()));
555- for (size_t i = 0 ; i < buffer_length; i += 1 ) {
556- buffer[i] = undefined;
557- }
558- }
559- }
560-
561- /* virtual*/
562- void SetReturnValue (napi_value value) override {
563- v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue (value);
564- _cbinfo.GetReturnValue ().Set (val);
565- }
566- };
567-
568- class SetterCallbackWrapper
569- : public CallbackWrapperBase<v8::PropertyCallbackInfo<void >,
570- &CallbackBundle::setter> {
571- public:
572- static void Invoke (v8::Local<v8::Name> property,
573- v8::Local<v8::Value> value,
574- const v8::PropertyCallbackInfo<void >& info) {
575- SetterCallbackWrapper cbwrapper (info, value);
576- cbwrapper.InvokeCallback ();
577- }
578-
579- SetterCallbackWrapper (const v8::PropertyCallbackInfo<void >& cbinfo,
580- const v8::Local<v8::Value>& value)
581- : CallbackWrapperBase(cbinfo, 1 ), _value(value) {}
582-
583- /* virtual*/
584- void Args (napi_value* buffer, size_t buffer_length) override {
585- if (buffer_length > 0 ) {
586- buffer[0 ] = v8impl::JsValueFromV8LocalValue (_value);
587-
588- if (buffer_length > 1 ) {
589- napi_value undefined = v8impl::JsValueFromV8LocalValue (
590- v8::Undefined (_cbinfo.GetIsolate ()));
591- for (size_t i = 1 ; i < buffer_length; i += 1 ) {
592- buffer[i] = undefined;
593- }
594- }
595- }
596- }
597-
598- /* virtual*/
599- void SetReturnValue (napi_value value) override {
600- // Ignore any value returned from a setter callback.
601- }
602-
603- private:
604- const v8::Local<v8::Value>& _value;
605- };
606-
607- static void DeleteCallbackBundle (napi_env env, void * data, void * hint) {
608- CallbackBundle* bundle = static_cast <CallbackBundle*>(data);
609- delete bundle;
610- }
611-
612- // Creates an object to be made available to the static function callback
613- // wrapper, used to retrieve the native callback function and data pointer.
614- static
615- v8::Local<v8::Value> CreateFunctionCallbackData (napi_env env,
616- napi_callback cb,
617- void * data) {
618- CallbackBundle* bundle = new CallbackBundle ();
619- bundle->function_or_getter = cb;
620- bundle->cb_data = data;
621- bundle->env = env;
622- v8::Local<v8::Value> cbdata = v8::External::New (env->isolate , bundle);
623- Reference::New (env, cbdata, 0 , true , DeleteCallbackBundle, bundle, nullptr );
624-
625- return cbdata;
626- }
627-
628578enum WrapType {
629579 retrievable,
630580 anonymous
@@ -746,22 +696,12 @@ napi_status napi_create_function(napi_env env,
746696 CHECK_ARG (env, result);
747697 CHECK_ARG (env, cb);
748698
749- v8::Isolate* isolate = env->isolate ;
750699 v8::Local<v8::Function> return_value;
751- v8::EscapableHandleScope scope (isolate);
752- v8::Local<v8::Value> cbdata =
753- v8impl::CreateFunctionCallbackData (env, cb, callback_data);
754-
755- RETURN_STATUS_IF_FALSE (env, !cbdata.IsEmpty (), napi_generic_failure);
756-
757- v8::Local<v8::Context> context = env->context ();
758- v8::MaybeLocal<v8::Function> maybe_function =
759- v8::Function::New (context,
760- v8impl::FunctionCallbackWrapper::Invoke,
761- cbdata);
762- CHECK_MAYBE_EMPTY (env, maybe_function, napi_generic_failure);
763-
764- return_value = scope.Escape (maybe_function.ToLocalChecked ());
700+ v8::EscapableHandleScope scope (env->isolate );
701+ v8::Local<v8::Function> fn;
702+ STATUS_CALL (v8impl::FunctionCallbackWrapper::NewFunction (
703+ env, cb, callback_data, &fn));
704+ return_value = scope.Escape (fn);
765705
766706 if (utf8name != nullptr ) {
767707 v8::Local<v8::String> name_string;
@@ -793,13 +733,9 @@ napi_status napi_define_class(napi_env env,
793733 v8::Isolate* isolate = env->isolate ;
794734
795735 v8::EscapableHandleScope scope (isolate);
796- v8::Local<v8::Value> cbdata =
797- v8impl::CreateFunctionCallbackData (env, constructor, callback_data);
798-
799- RETURN_STATUS_IF_FALSE (env, !cbdata.IsEmpty (), napi_generic_failure);
800-
801- v8::Local<v8::FunctionTemplate> tpl = v8::FunctionTemplate::New (
802- isolate, v8impl::FunctionCallbackWrapper::Invoke, cbdata);
736+ v8::Local<v8::FunctionTemplate> tpl;
737+ STATUS_CALL (v8impl::FunctionCallbackWrapper::NewTemplate (
738+ env, constructor, callback_data, &tpl));
803739
804740 v8::Local<v8::String> name_string;
805741 CHECK_NEW_FROM_UTF8_LEN (env, name_string, utf8name, length);
@@ -829,18 +765,12 @@ napi_status napi_define_class(napi_env env,
829765 v8::Local<v8::FunctionTemplate> getter_tpl;
830766 v8::Local<v8::FunctionTemplate> setter_tpl;
831767 if (p->getter != nullptr ) {
832- v8::Local<v8::Value> getter_data =
833- v8impl::CreateFunctionCallbackData (env, p->getter , p->data );
834-
835- getter_tpl = v8::FunctionTemplate::New (
836- isolate, v8impl::FunctionCallbackWrapper::Invoke, getter_data);
768+ STATUS_CALL (v8impl::FunctionCallbackWrapper::NewTemplate (
769+ env, p->getter , p->data , &getter_tpl));
837770 }
838771 if (p->setter != nullptr ) {
839- v8::Local<v8::Value> setter_data =
840- v8impl::CreateFunctionCallbackData (env, p->setter , p->data );
841-
842- setter_tpl = v8::FunctionTemplate::New (
843- isolate, v8impl::FunctionCallbackWrapper::Invoke, setter_data);
772+ STATUS_CALL (v8impl::FunctionCallbackWrapper::NewTemplate (
773+ env, p->setter , p->data , &setter_tpl));
844774 }
845775
846776 tpl->PrototypeTemplate ()->SetAccessorProperty (
@@ -850,16 +780,9 @@ napi_status napi_define_class(napi_env env,
850780 attributes,
851781 v8::AccessControl::DEFAULT);
852782 } else if (p->method != nullptr ) {
853- v8::Local<v8::Value> cbdata =
854- v8impl::CreateFunctionCallbackData (env, p->method , p->data );
855-
856- RETURN_STATUS_IF_FALSE (env, !cbdata.IsEmpty (), napi_generic_failure);
857-
858- v8::Local<v8::FunctionTemplate> t =
859- v8::FunctionTemplate::New (isolate,
860- v8impl::FunctionCallbackWrapper::Invoke,
861- cbdata,
862- v8::Signature::New (isolate, tpl));
783+ v8::Local<v8::FunctionTemplate> t;
784+ STATUS_CALL (v8impl::FunctionCallbackWrapper::NewTemplate (
785+ env, p->method , p->data , &t, v8::Signature::New (isolate, tpl)));
863786
864787 tpl->PrototypeTemplate ()->Set (property_name, t, attributes);
865788 } else {
@@ -1264,33 +1187,16 @@ napi_status napi_define_properties(napi_env env,
12641187 STATUS_CALL (v8impl::V8NameFromPropertyDescriptor (env, p, &property_name));
12651188
12661189 if (p->getter != nullptr || p->setter != nullptr ) {
1267- v8::Local<v8::Value > local_getter;
1268- v8::Local<v8::Value > local_setter;
1190+ v8::Local<v8::Function > local_getter;
1191+ v8::Local<v8::Function > local_setter;
12691192
12701193 if (p->getter != nullptr ) {
1271- v8::Local<v8::Value> getter_data =
1272- v8impl::CreateFunctionCallbackData (env, p->getter , p->data );
1273- CHECK_MAYBE_EMPTY (env, getter_data, napi_generic_failure);
1274-
1275- v8::MaybeLocal<v8::Function> maybe_getter =
1276- v8::Function::New (context,
1277- v8impl::FunctionCallbackWrapper::Invoke,
1278- getter_data);
1279- CHECK_MAYBE_EMPTY (env, maybe_getter, napi_generic_failure);
1280-
1281- local_getter = maybe_getter.ToLocalChecked ();
1194+ STATUS_CALL (v8impl::FunctionCallbackWrapper::NewFunction (
1195+ env, p->getter , p->data , &local_getter));
12821196 }
12831197 if (p->setter != nullptr ) {
1284- v8::Local<v8::Value> setter_data =
1285- v8impl::CreateFunctionCallbackData (env, p->setter , p->data );
1286- CHECK_MAYBE_EMPTY (env, setter_data, napi_generic_failure);
1287-
1288- v8::MaybeLocal<v8::Function> maybe_setter =
1289- v8::Function::New (context,
1290- v8impl::FunctionCallbackWrapper::Invoke,
1291- setter_data);
1292- CHECK_MAYBE_EMPTY (env, maybe_setter, napi_generic_failure);
1293- local_setter = maybe_setter.ToLocalChecked ();
1198+ STATUS_CALL (v8impl::FunctionCallbackWrapper::NewFunction (
1199+ env, p->setter , p->data , &local_setter));
12941200 }
12951201
12961202 v8::PropertyDescriptor descriptor (local_getter, local_setter);
@@ -1305,19 +1211,10 @@ napi_status napi_define_properties(napi_env env,
13051211 return napi_set_last_error (env, napi_invalid_arg);
13061212 }
13071213 } else if (p->method != nullptr ) {
1308- v8::Local<v8::Value> cbdata =
1309- v8impl::CreateFunctionCallbackData (env, p->method , p->data );
1310-
1311- CHECK_MAYBE_EMPTY (env, cbdata, napi_generic_failure);
1312-
1313- v8::MaybeLocal<v8::Function> maybe_fn =
1314- v8::Function::New (context,
1315- v8impl::FunctionCallbackWrapper::Invoke,
1316- cbdata);
1317-
1318- CHECK_MAYBE_EMPTY (env, maybe_fn, napi_generic_failure);
1319-
1320- v8::PropertyDescriptor descriptor (maybe_fn.ToLocalChecked (),
1214+ v8::Local<v8::Function> method;
1215+ STATUS_CALL (v8impl::FunctionCallbackWrapper::NewFunction (
1216+ env, p->method , p->data , &method));
1217+ v8::PropertyDescriptor descriptor (method,
13211218 (p->attributes & napi_writable) != 0 );
13221219 descriptor.set_enumerable ((p->attributes & napi_enumerable) != 0 );
13231220 descriptor.set_configurable ((p->attributes & napi_configurable) != 0 );
0 commit comments