diff options
Diffstat (limited to 'src/node_api.cc')
-rw-r--r-- | src/node_api.cc | 275 |
1 files changed, 121 insertions, 154 deletions
diff --git a/src/node_api.cc b/src/node_api.cc index 1e7651c426..418a18c8a0 100644 --- a/src/node_api.cc +++ b/src/node_api.cc @@ -36,6 +36,70 @@ class napi_env__ { napi_extended_error_info last_error; }; +#define RETURN_STATUS_IF_FALSE(env, condition, status) \ + do { \ + if (!(condition)) { \ + return napi_set_last_error((env), (status)); \ + } \ + } while (0) + +#define CHECK_ENV(env) \ + if ((env) == nullptr) { \ + node::FatalError(__func__, "environment(env) must not be null"); \ + } + +#define CHECK_ARG(env, arg) \ + RETURN_STATUS_IF_FALSE((env), ((arg) != nullptr), napi_invalid_arg) + +#define CHECK_MAYBE_EMPTY(env, maybe, status) \ + RETURN_STATUS_IF_FALSE((env), !((maybe).IsEmpty()), (status)) + +#define CHECK_MAYBE_NOTHING(env, maybe, status) \ + RETURN_STATUS_IF_FALSE((env), !((maybe).IsNothing()), (status)) + +// NAPI_PREAMBLE is not wrapped in do..while: try_catch must have function scope +#define NAPI_PREAMBLE(env) \ + CHECK_ENV((env)); \ + RETURN_STATUS_IF_FALSE((env), (env)->last_exception.IsEmpty(), \ + napi_pending_exception); \ + napi_clear_last_error((env)); \ + v8impl::TryCatch try_catch((env)) + +#define CHECK_TO_TYPE(env, type, context, result, src, status) \ + do { \ + auto maybe = v8impl::V8LocalValueFromJsValue((src))->To##type((context)); \ + CHECK_MAYBE_EMPTY((env), maybe, (status)); \ + (result) = maybe.ToLocalChecked(); \ + } while (0) + +#define CHECK_TO_OBJECT(env, context, result, src) \ + CHECK_TO_TYPE((env), Object, (context), (result), (src), napi_object_expected) + +#define CHECK_TO_STRING(env, context, result, src) \ + CHECK_TO_TYPE((env), String, (context), (result), (src), napi_string_expected) + +#define CHECK_TO_NUMBER(env, context, result, src) \ + CHECK_TO_TYPE((env), Number, (context), (result), (src), napi_number_expected) + +#define CHECK_TO_BOOL(env, context, result, src) \ + CHECK_TO_TYPE((env), Boolean, (context), (result), (src), \ + napi_boolean_expected) + +#define CHECK_NEW_FROM_UTF8_LEN(env, result, str, len) \ + do { \ + auto str_maybe = v8::String::NewFromUtf8( \ + (env)->isolate, (str), v8::NewStringType::kInternalized, (len)); \ + CHECK_MAYBE_EMPTY((env), str_maybe, napi_generic_failure); \ + (result) = str_maybe.ToLocalChecked(); \ + } while (0) + +#define CHECK_NEW_FROM_UTF8(env, result, str) \ + CHECK_NEW_FROM_UTF8_LEN((env), (result), (str), -1) + +#define GET_RETURN_STATUS(env) \ + (!try_catch.HasCaught() ? napi_ok \ + : napi_set_last_error((env), napi_pending_exception)) + namespace v8impl { // convert from n-api property attributes to v8::PropertyAttribute @@ -127,6 +191,22 @@ v8::Local<v8::Value> V8LocalValueFromJsValue(napi_value v) { return local; } +static inline napi_status V8NameFromPropertyDescriptor(napi_env env, + const napi_property_descriptor* p, + v8::Local<v8::Name>* result) { + if (p->utf8name != nullptr) { + CHECK_NEW_FROM_UTF8(env, *result, p->utf8name); + } else { + v8::Local<v8::Value> property_value = + v8impl::V8LocalValueFromJsValue(p->name); + + RETURN_STATUS_IF_FALSE(env, property_value->IsName(), napi_name_expected); + *result = property_value.As<v8::Name>(); + } + + return napi_ok; +} + // Adapter for napi_finalize callbacks. class Finalizer { protected: @@ -361,13 +441,19 @@ class CallbackWrapperBase : public CallbackWrapper { v8::Local<v8::External>::Cast( _cbdata->GetInternalField(kInternalFieldIndex))->Value()); v8::Isolate* isolate = _cbinfo.GetIsolate(); + napi_env env = static_cast<napi_env>( v8::Local<v8::External>::Cast( _cbdata->GetInternalField(kEnvIndex))->Value()); // Make sure any errors encountered last time we were in N-API are gone. napi_clear_last_error(env); - cb(env, cbinfo_wrapper); + + napi_value result = cb(env, cbinfo_wrapper); + + if (result != nullptr) { + this->SetReturnValue(result); + } if (!env->last_exception.IsEmpty()) { isolate->ThrowException( @@ -608,75 +694,12 @@ void napi_module_register(napi_module* mod) { node::node_module_register(nm); } -#define RETURN_STATUS_IF_FALSE(env, condition, status) \ - do { \ - if (!(condition)) { \ - return napi_set_last_error((env), (status)); \ - } \ - } while (0) - -#define CHECK_ENV(env) \ - if ((env) == nullptr) { \ - node::FatalError(__func__, "environment(env) must not be null"); \ - } - -#define CHECK_ARG(env, arg) \ - RETURN_STATUS_IF_FALSE((env), ((arg) != nullptr), napi_invalid_arg) - -#define CHECK_MAYBE_EMPTY(env, maybe, status) \ - RETURN_STATUS_IF_FALSE((env), !((maybe).IsEmpty()), (status)) - -#define CHECK_MAYBE_NOTHING(env, maybe, status) \ - RETURN_STATUS_IF_FALSE((env), !((maybe).IsNothing()), (status)) - -// NAPI_PREAMBLE is not wrapped in do..while: try_catch must have function scope -#define NAPI_PREAMBLE(env) \ - CHECK_ENV((env)); \ - RETURN_STATUS_IF_FALSE((env), (env)->last_exception.IsEmpty(), \ - napi_pending_exception); \ - napi_clear_last_error((env)); \ - v8impl::TryCatch try_catch((env)) - -#define CHECK_TO_TYPE(env, type, context, result, src, status) \ - do { \ - auto maybe = v8impl::V8LocalValueFromJsValue((src))->To##type((context)); \ - CHECK_MAYBE_EMPTY((env), maybe, (status)); \ - (result) = maybe.ToLocalChecked(); \ - } while (0) - -#define CHECK_TO_OBJECT(env, context, result, src) \ - CHECK_TO_TYPE((env), Object, (context), (result), (src), napi_object_expected) - -#define CHECK_TO_STRING(env, context, result, src) \ - CHECK_TO_TYPE((env), String, (context), (result), (src), napi_string_expected) - -#define CHECK_TO_NUMBER(env, context, result, src) \ - CHECK_TO_TYPE((env), Number, (context), (result), (src), napi_number_expected) - -#define CHECK_TO_BOOL(env, context, result, src) \ - CHECK_TO_TYPE((env), Boolean, (context), (result), (src), \ - napi_boolean_expected) - -#define CHECK_NEW_FROM_UTF8_LEN(env, result, str, len) \ - do { \ - auto str_maybe = v8::String::NewFromUtf8( \ - (env)->isolate, (str), v8::NewStringType::kInternalized, (len)); \ - CHECK_MAYBE_EMPTY((env), str_maybe, napi_generic_failure); \ - result = str_maybe.ToLocalChecked(); \ - } while (0) - -#define CHECK_NEW_FROM_UTF8(env, result, str) \ - CHECK_NEW_FROM_UTF8_LEN((env), (result), (str), -1) - -#define GET_RETURN_STATUS(env) \ - (!try_catch.HasCaught() ? napi_ok \ - : napi_set_last_error((env), napi_pending_exception)) - // Warning: Keep in-sync with napi_status enum const char* error_messages[] = {nullptr, "Invalid pointer passed as argument", "An object was expected", "A string was expected", + "A string or symbol was expected", "A function was expected", "A number was expected", "A boolean was expected", @@ -793,8 +816,14 @@ napi_status napi_define_class(napi_env env, continue; } - v8::Local<v8::String> property_name; - CHECK_NEW_FROM_UTF8(env, property_name, p->utf8name); + v8::Local<v8::Name> property_name; + napi_status status = + v8impl::V8NameFromPropertyDescriptor(env, p, &property_name); + + if (status != napi_ok) { + return napi_set_last_error(env, status); + } + v8::PropertyAttribute attributes = v8impl::V8PropertyAttributesFromDescriptor(p); @@ -822,7 +851,6 @@ napi_status napi_define_class(napi_env env, v8impl::FunctionCallbackWrapper::Invoke, cbdata, v8::Signature::New(isolate, tpl)); - t->SetClassName(property_name); tpl->PrototypeTemplate()->Set(property_name, t, attributes); } else { @@ -855,18 +883,6 @@ napi_status napi_define_class(napi_env env, return GET_RETURN_STATUS(env); } -napi_status napi_set_return_value(napi_env env, - napi_callback_info cbinfo, - napi_value value) { - NAPI_PREAMBLE(env); - - v8impl::CallbackWrapper* info = - reinterpret_cast<v8impl::CallbackWrapper*>(cbinfo); - - info->SetReturnValue(value); - return GET_RETURN_STATUS(env); -} - napi_status napi_get_property_names(napi_env env, napi_value object, napi_value* result) { @@ -1102,11 +1118,16 @@ napi_status napi_define_properties(napi_env env, for (size_t i = 0; i < property_count; i++) { const napi_property_descriptor* p = &properties[i]; - v8::Local<v8::Name> name; - CHECK_NEW_FROM_UTF8(env, name, p->utf8name); + v8::Local<v8::Name> property_name; + napi_status status = + v8impl::V8NameFromPropertyDescriptor(env, p, &property_name); + + if (status != napi_ok) { + return napi_set_last_error(env, status); + } v8::PropertyAttribute attributes = - v8impl::V8PropertyAttributesFromDescriptor(p); + v8impl::V8PropertyAttributesFromDescriptor(p); if (p->getter != nullptr || p->setter != nullptr) { v8::Local<v8::Object> cbdata = v8impl::CreateAccessorCallbackData( @@ -1117,7 +1138,7 @@ napi_status napi_define_properties(napi_env env, auto set_maybe = obj->SetAccessor( context, - name, + property_name, p->getter ? v8impl::GetterCallbackWrapper::Invoke : nullptr, p->setter ? v8impl::SetterCallbackWrapper::Invoke : nullptr, cbdata, @@ -1136,8 +1157,8 @@ napi_status napi_define_properties(napi_env env, v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New( isolate, v8impl::FunctionCallbackWrapper::Invoke, cbdata); - auto define_maybe = - obj->DefineOwnProperty(context, name, t->GetFunction(), attributes); + auto define_maybe = obj->DefineOwnProperty( + context, property_name, t->GetFunction(), attributes); if (!define_maybe.FromMaybe(false)) { return napi_set_last_error(env, napi_generic_failure); @@ -1146,7 +1167,7 @@ napi_status napi_define_properties(napi_env env, v8::Local<v8::Value> value = v8impl::V8LocalValueFromJsValue(p->value); auto define_maybe = - obj->DefineOwnProperty(context, name, value, attributes); + obj->DefineOwnProperty(context, property_name, value, attributes); if (!define_maybe.FromMaybe(false)) { return napi_set_last_error(env, napi_invalid_arg); @@ -1439,33 +1460,24 @@ napi_status napi_get_cb_info( napi_value* this_arg, // [out] Receives the JS 'this' arg for the call void** data) { // [out] Receives the data pointer for the callback. CHECK_ENV(env); - CHECK_ARG(env, argc); - CHECK_ARG(env, argv); - CHECK_ARG(env, this_arg); - CHECK_ARG(env, data); v8impl::CallbackWrapper* info = reinterpret_cast<v8impl::CallbackWrapper*>(cbinfo); - info->Args(argv, std::min(*argc, info->ArgsLength())); - *argc = info->ArgsLength(); - *this_arg = info->This(); - *data = info->Data(); - - return napi_ok; -} - -napi_status napi_get_cb_args_length(napi_env env, - napi_callback_info cbinfo, - size_t* result) { - // Omit NAPI_PREAMBLE and GET_RETURN_STATUS because no V8 APIs are called. - CHECK_ENV(env); - CHECK_ARG(env, result); - - v8impl::CallbackWrapper* info = - reinterpret_cast<v8impl::CallbackWrapper*>(cbinfo); + if (argv != nullptr) { + CHECK_ARG(env, argc); + info->Args(argv, std::min(*argc, info->ArgsLength())); + } + if (argc != nullptr) { + *argc = info->ArgsLength(); + } + if (this_arg != nullptr) { + *this_arg = info->This(); + } + if (data != nullptr) { + *data = info->Data(); + } - *result = info->ArgsLength(); return napi_ok; } @@ -1483,51 +1495,6 @@ napi_status napi_is_construct_call(napi_env env, return napi_ok; } -// copy encoded arguments into provided buffer or return direct pointer to -// encoded arguments array? -napi_status napi_get_cb_args(napi_env env, - napi_callback_info cbinfo, - napi_value* buf, - size_t bufsize) { - // Omit NAPI_PREAMBLE and GET_RETURN_STATUS because no V8 APIs are called. - CHECK_ENV(env); - CHECK_ARG(env, buf); - - v8impl::CallbackWrapper* info = - reinterpret_cast<v8impl::CallbackWrapper*>(cbinfo); - - info->Args(buf, bufsize); - return napi_ok; -} - -napi_status napi_get_cb_this(napi_env env, - napi_callback_info cbinfo, - napi_value* result) { - // Omit NAPI_PREAMBLE and GET_RETURN_STATUS because no V8 APIs are called. - CHECK_ENV(env); - CHECK_ARG(env, result); - - v8impl::CallbackWrapper* info = - reinterpret_cast<v8impl::CallbackWrapper*>(cbinfo); - - *result = info->This(); - return napi_ok; -} - -napi_status napi_get_cb_data(napi_env env, - napi_callback_info cbinfo, - void** result) { - // Omit NAPI_PREAMBLE and GET_RETURN_STATUS because no V8 APIs are called. - CHECK_ENV(env); - CHECK_ARG(env, result); - - v8impl::CallbackWrapper* info = - reinterpret_cast<v8impl::CallbackWrapper*>(cbinfo); - - *result = info->Data(); - return napi_ok; -} - napi_status napi_call_function(napi_env env, napi_value recv, napi_value func, |