Skip to content

Commit 26ee991

Browse files
author
Gabriel Schulhof
committed
n-api: clean up binding creation
* Remove dead code for `GetterCallbackWrapper` and `SetterCallbackWrapper`. * Factor out creation of new `v8::Function`s. * Factor out creation of new `v8::FunctionTemplate`s. * Turn `CallbackBundle` into a class, internalizing creation of new instances and garbage collection. Signed-off-by: Gabriel Schulhof <gabriel.schulhof@intel.com> PR-URL: #36170
1 parent 2fd2235 commit 26ee991

File tree

1 file changed

+80
-183
lines changed

1 file changed

+80
-183
lines changed

src/js_native_api_v8.cc

Lines changed: 80 additions & 183 deletions
Original file line numberDiff line numberDiff line change
@@ -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.
431449
class 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>
453470
class 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

490506
class 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-
628578
enum 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

Comments
 (0)