diff --git a/node.gyp b/node.gyp index 28db2a955b74d6..cf82aa995e2b52 100644 --- a/node.gyp +++ b/node.gyp @@ -950,8 +950,11 @@ 'NODE_PLATFORM="<(OS)"', 'NODE_WANT_INTERNALS=1', # Define NAPI_EXPERIMENTAL to enable Node-API experimental function symbols being exposed. - 'NAPI_EXPERIMENTAL=1', - 'NODE_API_EXPERIMENTAL_NO_WARNING=1', + 'NAPI_EXPERIMENTAL', + # Suppress warning about using experimental Node-API features. + 'NODE_API_EXPERIMENTAL_NO_WARNING', + # Enable Node-API headers to support v-table. + 'NODE_API_RUNTIME_USE_VTABLE', # Warn when using deprecated V8 APIs. 'V8_DEPRECATION_WARNINGS=1', 'NODE_OPENSSL_SYSTEM_CERT_PATH="<(openssl_system_ca_path)"', @@ -1381,6 +1384,9 @@ 'NODE_ARCH="<(target_arch)"', 'NODE_PLATFORM="<(OS)"', 'NODE_WANT_INTERNALS=1', + 'NAPI_EXPERIMENTAL', + 'NODE_API_EXPERIMENTAL_NO_WARNING', + 'NODE_API_RUNTIME_USE_VTABLE', ], 'sources': [ '<@(node_cctest_sources)' ], diff --git a/src/js_native_api.h b/src/js_native_api.h index d2375ecd32483f..ae15625b5b4f11 100644 --- a/src/js_native_api.h +++ b/src/js_native_api.h @@ -1,10 +1,6 @@ #ifndef SRC_JS_NATIVE_API_H_ #define SRC_JS_NATIVE_API_H_ -// This file needs to be compatible with C compilers. -#include // NOLINT(modernize-deprecated-headers) -#include // NOLINT(modernize-deprecated-headers) - #include "js_native_api_types.h" // If you need __declspec(dllimport), either include instead, or @@ -31,25 +27,146 @@ #define EXTERN_C_END #endif +#if defined(NODE_API_MODULE_USE_VTABLE) && \ + !defined(NODE_API_MODULE_NO_VTABLE_IMPL) +#define NODE_API_MODULE_USE_VTABLE_IMPL +#endif + +#ifdef NODE_API_MODULE_USE_VTABLE_IMPL + +// Implement all Node-API functions via vtable indirection. +#undef NAPI_EXTERN +#define NAPI_EXTERN static inline + +#ifndef NODE_API_MODULE_NO_VTABLE_FALLBACK + +extern node_api_js_vtable g_node_api_js_vtable_fallback; + +// Atomic pointer write with release semantics for thread-safe lazy init. +#ifndef NODE_API_WRITE_POINTER_RELEASE +// NOLINTBEGIN (readability/casting) - must be compilable by C compiler +#ifdef _MSC_VER +#include +#define NODE_API_WRITE_POINTER_RELEASE(ptr, val) \ + (void)_InterlockedExchangePointer((void* volatile*)(ptr), (void*)(val)) +#else +#define NODE_API_WRITE_POINTER_RELEASE(ptr, val) \ + __atomic_store_n((void**)(ptr), (void*)(val), __ATOMIC_RELEASE) +#endif +// NOLINTEND (readability/casting) +#endif // NODE_API_WRITE_POINTER_RELEASE + +#ifndef NODE_API_LOAD_SYMBOL +#ifdef _WIN32 +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif +#ifndef NOMINMAX +#define NOMINMAX +#endif +#include + +// NOLINTBEGIN (readability/null_usage) - must be compilable by C compiler +static inline HMODULE node_api_get_runtime_module_handle(void) { + static HMODULE module_handle = NULL; + HMODULE handle = module_handle; + if (handle == NULL) { + // Match the code in win_delay_load_hook.cc from node-gyp. + handle = GetModuleHandleA("libnode.dll"); + if (handle == NULL) { + handle = GetModuleHandleA(NULL); + } + NODE_API_WRITE_POINTER_RELEASE(&module_handle, handle); + } + return handle; +} +// NOLINTEND (readability/null_usage) + +#define NODE_API_LOAD_SYMBOL(name) \ + GetProcAddress(node_api_get_runtime_module_handle(), name) +#else +#include +#define NODE_API_LOAD_SYMBOL(name) dlsym(RTLD_DEFAULT, name) +#endif // _WIN32 +#endif // NODE_API_LOAD_SYMBOL + +#define NODE_API_VTABLE_IMPL_FALLBACK( \ + ret, vtable, func_name, method_name, ...) \ + const node_api_##vtable* vtable = &g_node_api_##vtable##_fallback; \ + if (!vtable->method_name) { \ + NODE_API_WRITE_POINTER_RELEASE(&vtable->method_name, \ + NODE_API_LOAD_SYMBOL(#func_name)); \ + } \ + ret vtable->method_name(__VA_ARGS__) + +#else // NODE_API_MODULE_NO_VTABLE_FALLBACK + +#ifndef NODE_API_UNREACHABLE +#ifdef _MSC_VER +#define NODE_API_UNREACHABLE() __fastfail(7 /* FAST_FAIL_FATAL_APP_EXIT */) +#else +#define NODE_API_UNREACHABLE() __builtin_trap() +#endif +#endif // NODE_API_UNREACHABLE + +#define NODE_API_VTABLE_IMPL_FALLBACK(...) NODE_API_UNREACHABLE() + +#endif // NODE_API_MODULE_NO_VTABLE_FALLBACK + +#define NODE_API_VTABLE_IMPL_BASE(vtable, func_name, method_name, obj, ...) \ + { \ + if (!obj) { \ + return napi_invalid_arg; \ + } else if (obj->sentinel == NODE_API_VT_SENTINEL) { \ + return obj->vtable->method_name(__VA_ARGS__); \ + } else { \ + NODE_API_VTABLE_IMPL_FALLBACK( \ + return, vtable, func_name, method_name, __VA_ARGS__); \ + } \ + } + +#define NODE_API_JS_VTABLE_IMPL(func_name, method_name, env, ...) \ + NODE_API_VTABLE_IMPL_BASE( \ + js_vtable, func_name, method_name, env, env, __VA_ARGS__) + +#else // NODE_API_MODULE_USE_VTABLE_IMPL + +#define NODE_API_JS_VTABLE_IMPL(...) + +#endif // NODE_API_MODULE_USE_VTABLE_IMPL + EXTERN_C_START NAPI_EXTERN napi_status NAPI_CDECL napi_get_last_error_info( - node_api_basic_env env, const napi_extended_error_info** result); + node_api_basic_env env, const napi_extended_error_info** result) + NODE_API_JS_VTABLE_IMPL(napi_get_last_error_info, + get_last_error_info, + env, + result); // Getters for defined singletons NAPI_EXTERN napi_status NAPI_CDECL napi_get_undefined(napi_env env, - napi_value* result); + napi_value* result) + NODE_API_JS_VTABLE_IMPL(napi_get_undefined, get_undefined, env, result); + NAPI_EXTERN napi_status NAPI_CDECL napi_get_null(napi_env env, - napi_value* result); + napi_value* result) + NODE_API_JS_VTABLE_IMPL(napi_get_null, get_null, env, result); + NAPI_EXTERN napi_status NAPI_CDECL napi_get_global(napi_env env, - napi_value* result); + napi_value* result) + NODE_API_JS_VTABLE_IMPL(napi_get_global, get_global, env, result); + NAPI_EXTERN napi_status NAPI_CDECL napi_get_boolean(napi_env env, bool value, - napi_value* result); + napi_value* result) + NODE_API_JS_VTABLE_IMPL(napi_get_boolean, get_boolean, env, value, result); // Methods to create Primitive types/Objects NAPI_EXTERN napi_status NAPI_CDECL napi_create_object(napi_env env, - napi_value* result); + napi_value* result) + NODE_API_JS_VTABLE_IMPL(napi_create_object, create_object, env, result); + #ifdef NAPI_EXPERIMENTAL #define NODE_API_EXPERIMENTAL_HAS_CREATE_OBJECT_WITH_PROPERTIES NAPI_EXTERN napi_status NAPI_CDECL @@ -58,35 +175,82 @@ node_api_create_object_with_properties(napi_env env, napi_value* property_names, napi_value* property_values, size_t property_count, - napi_value* result); + napi_value* result) + NODE_API_JS_VTABLE_IMPL(node_api_create_object_with_properties, + create_object_with_properties, + env, + prototype_or_null, + property_names, + property_values, + property_count, + result); #endif // NAPI_EXPERIMENTAL NAPI_EXTERN napi_status NAPI_CDECL napi_create_array(napi_env env, - napi_value* result); + napi_value* result) + NODE_API_JS_VTABLE_IMPL(napi_create_array, create_array, env, result); + NAPI_EXTERN napi_status NAPI_CDECL -napi_create_array_with_length(napi_env env, size_t length, napi_value* result); +napi_create_array_with_length(napi_env env, size_t length, napi_value* result) + NODE_API_JS_VTABLE_IMPL(napi_create_array_with_length, + create_array_with_length, + env, + length, + result); + NAPI_EXTERN napi_status NAPI_CDECL napi_create_double(napi_env env, double value, - napi_value* result); + napi_value* result) + NODE_API_JS_VTABLE_IMPL( + napi_create_double, create_double, env, value, result); + NAPI_EXTERN napi_status NAPI_CDECL napi_create_int32(napi_env env, int32_t value, - napi_value* result); + napi_value* result) + NODE_API_JS_VTABLE_IMPL( + napi_create_int32, create_int32, env, value, result); + NAPI_EXTERN napi_status NAPI_CDECL napi_create_uint32(napi_env env, uint32_t value, - napi_value* result); + napi_value* result) + NODE_API_JS_VTABLE_IMPL( + napi_create_uint32, create_uint32, env, value, result); + NAPI_EXTERN napi_status NAPI_CDECL napi_create_int64(napi_env env, int64_t value, - napi_value* result); -NAPI_EXTERN napi_status NAPI_CDECL napi_create_string_latin1( - napi_env env, const char* str, size_t length, napi_value* result); + napi_value* result) + NODE_API_JS_VTABLE_IMPL( + napi_create_int64, create_int64, env, value, result); + +NAPI_EXTERN napi_status NAPI_CDECL napi_create_string_latin1(napi_env env, + const char* str, + size_t length, + napi_value* result) + NODE_API_JS_VTABLE_IMPL(napi_create_string_latin1, + create_string_latin1, + env, + str, + length, + result); + NAPI_EXTERN napi_status NAPI_CDECL napi_create_string_utf8(napi_env env, const char* str, size_t length, - napi_value* result); + napi_value* result) + NODE_API_JS_VTABLE_IMPL( + napi_create_string_utf8, create_string_utf8, env, str, length, result); + NAPI_EXTERN napi_status NAPI_CDECL napi_create_string_utf16(napi_env env, const char16_t* str, size_t length, - napi_value* result); + napi_value* result) + NODE_API_JS_VTABLE_IMPL(napi_create_string_utf16, + create_string_utf16, + env, + str, + length, + result); + #if NAPI_VERSION >= 10 NAPI_EXTERN napi_status NAPI_CDECL node_api_create_external_string_latin1( napi_env env, @@ -95,187 +259,365 @@ NAPI_EXTERN napi_status NAPI_CDECL node_api_create_external_string_latin1( node_api_basic_finalize finalize_callback, void* finalize_hint, napi_value* result, - bool* copied); -NAPI_EXTERN napi_status NAPI_CDECL -node_api_create_external_string_utf16(napi_env env, - char16_t* str, - size_t length, - node_api_basic_finalize finalize_callback, - void* finalize_hint, - napi_value* result, - bool* copied); + bool* copied) + NODE_API_JS_VTABLE_IMPL(node_api_create_external_string_latin1, + create_external_string_latin1, + env, + str, + length, + finalize_callback, + finalize_hint, + result, + copied); + +NAPI_EXTERN napi_status NAPI_CDECL node_api_create_external_string_utf16( + napi_env env, + char16_t* str, + size_t length, + node_api_basic_finalize finalize_callback, + void* finalize_hint, + napi_value* result, + bool* copied) NODE_API_JS_VTABLE_IMPL(node_api_create_external_string_utf16, + create_external_string_utf16, + env, + str, + length, + finalize_callback, + finalize_hint, + result, + copied); NAPI_EXTERN napi_status NAPI_CDECL node_api_create_property_key_latin1( - napi_env env, const char* str, size_t length, napi_value* result); + napi_env env, const char* str, size_t length, napi_value* result) + NODE_API_JS_VTABLE_IMPL(node_api_create_property_key_latin1, + create_property_key_latin1, + env, + str, + length, + result); + NAPI_EXTERN napi_status NAPI_CDECL node_api_create_property_key_utf8( - napi_env env, const char* str, size_t length, napi_value* result); + napi_env env, const char* str, size_t length, napi_value* result) + NODE_API_JS_VTABLE_IMPL(node_api_create_property_key_utf8, + create_property_key_utf8, + env, + str, + length, + result); + NAPI_EXTERN napi_status NAPI_CDECL node_api_create_property_key_utf16( - napi_env env, const char16_t* str, size_t length, napi_value* result); + napi_env env, const char16_t* str, size_t length, napi_value* result) + NODE_API_JS_VTABLE_IMPL(node_api_create_property_key_utf16, + create_property_key_utf16, + env, + str, + length, + result); + #endif // NAPI_VERSION >= 10 NAPI_EXTERN napi_status NAPI_CDECL napi_create_symbol(napi_env env, napi_value description, - napi_value* result); + napi_value* result) + NODE_API_JS_VTABLE_IMPL( + napi_create_symbol, create_symbol, env, description, result); + #if NAPI_VERSION >= 9 NAPI_EXTERN napi_status NAPI_CDECL node_api_symbol_for(napi_env env, const char* utf8description, size_t length, - napi_value* result); + napi_value* result) + NODE_API_JS_VTABLE_IMPL( + node_api_symbol_for, symbol_for, env, utf8description, length, result); #endif // NAPI_VERSION >= 9 NAPI_EXTERN napi_status NAPI_CDECL napi_create_function(napi_env env, const char* utf8name, size_t length, napi_callback cb, void* data, - napi_value* result); + napi_value* result) + NODE_API_JS_VTABLE_IMPL(napi_create_function, + create_function, + env, + utf8name, + length, + cb, + data, + result); + NAPI_EXTERN napi_status NAPI_CDECL napi_create_error(napi_env env, napi_value code, napi_value msg, - napi_value* result); + napi_value* result) + NODE_API_JS_VTABLE_IMPL( + napi_create_error, create_error, env, code, msg, result); + NAPI_EXTERN napi_status NAPI_CDECL napi_create_type_error(napi_env env, napi_value code, napi_value msg, - napi_value* result); + napi_value* result) + NODE_API_JS_VTABLE_IMPL( + napi_create_type_error, create_type_error, env, code, msg, result); + NAPI_EXTERN napi_status NAPI_CDECL napi_create_range_error(napi_env env, napi_value code, napi_value msg, - napi_value* result); + napi_value* result) + NODE_API_JS_VTABLE_IMPL( + napi_create_range_error, create_range_error, env, code, msg, result); + #if NAPI_VERSION >= 9 NAPI_EXTERN napi_status NAPI_CDECL node_api_create_syntax_error( - napi_env env, napi_value code, napi_value msg, napi_value* result); + napi_env env, napi_value code, napi_value msg, napi_value* result) + NODE_API_JS_VTABLE_IMPL(node_api_create_syntax_error, + create_syntax_error, + env, + code, + msg, + result); #endif // NAPI_VERSION >= 9 // Methods to get the native napi_value from Primitive type NAPI_EXTERN napi_status NAPI_CDECL napi_typeof(napi_env env, napi_value value, - napi_valuetype* result); + napi_valuetype* result) + NODE_API_JS_VTABLE_IMPL(napi_typeof, type_of, env, value, result); + NAPI_EXTERN napi_status NAPI_CDECL napi_get_value_double(napi_env env, napi_value value, - double* result); + double* result) + NODE_API_JS_VTABLE_IMPL( + napi_get_value_double, get_value_double, env, value, result); + NAPI_EXTERN napi_status NAPI_CDECL napi_get_value_int32(napi_env env, napi_value value, - int32_t* result); + int32_t* result) + NODE_API_JS_VTABLE_IMPL( + napi_get_value_int32, get_value_int32, env, value, result); + NAPI_EXTERN napi_status NAPI_CDECL napi_get_value_uint32(napi_env env, napi_value value, - uint32_t* result); + uint32_t* result) + NODE_API_JS_VTABLE_IMPL( + napi_get_value_uint32, get_value_uint32, env, value, result); + NAPI_EXTERN napi_status NAPI_CDECL napi_get_value_int64(napi_env env, napi_value value, - int64_t* result); + int64_t* result) + NODE_API_JS_VTABLE_IMPL( + napi_get_value_int64, get_value_int64, env, value, result); + NAPI_EXTERN napi_status NAPI_CDECL napi_get_value_bool(napi_env env, napi_value value, - bool* result); + bool* result) + NODE_API_JS_VTABLE_IMPL( + napi_get_value_bool, get_value_bool, env, value, result); // Copies LATIN-1 encoded bytes from a string into a buffer. NAPI_EXTERN napi_status NAPI_CDECL napi_get_value_string_latin1( - napi_env env, napi_value value, char* buf, size_t bufsize, size_t* result); + napi_env env, napi_value value, char* buf, size_t bufsize, size_t* result) + NODE_API_JS_VTABLE_IMPL(napi_get_value_string_latin1, + get_value_string_latin1, + env, + value, + buf, + bufsize, + result); // Copies UTF-8 encoded bytes from a string into a buffer. NAPI_EXTERN napi_status NAPI_CDECL napi_get_value_string_utf8( - napi_env env, napi_value value, char* buf, size_t bufsize, size_t* result); + napi_env env, napi_value value, char* buf, size_t bufsize, size_t* result) + NODE_API_JS_VTABLE_IMPL(napi_get_value_string_utf8, + get_value_string_utf8, + env, + value, + buf, + bufsize, + result); // Copies UTF-16 encoded bytes from a string into a buffer. NAPI_EXTERN napi_status NAPI_CDECL napi_get_value_string_utf16(napi_env env, napi_value value, char16_t* buf, size_t bufsize, - size_t* result); + size_t* result) + NODE_API_JS_VTABLE_IMPL(napi_get_value_string_utf16, + get_value_string_utf16, + env, + value, + buf, + bufsize, + result); // Methods to coerce values // These APIs may execute user scripts NAPI_EXTERN napi_status NAPI_CDECL napi_coerce_to_bool(napi_env env, napi_value value, - napi_value* result); + napi_value* result) + NODE_API_JS_VTABLE_IMPL( + napi_coerce_to_bool, coerce_to_bool, env, value, result); + NAPI_EXTERN napi_status NAPI_CDECL napi_coerce_to_number(napi_env env, napi_value value, - napi_value* result); + napi_value* result) + NODE_API_JS_VTABLE_IMPL( + napi_coerce_to_number, coerce_to_number, env, value, result); + NAPI_EXTERN napi_status NAPI_CDECL napi_coerce_to_object(napi_env env, napi_value value, - napi_value* result); + napi_value* result) + NODE_API_JS_VTABLE_IMPL( + napi_coerce_to_object, coerce_to_object, env, value, result); + NAPI_EXTERN napi_status NAPI_CDECL napi_coerce_to_string(napi_env env, napi_value value, - napi_value* result); + napi_value* result) + NODE_API_JS_VTABLE_IMPL( + napi_coerce_to_string, coerce_to_string, env, value, result); // Methods to work with Objects #ifdef NAPI_EXPERIMENTAL #define NODE_API_EXPERIMENTAL_HAS_SET_PROTOTYPE NAPI_EXTERN napi_status NAPI_CDECL node_api_set_prototype(napi_env env, napi_value object, - napi_value value); + napi_value value) + NODE_API_JS_VTABLE_IMPL( + node_api_set_prototype, set_prototype, env, object, value); #endif NAPI_EXTERN napi_status NAPI_CDECL napi_get_prototype(napi_env env, napi_value object, - napi_value* result); + napi_value* result) + NODE_API_JS_VTABLE_IMPL( + napi_get_prototype, get_prototype, env, object, result); + NAPI_EXTERN napi_status NAPI_CDECL napi_get_property_names(napi_env env, napi_value object, - napi_value* result); + napi_value* result) + NODE_API_JS_VTABLE_IMPL( + napi_get_property_names, get_property_names, env, object, result); + NAPI_EXTERN napi_status NAPI_CDECL napi_set_property(napi_env env, napi_value object, napi_value key, - napi_value value); -NAPI_EXTERN napi_status NAPI_CDECL napi_has_property(napi_env env, - napi_value object, - napi_value key, - bool* result); + napi_value value) + NODE_API_JS_VTABLE_IMPL( + napi_set_property, set_property, env, object, key, value); + +NAPI_EXTERN napi_status NAPI_CDECL +napi_has_property(napi_env env, napi_value object, napi_value key, bool* result) + NODE_API_JS_VTABLE_IMPL( + napi_has_property, has_property, env, object, key, result); + NAPI_EXTERN napi_status NAPI_CDECL napi_get_property(napi_env env, napi_value object, napi_value key, - napi_value* result); + napi_value* result) + NODE_API_JS_VTABLE_IMPL( + napi_get_property, get_property, env, object, key, result); + NAPI_EXTERN napi_status NAPI_CDECL napi_delete_property(napi_env env, napi_value object, napi_value key, - bool* result); + bool* result) + NODE_API_JS_VTABLE_IMPL( + napi_delete_property, delete_property, env, object, key, result); + NAPI_EXTERN napi_status NAPI_CDECL napi_has_own_property(napi_env env, napi_value object, napi_value key, - bool* result); + bool* result) + NODE_API_JS_VTABLE_IMPL( + napi_has_own_property, has_own_property, env, object, key, result); + NAPI_EXTERN napi_status NAPI_CDECL napi_set_named_property(napi_env env, napi_value object, const char* utf8name, - napi_value value); + napi_value value) + NODE_API_JS_VTABLE_IMPL(napi_set_named_property, + set_named_property, + env, + object, + utf8name, + value); + NAPI_EXTERN napi_status NAPI_CDECL napi_has_named_property(napi_env env, napi_value object, const char* utf8name, - bool* result); + bool* result) + NODE_API_JS_VTABLE_IMPL(napi_has_named_property, + has_named_property, + env, + object, + utf8name, + result); + NAPI_EXTERN napi_status NAPI_CDECL napi_get_named_property(napi_env env, napi_value object, const char* utf8name, - napi_value* result); + napi_value* result) + NODE_API_JS_VTABLE_IMPL(napi_get_named_property, + get_named_property, + env, + object, + utf8name, + result); + NAPI_EXTERN napi_status NAPI_CDECL napi_set_element(napi_env env, napi_value object, uint32_t index, - napi_value value); -NAPI_EXTERN napi_status NAPI_CDECL napi_has_element(napi_env env, - napi_value object, - uint32_t index, - bool* result); + napi_value value) + NODE_API_JS_VTABLE_IMPL( + napi_set_element, set_element, env, object, index, value); + +NAPI_EXTERN napi_status NAPI_CDECL +napi_has_element(napi_env env, napi_value object, uint32_t index, bool* result) + NODE_API_JS_VTABLE_IMPL( + napi_has_element, has_element, env, object, index, result); + NAPI_EXTERN napi_status NAPI_CDECL napi_get_element(napi_env env, napi_value object, uint32_t index, - napi_value* result); + napi_value* result) + NODE_API_JS_VTABLE_IMPL( + napi_get_element, get_element, env, object, index, result); + NAPI_EXTERN napi_status NAPI_CDECL napi_delete_element(napi_env env, napi_value object, uint32_t index, - bool* result); + bool* result) + NODE_API_JS_VTABLE_IMPL( + napi_delete_element, delete_element, env, object, index, result); + NAPI_EXTERN napi_status NAPI_CDECL napi_define_properties(napi_env env, napi_value object, size_t property_count, - const napi_property_descriptor* properties); + const napi_property_descriptor* properties) + NODE_API_JS_VTABLE_IMPL(napi_define_properties, + define_properties, + env, + object, + property_count, + properties); // Methods to work with Arrays NAPI_EXTERN napi_status NAPI_CDECL napi_is_array(napi_env env, napi_value value, - bool* result); + bool* result) + NODE_API_JS_VTABLE_IMPL(napi_is_array, is_array, env, value, result); + NAPI_EXTERN napi_status NAPI_CDECL napi_get_array_length(napi_env env, napi_value value, - uint32_t* result); + uint32_t* result) + NODE_API_JS_VTABLE_IMPL( + napi_get_array_length, get_array_length, env, value, result); // Methods to compare values -NAPI_EXTERN napi_status NAPI_CDECL napi_strict_equals(napi_env env, - napi_value lhs, - napi_value rhs, - bool* result); +NAPI_EXTERN napi_status NAPI_CDECL +napi_strict_equals(napi_env env, napi_value lhs, napi_value rhs, bool* result) + NODE_API_JS_VTABLE_IMPL( + napi_strict_equals, strict_equals, env, lhs, rhs, result); // Methods to work with Functions NAPI_EXTERN napi_status NAPI_CDECL napi_call_function(napi_env env, @@ -283,16 +625,25 @@ NAPI_EXTERN napi_status NAPI_CDECL napi_call_function(napi_env env, napi_value func, size_t argc, const napi_value* argv, - napi_value* result); + napi_value* result) + NODE_API_JS_VTABLE_IMPL( + napi_call_function, call_function, env, recv, func, argc, argv, result); + NAPI_EXTERN napi_status NAPI_CDECL napi_new_instance(napi_env env, napi_value constructor, size_t argc, const napi_value* argv, - napi_value* result); + napi_value* result) + NODE_API_JS_VTABLE_IMPL( + napi_new_instance, new_instance, env, constructor, argc, argv, result); + NAPI_EXTERN napi_status NAPI_CDECL napi_instanceof(napi_env env, napi_value object, napi_value constructor, - bool* result); + bool* result) + NODE_API_JS_VTABLE_IMPL(napi_instanceof, + instanceof + , env, object, constructor, result); // Methods to work with napi_callbacks @@ -304,10 +655,15 @@ NAPI_EXTERN napi_status NAPI_CDECL napi_get_cb_info( // and receives the actual count of args. napi_value* argv, // [out] Array of values napi_value* this_arg, // [out] Receives the JS 'this' arg for the call - void** data); // [out] Receives the data pointer for the callback. + void** data) // [out] Receives the data pointer for the callback. + NODE_API_JS_VTABLE_IMPL( + napi_get_cb_info, get_cb_info, env, cbinfo, argc, argv, this_arg, data); + +NAPI_EXTERN napi_status NAPI_CDECL +napi_get_new_target(napi_env env, napi_callback_info cbinfo, napi_value* result) + NODE_API_JS_VTABLE_IMPL( + napi_get_new_target, get_new_target, env, cbinfo, result); -NAPI_EXTERN napi_status NAPI_CDECL napi_get_new_target( - napi_env env, napi_callback_info cbinfo, napi_value* result); NAPI_EXTERN napi_status NAPI_CDECL napi_define_class(napi_env env, const char* utf8name, @@ -316,7 +672,16 @@ napi_define_class(napi_env env, void* data, size_t property_count, const napi_property_descriptor* properties, - napi_value* result); + napi_value* result) NODE_API_JS_VTABLE_IMPL(napi_define_class, + define_class, + env, + utf8name, + length, + constructor, + data, + property_count, + properties, + result); // Methods to work with external data objects NAPI_EXTERN napi_status NAPI_CDECL @@ -325,36 +690,62 @@ napi_wrap(napi_env env, void* native_object, node_api_basic_finalize finalize_cb, void* finalize_hint, - napi_ref* result); + napi_ref* result) NODE_API_JS_VTABLE_IMPL(napi_wrap, + wrap, + env, + js_object, + native_object, + finalize_cb, + finalize_hint, + result); + NAPI_EXTERN napi_status NAPI_CDECL napi_unwrap(napi_env env, napi_value js_object, - void** result); + void** result) + NODE_API_JS_VTABLE_IMPL(napi_unwrap, unwrap, env, js_object, result); + NAPI_EXTERN napi_status NAPI_CDECL napi_remove_wrap(napi_env env, napi_value js_object, - void** result); -NAPI_EXTERN napi_status NAPI_CDECL -napi_create_external(napi_env env, - void* data, - node_api_basic_finalize finalize_cb, - void* finalize_hint, - napi_value* result); + void** result) + NODE_API_JS_VTABLE_IMPL( + napi_remove_wrap, remove_wrap, env, js_object, result); + +NAPI_EXTERN napi_status NAPI_CDECL napi_create_external( + napi_env env, + void* data, + node_api_basic_finalize finalize_cb, + void* finalize_hint, + napi_value* result) NODE_API_JS_VTABLE_IMPL(napi_create_external, + create_external, + env, + data, + finalize_cb, + finalize_hint, + result); + NAPI_EXTERN napi_status NAPI_CDECL napi_get_value_external(napi_env env, napi_value value, - void** result); + void** result) + NODE_API_JS_VTABLE_IMPL( + napi_get_value_external, get_value_external, env, value, result); // Methods to control object lifespan // Set initial_refcount to 0 for a weak reference, >0 for a strong reference. -NAPI_EXTERN napi_status NAPI_CDECL -napi_create_reference(napi_env env, - napi_value value, - uint32_t initial_refcount, - napi_ref* result); +NAPI_EXTERN napi_status NAPI_CDECL napi_create_reference( + napi_env env, napi_value value, uint32_t initial_refcount, napi_ref* result) + NODE_API_JS_VTABLE_IMPL(napi_create_reference, + create_reference, + env, + value, + initial_refcount, + result); // Deletes a reference. The referenced value is released, and may // be GC'd unless there are other references to it. NAPI_EXTERN napi_status NAPI_CDECL napi_delete_reference(node_api_basic_env env, - napi_ref ref); + napi_ref ref) + NODE_API_JS_VTABLE_IMPL(napi_delete_reference, delete_reference, env, ref); // Increments the reference count, optionally returning the resulting count. // After this call the reference will be a strong reference because its @@ -363,7 +754,9 @@ NAPI_EXTERN napi_status NAPI_CDECL napi_delete_reference(node_api_basic_env env, // results in an error. NAPI_EXTERN napi_status NAPI_CDECL napi_reference_ref(napi_env env, napi_ref ref, - uint32_t* result); + uint32_t* result) + NODE_API_JS_VTABLE_IMPL( + napi_reference_ref, reference_ref, env, ref, result); // Decrements the reference count, optionally returning the resulting count. // If the result is 0 the reference is now weak and the object may be GC'd @@ -371,64 +764,122 @@ NAPI_EXTERN napi_status NAPI_CDECL napi_reference_ref(napi_env env, // refcount is already 0 results in an error. NAPI_EXTERN napi_status NAPI_CDECL napi_reference_unref(napi_env env, napi_ref ref, - uint32_t* result); + uint32_t* result) + NODE_API_JS_VTABLE_IMPL( + napi_reference_unref, reference_unref, env, ref, result); // Attempts to get a referenced value. If the reference is weak, // the value might no longer be available, in that case the call // is still successful but the result is NULL. NAPI_EXTERN napi_status NAPI_CDECL napi_get_reference_value(napi_env env, napi_ref ref, - napi_value* result); + napi_value* result) + NODE_API_JS_VTABLE_IMPL( + napi_get_reference_value, get_reference_value, env, ref, result); NAPI_EXTERN napi_status NAPI_CDECL -napi_open_handle_scope(napi_env env, napi_handle_scope* result); +napi_open_handle_scope(napi_env env, napi_handle_scope* result) + NODE_API_JS_VTABLE_IMPL(napi_open_handle_scope, + open_handle_scope, + env, + result); + NAPI_EXTERN napi_status NAPI_CDECL -napi_close_handle_scope(napi_env env, napi_handle_scope scope); +napi_close_handle_scope(napi_env env, napi_handle_scope scope) + NODE_API_JS_VTABLE_IMPL(napi_close_handle_scope, + close_handle_scope, + env, + scope); + NAPI_EXTERN napi_status NAPI_CDECL napi_open_escapable_handle_scope( - napi_env env, napi_escapable_handle_scope* result); + napi_env env, napi_escapable_handle_scope* result) + NODE_API_JS_VTABLE_IMPL(napi_open_escapable_handle_scope, + open_escapable_handle_scope, + env, + result); + NAPI_EXTERN napi_status NAPI_CDECL napi_close_escapable_handle_scope( - napi_env env, napi_escapable_handle_scope scope); + napi_env env, napi_escapable_handle_scope scope) + NODE_API_JS_VTABLE_IMPL(napi_close_escapable_handle_scope, + close_escapable_handle_scope, + env, + scope); NAPI_EXTERN napi_status NAPI_CDECL napi_escape_handle(napi_env env, napi_escapable_handle_scope scope, napi_value escapee, - napi_value* result); + napi_value* result) + NODE_API_JS_VTABLE_IMPL( + napi_escape_handle, escape_handle, env, scope, escapee, result); // Methods to support error handling -NAPI_EXTERN napi_status NAPI_CDECL napi_throw(napi_env env, napi_value error); +NAPI_EXTERN napi_status NAPI_CDECL napi_throw(napi_env env, napi_value error) + NODE_API_JS_VTABLE_IMPL(napi_throw, throw_value, env, error); + NAPI_EXTERN napi_status NAPI_CDECL napi_throw_error(napi_env env, const char* code, - const char* msg); + const char* msg) + NODE_API_JS_VTABLE_IMPL(napi_throw_error, throw_error, env, code, msg); + NAPI_EXTERN napi_status NAPI_CDECL napi_throw_type_error(napi_env env, const char* code, - const char* msg); + const char* msg) + NODE_API_JS_VTABLE_IMPL( + napi_throw_type_error, throw_type_error, env, code, msg); + NAPI_EXTERN napi_status NAPI_CDECL napi_throw_range_error(napi_env env, const char* code, - const char* msg); + const char* msg) + NODE_API_JS_VTABLE_IMPL( + napi_throw_range_error, throw_range_error, env, code, msg); + #if NAPI_VERSION >= 9 NAPI_EXTERN napi_status NAPI_CDECL node_api_throw_syntax_error(napi_env env, const char* code, - const char* msg); + const char* msg) + NODE_API_JS_VTABLE_IMPL( + node_api_throw_syntax_error, throw_syntax_error, env, code, msg); #endif // NAPI_VERSION >= 9 + NAPI_EXTERN napi_status NAPI_CDECL napi_is_error(napi_env env, napi_value value, - bool* result); + bool* result) + NODE_API_JS_VTABLE_IMPL(napi_is_error, is_error, env, value, result); // Methods to support catching exceptions NAPI_EXTERN napi_status NAPI_CDECL napi_is_exception_pending(napi_env env, - bool* result); + bool* result) + NODE_API_JS_VTABLE_IMPL(napi_is_exception_pending, + is_exception_pending, + env, + result); + NAPI_EXTERN napi_status NAPI_CDECL -napi_get_and_clear_last_exception(napi_env env, napi_value* result); +napi_get_and_clear_last_exception(napi_env env, napi_value* result) + NODE_API_JS_VTABLE_IMPL(napi_get_and_clear_last_exception, + get_and_clear_last_exception, + env, + result); // Methods to work with array buffers and typed arrays NAPI_EXTERN napi_status NAPI_CDECL napi_is_arraybuffer(napi_env env, napi_value value, - bool* result); + bool* result) + NODE_API_JS_VTABLE_IMPL( + napi_is_arraybuffer, is_arraybuffer, env, value, result); + NAPI_EXTERN napi_status NAPI_CDECL napi_create_arraybuffer(napi_env env, size_t byte_length, void** data, - napi_value* result); + napi_value* result) + NODE_API_JS_VTABLE_IMPL(napi_create_arraybuffer, + create_arraybuffer, + env, + byte_length, + data, + result); + #ifndef NODE_API_NO_EXTERNAL_BUFFERS_ALLOWED NAPI_EXTERN napi_status NAPI_CDECL napi_create_external_arraybuffer(napi_env env, @@ -436,7 +887,16 @@ napi_create_external_arraybuffer(napi_env env, size_t byte_length, node_api_basic_finalize finalize_cb, void* finalize_hint, - napi_value* result); + napi_value* result) + NODE_API_JS_VTABLE_IMPL(napi_create_external_arraybuffer, + create_external_arraybuffer, + env, + external_data, + byte_length, + finalize_cb, + finalize_hint, + result); + #ifdef NAPI_EXPERIMENTAL #define NODE_API_EXPERIMENTAL_HAS_CREATE_EXTERNAL_SHAREDARRAYBUFFER NAPI_EXTERN napi_status NAPI_CDECL @@ -445,95 +905,181 @@ node_api_create_external_sharedarraybuffer(napi_env env, size_t byte_length, node_api_noenv_finalize finalize_cb, void* finalize_hint, - napi_value* result); + napi_value* result) + NODE_API_JS_VTABLE_IMPL(node_api_create_external_sharedarraybuffer, + create_external_sharedarraybuffer, + env, + external_data, + byte_length, + finalize_cb, + finalize_hint, + result); #endif // NAPI_EXPERIMENTAL #endif // NODE_API_NO_EXTERNAL_BUFFERS_ALLOWED + NAPI_EXTERN napi_status NAPI_CDECL napi_get_arraybuffer_info( - napi_env env, napi_value arraybuffer, void** data, size_t* byte_length); + napi_env env, napi_value arraybuffer, void** data, size_t* byte_length) + NODE_API_JS_VTABLE_IMPL(napi_get_arraybuffer_info, + get_arraybuffer_info, + env, + arraybuffer, + data, + byte_length); + NAPI_EXTERN napi_status NAPI_CDECL napi_is_typedarray(napi_env env, napi_value value, - bool* result); -NAPI_EXTERN napi_status NAPI_CDECL -napi_create_typedarray(napi_env env, - napi_typedarray_type type, - size_t length, - napi_value arraybuffer, - size_t byte_offset, - napi_value* result); -NAPI_EXTERN napi_status NAPI_CDECL -napi_get_typedarray_info(napi_env env, - napi_value typedarray, - napi_typedarray_type* type, - size_t* length, - void** data, - napi_value* arraybuffer, - size_t* byte_offset); + bool* result) + NODE_API_JS_VTABLE_IMPL( + napi_is_typedarray, is_typedarray, env, value, result); + +NAPI_EXTERN napi_status NAPI_CDECL napi_create_typedarray( + napi_env env, + napi_typedarray_type type, + size_t length, + napi_value arraybuffer, + size_t byte_offset, + napi_value* result) NODE_API_JS_VTABLE_IMPL(napi_create_typedarray, + create_typedarray, + env, + type, + length, + arraybuffer, + byte_offset, + result); + +NAPI_EXTERN napi_status NAPI_CDECL napi_get_typedarray_info( + napi_env env, + napi_value typedarray, + napi_typedarray_type* type, + size_t* length, + void** data, + napi_value* arraybuffer, + size_t* byte_offset) NODE_API_JS_VTABLE_IMPL(napi_get_typedarray_info, + get_typedarray_info, + env, + typedarray, + type, + length, + data, + arraybuffer, + byte_offset); NAPI_EXTERN napi_status NAPI_CDECL napi_create_dataview(napi_env env, size_t length, napi_value arraybuffer, size_t byte_offset, - napi_value* result); + napi_value* result) + NODE_API_JS_VTABLE_IMPL(napi_create_dataview, + create_dataview, + env, + length, + arraybuffer, + byte_offset, + result); + NAPI_EXTERN napi_status NAPI_CDECL napi_is_dataview(napi_env env, napi_value value, - bool* result); -NAPI_EXTERN napi_status NAPI_CDECL -napi_get_dataview_info(napi_env env, - napi_value dataview, - size_t* bytelength, - void** data, - napi_value* arraybuffer, - size_t* byte_offset); + bool* result) + NODE_API_JS_VTABLE_IMPL(napi_is_dataview, is_dataview, env, value, result); + +NAPI_EXTERN napi_status NAPI_CDECL napi_get_dataview_info( + napi_env env, + napi_value dataview, + size_t* bytelength, + void** data, + napi_value* arraybuffer, + size_t* byte_offset) NODE_API_JS_VTABLE_IMPL(napi_get_dataview_info, + get_dataview_info, + env, + dataview, + bytelength, + data, + arraybuffer, + byte_offset); #ifdef NAPI_EXPERIMENTAL #define NODE_API_EXPERIMENTAL_HAS_SHAREDARRAYBUFFER NAPI_EXTERN napi_status NAPI_CDECL -node_api_is_sharedarraybuffer(napi_env env, napi_value value, bool* result); +node_api_is_sharedarraybuffer(napi_env env, napi_value value, bool* result) + NODE_API_JS_VTABLE_IMPL(node_api_is_sharedarraybuffer, + is_sharedarraybuffer, + env, + value, + result); + NAPI_EXTERN napi_status NAPI_CDECL node_api_create_sharedarraybuffer( - napi_env env, size_t byte_length, void** data, napi_value* result); + napi_env env, size_t byte_length, void** data, napi_value* result) + NODE_API_JS_VTABLE_IMPL(node_api_create_sharedarraybuffer, + create_sharedarraybuffer, + env, + byte_length, + data, + result); #endif // NAPI_EXPERIMENTAL // version management NAPI_EXTERN napi_status NAPI_CDECL napi_get_version(node_api_basic_env env, - uint32_t* result); + uint32_t* result) + NODE_API_JS_VTABLE_IMPL(napi_get_version, get_version, env, result); // Promises NAPI_EXTERN napi_status NAPI_CDECL napi_create_promise(napi_env env, napi_deferred* deferred, - napi_value* promise); + napi_value* promise) + NODE_API_JS_VTABLE_IMPL( + napi_create_promise, create_promise, env, deferred, promise); + NAPI_EXTERN napi_status NAPI_CDECL napi_resolve_deferred(napi_env env, napi_deferred deferred, - napi_value resolution); + napi_value resolution) + NODE_API_JS_VTABLE_IMPL( + napi_resolve_deferred, resolve_deferred, env, deferred, resolution); + NAPI_EXTERN napi_status NAPI_CDECL napi_reject_deferred(napi_env env, napi_deferred deferred, - napi_value rejection); + napi_value rejection) + NODE_API_JS_VTABLE_IMPL( + napi_reject_deferred, reject_deferred, env, deferred, rejection); + NAPI_EXTERN napi_status NAPI_CDECL napi_is_promise(napi_env env, napi_value value, - bool* is_promise); + bool* is_promise) + NODE_API_JS_VTABLE_IMPL( + napi_is_promise, is_promise, env, value, is_promise); // Running a script NAPI_EXTERN napi_status NAPI_CDECL napi_run_script(napi_env env, napi_value script, - napi_value* result); + napi_value* result) + NODE_API_JS_VTABLE_IMPL(napi_run_script, run_script, env, script, result); // Memory management NAPI_EXTERN napi_status NAPI_CDECL napi_adjust_external_memory( - node_api_basic_env env, int64_t change_in_bytes, int64_t* adjusted_value); + node_api_basic_env env, int64_t change_in_bytes, int64_t* adjusted_value) + NODE_API_JS_VTABLE_IMPL(napi_adjust_external_memory, + adjust_external_memory, + env, + change_in_bytes, + adjusted_value); #if NAPI_VERSION >= 5 // Dates NAPI_EXTERN napi_status NAPI_CDECL napi_create_date(napi_env env, double time, - napi_value* result); + napi_value* result) + NODE_API_JS_VTABLE_IMPL(napi_create_date, create_date, env, time, result); NAPI_EXTERN napi_status NAPI_CDECL napi_is_date(napi_env env, napi_value value, - bool* is_date); + bool* is_date) + NODE_API_JS_VTABLE_IMPL(napi_is_date, is_date, env, value, is_date); NAPI_EXTERN napi_status NAPI_CDECL napi_get_date_value(napi_env env, napi_value value, - double* result); + double* result) + NODE_API_JS_VTABLE_IMPL( + napi_get_date_value, get_date_value, env, value, result); // Add finalizer for pointer NAPI_EXTERN napi_status NAPI_CDECL @@ -542,18 +1088,30 @@ napi_add_finalizer(napi_env env, void* finalize_data, node_api_basic_finalize finalize_cb, void* finalize_hint, - napi_ref* result); + napi_ref* result) NODE_API_JS_VTABLE_IMPL(napi_add_finalizer, + add_finalizer, + env, + js_object, + finalize_data, + finalize_cb, + finalize_hint, + result); #endif // NAPI_VERSION >= 5 #ifdef NAPI_EXPERIMENTAL #define NODE_API_EXPERIMENTAL_HAS_POST_FINALIZER -NAPI_EXTERN napi_status NAPI_CDECL -node_api_post_finalizer(node_api_basic_env env, - napi_finalize finalize_cb, - void* finalize_data, - void* finalize_hint); +NAPI_EXTERN napi_status NAPI_CDECL node_api_post_finalizer( + node_api_basic_env env, + napi_finalize finalize_cb, + void* finalize_data, + void* finalize_hint) NODE_API_JS_VTABLE_IMPL(node_api_post_finalizer, + post_finalizer, + env, + finalize_cb, + finalize_data, + finalize_hint); #endif // NAPI_EXPERIMENTAL @@ -562,71 +1120,142 @@ node_api_post_finalizer(node_api_basic_env env, // BigInt NAPI_EXTERN napi_status NAPI_CDECL napi_create_bigint_int64(napi_env env, int64_t value, - napi_value* result); -NAPI_EXTERN napi_status NAPI_CDECL -napi_create_bigint_uint64(napi_env env, uint64_t value, napi_value* result); -NAPI_EXTERN napi_status NAPI_CDECL -napi_create_bigint_words(napi_env env, - int sign_bit, - size_t word_count, - const uint64_t* words, - napi_value* result); + napi_value* result) + NODE_API_JS_VTABLE_IMPL( + napi_create_bigint_int64, create_bigint_int64, env, value, result); + +NAPI_EXTERN napi_status NAPI_CDECL napi_create_bigint_uint64(napi_env env, + uint64_t value, + napi_value* result) + NODE_API_JS_VTABLE_IMPL( + napi_create_bigint_uint64, create_bigint_uint64, env, value, result); + +NAPI_EXTERN napi_status NAPI_CDECL napi_create_bigint_words( + napi_env env, + int sign_bit, + size_t word_count, + const uint64_t* words, + napi_value* result) NODE_API_JS_VTABLE_IMPL(napi_create_bigint_words, + create_bigint_words, + env, + sign_bit, + word_count, + words, + result); + NAPI_EXTERN napi_status NAPI_CDECL napi_get_value_bigint_int64(napi_env env, napi_value value, int64_t* result, - bool* lossless); + bool* lossless) + NODE_API_JS_VTABLE_IMPL(napi_get_value_bigint_int64, + get_value_bigint_int64, + env, + value, + result, + lossless); + NAPI_EXTERN napi_status NAPI_CDECL napi_get_value_bigint_uint64( - napi_env env, napi_value value, uint64_t* result, bool* lossless); -NAPI_EXTERN napi_status NAPI_CDECL -napi_get_value_bigint_words(napi_env env, - napi_value value, - int* sign_bit, - size_t* word_count, - uint64_t* words); + napi_env env, napi_value value, uint64_t* result, bool* lossless) + NODE_API_JS_VTABLE_IMPL(napi_get_value_bigint_uint64, + get_value_bigint_uint64, + env, + value, + result, + lossless); + +NAPI_EXTERN napi_status NAPI_CDECL napi_get_value_bigint_words( + napi_env env, + napi_value value, + int* sign_bit, + size_t* word_count, + uint64_t* words) NODE_API_JS_VTABLE_IMPL(napi_get_value_bigint_words, + get_value_bigint_words, + env, + value, + sign_bit, + word_count, + words); // Object -NAPI_EXTERN napi_status NAPI_CDECL -napi_get_all_property_names(napi_env env, - napi_value object, - napi_key_collection_mode key_mode, - napi_key_filter key_filter, - napi_key_conversion key_conversion, - napi_value* result); +NAPI_EXTERN napi_status NAPI_CDECL napi_get_all_property_names( + napi_env env, + napi_value object, + napi_key_collection_mode key_mode, + napi_key_filter key_filter, + napi_key_conversion key_conversion, + napi_value* result) NODE_API_JS_VTABLE_IMPL(napi_get_all_property_names, + get_all_property_names, + env, + object, + key_mode, + key_filter, + key_conversion, + result); // Instance data -NAPI_EXTERN napi_status NAPI_CDECL -napi_set_instance_data(node_api_basic_env env, - void* data, - napi_finalize finalize_cb, - void* finalize_hint); +NAPI_EXTERN napi_status NAPI_CDECL napi_set_instance_data( + node_api_basic_env env, + void* data, + napi_finalize finalize_cb, + void* finalize_hint) NODE_API_JS_VTABLE_IMPL(napi_set_instance_data, + set_instance_data, + env, + data, + finalize_cb, + finalize_hint); NAPI_EXTERN napi_status NAPI_CDECL -napi_get_instance_data(node_api_basic_env env, void** data); +napi_get_instance_data(node_api_basic_env env, void** data) + NODE_API_JS_VTABLE_IMPL(napi_get_instance_data, + get_instance_data, + env, + data); + #endif // NAPI_VERSION >= 6 #if NAPI_VERSION >= 7 // ArrayBuffer detaching NAPI_EXTERN napi_status NAPI_CDECL -napi_detach_arraybuffer(napi_env env, napi_value arraybuffer); +napi_detach_arraybuffer(napi_env env, napi_value arraybuffer) + NODE_API_JS_VTABLE_IMPL(napi_detach_arraybuffer, + detach_arraybuffer, + env, + arraybuffer); NAPI_EXTERN napi_status NAPI_CDECL -napi_is_detached_arraybuffer(napi_env env, napi_value value, bool* result); +napi_is_detached_arraybuffer(napi_env env, napi_value value, bool* result) + NODE_API_JS_VTABLE_IMPL(napi_is_detached_arraybuffer, + is_detached_arraybuffer, + env, + value, + result); + #endif // NAPI_VERSION >= 7 #if NAPI_VERSION >= 8 // Type tagging NAPI_EXTERN napi_status NAPI_CDECL napi_type_tag_object( - napi_env env, napi_value value, const napi_type_tag* type_tag); + napi_env env, napi_value value, const napi_type_tag* type_tag) + NODE_API_JS_VTABLE_IMPL( + napi_type_tag_object, type_tag_object, env, value, type_tag); + +NAPI_EXTERN napi_status NAPI_CDECL napi_check_object_type_tag( + napi_env env, napi_value value, const napi_type_tag* type_tag, bool* result) + NODE_API_JS_VTABLE_IMPL(napi_check_object_type_tag, + check_object_type_tag, + env, + value, + type_tag, + result); -NAPI_EXTERN napi_status NAPI_CDECL -napi_check_object_type_tag(napi_env env, - napi_value value, - const napi_type_tag* type_tag, - bool* result); NAPI_EXTERN napi_status NAPI_CDECL napi_object_freeze(napi_env env, - napi_value object); + napi_value object) + NODE_API_JS_VTABLE_IMPL(napi_object_freeze, object_freeze, env, object); + NAPI_EXTERN napi_status NAPI_CDECL napi_object_seal(napi_env env, - napi_value object); + napi_value object) + NODE_API_JS_VTABLE_IMPL(napi_object_seal, object_seal, env, object); + #endif // NAPI_VERSION >= 8 EXTERN_C_END diff --git a/src/js_native_api_types.h b/src/js_native_api_types.h index 1de8e29d631ff6..e593917dff4c86 100644 --- a/src/js_native_api_types.h +++ b/src/js_native_api_types.h @@ -28,13 +28,19 @@ #endif #endif +#ifdef __cplusplus +#include +#include +#else // This file needs to be compatible with C compilers. // This is a public include file, and these includes have essentially // become part of its API. -#include // NOLINT(modernize-deprecated-headers) -#include // NOLINT(modernize-deprecated-headers) +#include +#include +#include +#endif -#if !defined __cplusplus || (defined(_MSC_VER) && _MSC_VER < 1900) +#if !defined(__cplusplus) || (defined(_MSC_VER) && _MSC_VER < 1900) typedef uint16_t char16_t; #endif @@ -241,4 +247,582 @@ typedef struct { } napi_type_tag; #endif // NAPI_VERSION >= 8 +#if defined(NODE_API_MODULE_USE_VTABLE) || defined(NODE_API_RUNTIME_USE_VTABLE) + +// Vtable for JavaScript to native interop functions. +// New functions must be added at the end to maintain backward compatibility. +typedef struct node_api_js_vtable { + napi_status(NAPI_CDECL* get_last_error_info)( + node_api_basic_env env, const napi_extended_error_info** result); + + napi_status(NAPI_CDECL* get_undefined)(napi_env env, napi_value* result); + napi_status(NAPI_CDECL* get_null)(napi_env env, napi_value* result); + napi_status(NAPI_CDECL* get_global)(napi_env env, napi_value* result); + napi_status(NAPI_CDECL* get_boolean)(napi_env env, + bool value, + napi_value* result); + + napi_status(NAPI_CDECL* create_object)(napi_env env, napi_value* result); + + napi_status(NAPI_CDECL* create_array)(napi_env env, napi_value* result); + napi_status(NAPI_CDECL* create_array_with_length)(napi_env env, + size_t length, + napi_value* result); + napi_status(NAPI_CDECL* create_double)(napi_env env, + double value, + napi_value* result); + napi_status(NAPI_CDECL* create_int32)(napi_env env, + int32_t value, + napi_value* result); + napi_status(NAPI_CDECL* create_uint32)(napi_env env, + uint32_t value, + napi_value* result); + napi_status(NAPI_CDECL* create_int64)(napi_env env, + int64_t value, + napi_value* result); + napi_status(NAPI_CDECL* create_string_latin1)(napi_env env, + const char* str, + size_t length, + napi_value* result); + napi_status(NAPI_CDECL* create_string_utf8)(napi_env env, + const char* str, + size_t length, + napi_value* result); + napi_status(NAPI_CDECL* create_string_utf16)(napi_env env, + const char16_t* str, + size_t length, + napi_value* result); + + napi_status(NAPI_CDECL* create_symbol)(napi_env env, + napi_value description, + napi_value* result); + napi_status(NAPI_CDECL* create_function)(napi_env env, + const char* utf8name, + size_t length, + napi_callback cb, + void* data, + napi_value* result); + napi_status(NAPI_CDECL* create_error)(napi_env env, + napi_value code, + napi_value msg, + napi_value* result); + napi_status(NAPI_CDECL* create_type_error)(napi_env env, + napi_value code, + napi_value msg, + napi_value* result); + napi_status(NAPI_CDECL* create_range_error)(napi_env env, + napi_value code, + napi_value msg, + napi_value* result); + + // The name is changed to avoid conflict with the `typeof` keyword in C + napi_status(NAPI_CDECL* type_of)(napi_env env, + napi_value value, + napi_valuetype* result); + napi_status(NAPI_CDECL* get_value_double)(napi_env env, + napi_value value, + double* result); + napi_status(NAPI_CDECL* get_value_int32)(napi_env env, + napi_value value, + int32_t* result); + napi_status(NAPI_CDECL* get_value_uint32)(napi_env env, + napi_value value, + uint32_t* result); + napi_status(NAPI_CDECL* get_value_int64)(napi_env env, + napi_value value, + int64_t* result); + napi_status(NAPI_CDECL* get_value_bool)(napi_env env, + napi_value value, + bool* result); + + napi_status(NAPI_CDECL* get_value_string_latin1)(napi_env env, + napi_value value, + char* buf, + size_t bufsize, + size_t* result); + + napi_status(NAPI_CDECL* get_value_string_utf8)(napi_env env, + napi_value value, + char* buf, + size_t bufsize, + size_t* result); + + napi_status(NAPI_CDECL* get_value_string_utf16)(napi_env env, + napi_value value, + char16_t* buf, + size_t bufsize, + size_t* result); + + napi_status(NAPI_CDECL* coerce_to_bool)(napi_env env, + napi_value value, + napi_value* result); + napi_status(NAPI_CDECL* coerce_to_number)(napi_env env, + napi_value value, + napi_value* result); + napi_status(NAPI_CDECL* coerce_to_object)(napi_env env, + napi_value value, + napi_value* result); + napi_status(NAPI_CDECL* coerce_to_string)(napi_env env, + napi_value value, + napi_value* result); + + napi_status(NAPI_CDECL* get_prototype)(napi_env env, + napi_value object, + napi_value* result); + napi_status(NAPI_CDECL* get_property_names)(napi_env env, + napi_value object, + napi_value* result); + napi_status(NAPI_CDECL* set_property)(napi_env env, + napi_value object, + napi_value key, + napi_value value); + napi_status(NAPI_CDECL* has_property)(napi_env env, + napi_value object, + napi_value key, + bool* result); + napi_status(NAPI_CDECL* get_property)(napi_env env, + napi_value object, + napi_value key, + napi_value* result); + napi_status(NAPI_CDECL* delete_property)(napi_env env, + napi_value object, + napi_value key, + bool* result); + napi_status(NAPI_CDECL* has_own_property)(napi_env env, + napi_value object, + napi_value key, + bool* result); + napi_status(NAPI_CDECL* set_named_property)(napi_env env, + napi_value object, + const char* utf8name, + napi_value value); + napi_status(NAPI_CDECL* has_named_property)(napi_env env, + napi_value object, + const char* utf8name, + bool* result); + napi_status(NAPI_CDECL* get_named_property)(napi_env env, + napi_value object, + const char* utf8name, + napi_value* result); + napi_status(NAPI_CDECL* set_element)(napi_env env, + napi_value object, + uint32_t index, + napi_value value); + napi_status(NAPI_CDECL* has_element)(napi_env env, + napi_value object, + uint32_t index, + bool* result); + napi_status(NAPI_CDECL* get_element)(napi_env env, + napi_value object, + uint32_t index, + napi_value* result); + napi_status(NAPI_CDECL* delete_element)(napi_env env, + napi_value object, + uint32_t index, + bool* result); + napi_status(NAPI_CDECL* define_properties)( + napi_env env, + napi_value object, + size_t property_count, + const napi_property_descriptor* properties); + + napi_status(NAPI_CDECL* is_array)(napi_env env, + napi_value value, + bool* result); + napi_status(NAPI_CDECL* get_array_length)(napi_env env, + napi_value value, + uint32_t* result); + + napi_status(NAPI_CDECL* strict_equals)(napi_env env, + napi_value lhs, + napi_value rhs, + bool* result); + + napi_status(NAPI_CDECL* call_function)(napi_env env, + napi_value recv, + napi_value func, + size_t argc, + const napi_value* argv, + napi_value* result); + napi_status(NAPI_CDECL* new_instance)(napi_env env, + napi_value constructor, + size_t argc, + const napi_value* argv, + napi_value* result); + napi_status(NAPI_CDECL* instanceof)(napi_env env, + napi_value object, + napi_value constructor, + bool* result); + + napi_status(NAPI_CDECL* get_cb_info)(napi_env env, + napi_callback_info cbinfo, + size_t* argc, + napi_value* argv, + napi_value* this_arg, + void** data); + + napi_status(NAPI_CDECL* get_new_target)(napi_env env, + napi_callback_info cbinfo, + napi_value* result); + napi_status(NAPI_CDECL* define_class)( + napi_env env, + const char* utf8name, + size_t length, + napi_callback constructor, + void* data, + size_t property_count, + const napi_property_descriptor* properties, + napi_value* result); + + napi_status(NAPI_CDECL* wrap)(napi_env env, + napi_value js_object, + void* native_object, + node_api_basic_finalize finalize_cb, + void* finalize_hint, + napi_ref* result); + napi_status(NAPI_CDECL* unwrap)(napi_env env, + napi_value js_object, + void** result); + napi_status(NAPI_CDECL* remove_wrap)(napi_env env, + napi_value js_object, + void** result); + napi_status(NAPI_CDECL* create_external)(napi_env env, + void* data, + node_api_basic_finalize finalize_cb, + void* finalize_hint, + napi_value* result); + napi_status(NAPI_CDECL* get_value_external)(napi_env env, + napi_value value, + void** result); + + napi_status(NAPI_CDECL* create_reference)(napi_env env, + napi_value value, + uint32_t initial_refcount, + napi_ref* result); + + napi_status(NAPI_CDECL* delete_reference)(node_api_basic_env env, + napi_ref ref); + + napi_status(NAPI_CDECL* reference_ref)(napi_env env, + napi_ref ref, + uint32_t* result); + + napi_status(NAPI_CDECL* reference_unref)(napi_env env, + napi_ref ref, + uint32_t* result); + + napi_status(NAPI_CDECL* get_reference_value)(napi_env env, + napi_ref ref, + napi_value* result); + + napi_status(NAPI_CDECL* open_handle_scope)(napi_env env, + napi_handle_scope* result); + napi_status(NAPI_CDECL* close_handle_scope)(napi_env env, + napi_handle_scope scope); + napi_status(NAPI_CDECL* open_escapable_handle_scope)( + napi_env env, napi_escapable_handle_scope* result); + napi_status(NAPI_CDECL* close_escapable_handle_scope)( + napi_env env, napi_escapable_handle_scope scope); + + napi_status(NAPI_CDECL* escape_handle)(napi_env env, + napi_escapable_handle_scope scope, + napi_value escapee, + napi_value* result); + + // The name is changed to avoid conflict with the `throw` keyword in C++ + napi_status(NAPI_CDECL* throw_value)(napi_env env, napi_value error); + napi_status(NAPI_CDECL* throw_error)(napi_env env, + const char* code, + const char* msg); + napi_status(NAPI_CDECL* throw_type_error)(napi_env env, + const char* code, + const char* msg); + napi_status(NAPI_CDECL* throw_range_error)(napi_env env, + const char* code, + const char* msg); + napi_status(NAPI_CDECL* is_error)(napi_env env, + napi_value value, + bool* result); + + napi_status(NAPI_CDECL* is_exception_pending)(napi_env env, bool* result); + napi_status(NAPI_CDECL* get_and_clear_last_exception)(napi_env env, + napi_value* result); + + napi_status(NAPI_CDECL* is_arraybuffer)(napi_env env, + napi_value value, + bool* result); + napi_status(NAPI_CDECL* create_arraybuffer)(napi_env env, + size_t byte_length, + void** data, + napi_value* result); + napi_status(NAPI_CDECL* create_external_arraybuffer)( + napi_env env, + void* external_data, + size_t byte_length, + node_api_basic_finalize finalize_cb, + void* finalize_hint, + napi_value* result); + napi_status(NAPI_CDECL* get_arraybuffer_info)(napi_env env, + napi_value arraybuffer, + void** data, + size_t* byte_length); + napi_status(NAPI_CDECL* is_typedarray)(napi_env env, + napi_value value, + bool* result); + napi_status(NAPI_CDECL* create_typedarray)(napi_env env, + napi_typedarray_type type, + size_t length, + napi_value arraybuffer, + size_t byte_offset, + napi_value* result); + napi_status(NAPI_CDECL* get_typedarray_info)(napi_env env, + napi_value typedarray, + napi_typedarray_type* type, + size_t* length, + void** data, + napi_value* arraybuffer, + size_t* byte_offset); + + napi_status(NAPI_CDECL* create_dataview)(napi_env env, + size_t length, + napi_value arraybuffer, + size_t byte_offset, + napi_value* result); + napi_status(NAPI_CDECL* is_dataview)(napi_env env, + napi_value value, + bool* result); + napi_status(NAPI_CDECL* get_dataview_info)(napi_env env, + napi_value dataview, + size_t* bytelength, + void** data, + napi_value* arraybuffer, + size_t* byte_offset); + + napi_status(NAPI_CDECL* get_version)(node_api_basic_env env, + uint32_t* result); + + napi_status(NAPI_CDECL* create_promise)(napi_env env, + napi_deferred* deferred, + napi_value* promise); + napi_status(NAPI_CDECL* resolve_deferred)(napi_env env, + napi_deferred deferred, + napi_value resolution); + napi_status(NAPI_CDECL* reject_deferred)(napi_env env, + napi_deferred deferred, + napi_value rejection); + napi_status(NAPI_CDECL* is_promise)(napi_env env, + napi_value value, + bool* is_promise); + + napi_status(NAPI_CDECL* run_script)(napi_env env, + napi_value script, + napi_value* result); + + napi_status(NAPI_CDECL* adjust_external_memory)(node_api_basic_env env, + int64_t change_in_bytes, + int64_t* adjusted_value); + +#if NAPI_VERSION >= 5 + + napi_status(NAPI_CDECL* create_date)(napi_env env, + double time, + napi_value* result); + + napi_status(NAPI_CDECL* is_date)(napi_env env, + napi_value value, + bool* is_date); + + napi_status(NAPI_CDECL* get_date_value)(napi_env env, + napi_value value, + double* result); + + napi_status(NAPI_CDECL* add_finalizer)(napi_env env, + napi_value js_object, + void* finalize_data, + node_api_basic_finalize finalize_cb, + void* finalize_hint, + napi_ref* result); + +#endif // NAPI_VERSION >= 5 + +#if NAPI_VERSION >= 6 + + napi_status(NAPI_CDECL* create_bigint_int64)(napi_env env, + int64_t value, + napi_value* result); + napi_status(NAPI_CDECL* create_bigint_uint64)(napi_env env, + uint64_t value, + napi_value* result); + napi_status(NAPI_CDECL* create_bigint_words)(napi_env env, + int sign_bit, + size_t word_count, + const uint64_t* words, + napi_value* result); + napi_status(NAPI_CDECL* get_value_bigint_int64)(napi_env env, + napi_value value, + int64_t* result, + bool* lossless); + napi_status(NAPI_CDECL* get_value_bigint_uint64)(napi_env env, + napi_value value, + uint64_t* result, + bool* lossless); + napi_status(NAPI_CDECL* get_value_bigint_words)(napi_env env, + napi_value value, + int* sign_bit, + size_t* word_count, + uint64_t* words); + + napi_status(NAPI_CDECL* get_all_property_names)( + napi_env env, + napi_value object, + napi_key_collection_mode key_mode, + napi_key_filter key_filter, + napi_key_conversion key_conversion, + napi_value* result); + + napi_status(NAPI_CDECL* set_instance_data)(node_api_basic_env env, + void* data, + napi_finalize finalize_cb, + void* finalize_hint); + + napi_status(NAPI_CDECL* get_instance_data)(node_api_basic_env env, + void** data); + +#endif // NAPI_VERSION >= 6 + +#if NAPI_VERSION >= 7 + + napi_status(NAPI_CDECL* detach_arraybuffer)(napi_env env, + napi_value arraybuffer); + + napi_status(NAPI_CDECL* is_detached_arraybuffer)(napi_env env, + napi_value value, + bool* result); +#endif // NAPI_VERSION >= 7 + +#if NAPI_VERSION >= 8 + + napi_status(NAPI_CDECL* type_tag_object)(napi_env env, + napi_value value, + const napi_type_tag* type_tag); + + napi_status(NAPI_CDECL* check_object_type_tag)(napi_env env, + napi_value value, + const napi_type_tag* type_tag, + bool* result); + napi_status(NAPI_CDECL* object_freeze)(napi_env env, napi_value object); + napi_status(NAPI_CDECL* object_seal)(napi_env env, napi_value object); + +#endif // NAPI_VERSION >= 8 + +#if NAPI_VERSION >= 9 + + napi_status(NAPI_CDECL* symbol_for)(napi_env env, + const char* utf8description, + size_t length, + napi_value* result); + + napi_status(NAPI_CDECL* create_syntax_error)(napi_env env, + napi_value code, + napi_value msg, + napi_value* result); + + napi_status(NAPI_CDECL* throw_syntax_error)(napi_env env, + const char* code, + const char* msg); + +#endif // NAPI_VERSION >= 9 + +#if NAPI_VERSION >= 10 + + napi_status(NAPI_CDECL* create_external_string_latin1)( + napi_env env, + char* str, + size_t length, + node_api_basic_finalize finalize_callback, + void* finalize_hint, + napi_value* result, + bool* copied); + napi_status(NAPI_CDECL* create_external_string_utf16)( + napi_env env, + char16_t* str, + size_t length, + node_api_basic_finalize finalize_callback, + void* finalize_hint, + napi_value* result, + bool* copied); + + napi_status(NAPI_CDECL* create_property_key_latin1)(napi_env env, + const char* str, + size_t length, + napi_value* result); + napi_status(NAPI_CDECL* create_property_key_utf8)(napi_env env, + const char* str, + size_t length, + napi_value* result); + napi_status(NAPI_CDECL* create_property_key_utf16)(napi_env env, + const char16_t* str, + size_t length, + napi_value* result); + +#endif // NAPI_VERSION >= 10 + +#ifdef NAPI_EXPERIMENTAL + + napi_status(NAPI_CDECL* create_object_with_properties)( + napi_env env, + napi_value prototype_or_null, + napi_value* property_names, + napi_value* property_values, + size_t property_count, + napi_value* result); + + napi_status(NAPI_CDECL* is_sharedarraybuffer)(napi_env env, + napi_value value, + bool* result); + napi_status(NAPI_CDECL* create_sharedarraybuffer)(napi_env env, + size_t byte_length, + void** data, + napi_value* result); + + napi_status(NAPI_CDECL* set_prototype)(napi_env env, + napi_value object, + napi_value value); + + napi_status(NAPI_CDECL* create_external_sharedarraybuffer)( + napi_env env, + void* external_data, + size_t byte_length, + node_api_noenv_finalize finalize_cb, + void* finalize_hint, + napi_value* result); + + napi_status(NAPI_CDECL* post_finalizer)(node_api_basic_env env, + napi_finalize finalize_cb, + void* finalize_data, + void* finalize_hint); + +#endif // NAPI_EXPERIMENTAL +} node_api_js_vtable; + +// Sentinel format: "NODE_VT" (7 bytes) + marker byte. +// Marker byte = (version << 1) | 1 +// - Bit 0 is always 1: ensures the sentinel can never match a C++ vtable +// pointer (which is always pointer-aligned, thus bit 0 = 0). +// - Bits 1-7: struct version number (0-127). +#define NODE_API_VT_SENTINEL_VERSION 0 +#define NODE_API_VT_SENTINEL_MAKE(version) \ + (0x4E4F44455F565400ULL | (((version) << 1) | 1)) +#define NODE_API_VT_SENTINEL \ + NODE_API_VT_SENTINEL_MAKE(NODE_API_VT_SENTINEL_VERSION) + +struct napi_env__ { + uint64_t sentinel; // Should be NODE_API_VT_SENTINEL + const struct node_api_js_vtable* js_vtable; + const struct node_api_module_vtable* module_vtable; +}; + +#endif // defined(NODE_API_MODULE_USE_VTABLE) || + // defined(NODE_API_RUNTIME_USE_VTABLE) + #endif // SRC_JS_NATIVE_API_TYPES_H_ diff --git a/src/js_native_api_v8.cc b/src/js_native_api_v8.cc index 5e533d2a682275..d406a3a717d354 100644 --- a/src/js_native_api_v8.cc +++ b/src/js_native_api_v8.cc @@ -1,6 +1,7 @@ #include #include // INT_MAX #include + #ifndef NAPI_EXPERIMENTAL #define NAPI_EXPERIMENTAL #endif @@ -70,7 +71,9 @@ (out) = v8::type::New((buffer), (byte_offset), (length)); \ } while (0) -void napi_env__::InvokeFinalizerFromGC(v8impl::RefTracker* finalizer) { +namespace v8impl { + +void NodeApiBaseEnv::InvokeFinalizerFromGC(v8impl::RefTracker* finalizer) { if (module_api_version != NAPI_VERSION_EXPERIMENTAL) { EnqueueFinalizer(finalizer); } else { @@ -85,11 +88,10 @@ void napi_env__::InvokeFinalizerFromGC(v8impl::RefTracker* finalizer) { } } -namespace v8impl { namespace { template -napi_status NewString(napi_env env, +napi_status NewString(NodeApiBaseEnv* env, const CCharType* str, size_t length, napi_value* result, @@ -104,7 +106,7 @@ napi_status NewString(napi_env env, } template -napi_status NewExternalString(napi_env env, +napi_status NewExternalString(NodeApiBaseEnv* env, CharType* str, size_t length, napi_finalize finalize_callback, @@ -138,7 +140,7 @@ napi_status NewExternalString(napi_env env, class TrackedStringResource : private RefTracker { public: - TrackedStringResource(napi_env env, + TrackedStringResource(NodeApiBaseEnv* env, napi_finalize finalize_callback, void* data, void* finalize_hint) @@ -171,7 +173,7 @@ class ExternalOneByteStringResource final : public v8::String::ExternalOneByteStringResource, TrackedStringResource { public: - ExternalOneByteStringResource(napi_env env, + ExternalOneByteStringResource(NodeApiBaseEnv* env, char* string, const size_t length, napi_finalize finalize_callback, @@ -191,7 +193,7 @@ class ExternalOneByteStringResource final class ExternalStringResource final : public v8::String::ExternalStringResource, TrackedStringResource { public: - ExternalStringResource(napi_env env, + ExternalStringResource(NodeApiBaseEnv* env, char16_t* string, const size_t length, napi_finalize finalize_callback, @@ -209,7 +211,7 @@ class ExternalStringResource final : public v8::String::ExternalStringResource, }; inline napi_status V8NameFromPropertyDescriptor( - napi_env env, + NodeApiBaseEnv* env, const napi_property_descriptor* p, v8::Local* result) { if (p->utf8name != nullptr) { @@ -306,7 +308,7 @@ V8EscapableHandleScopeFromJsEscapableHandleScope( return reinterpret_cast(s); } -inline napi_status ConcludeDeferred(napi_env env, +inline napi_status ConcludeDeferred(NodeApiBaseEnv* env, napi_deferred deferred, napi_value result, bool is_resolved) { @@ -336,7 +338,7 @@ inline napi_status ConcludeDeferred(napi_env env, enum UnwrapAction { KeepWrap, RemoveWrap }; -inline napi_status Unwrap(napi_env env, +inline napi_status Unwrap(NodeApiBaseEnv* env, napi_value js_object, void** result, UnwrapAction action) { @@ -387,7 +389,7 @@ class CallbackBundle { public: // Creates an object to be made available to the static function callback // wrapper, used to retrieve the native callback function and data pointer. - static inline v8::Local New(napi_env env, + static inline v8::Local New(NodeApiBaseEnv* env, napi_callback cb, void* data) { CallbackBundle* bundle = new CallbackBundle(); @@ -408,8 +410,8 @@ class CallbackBundle { } public: - napi_env env; // Necessary to invoke C++ Node-API callback - void* cb_data; // The user provided callback data + NodeApiBaseEnv* env; // Necessary to invoke C++ Node-API callback + void* cb_data; // The user provided callback data napi_callback cb; private: @@ -428,7 +430,7 @@ class FunctionCallbackWrapper { cbwrapper.InvokeCallback(); } - static inline napi_status NewFunction(napi_env env, + static inline napi_status NewFunction(NodeApiBaseEnv* env, napi_callback cb, void* cb_data, v8::Local* result) { @@ -444,7 +446,7 @@ class FunctionCallbackWrapper { } static inline napi_status NewTemplate( - napi_env env, + NodeApiBaseEnv* env, napi_callback cb, void* cb_data, v8::Local* result, @@ -498,19 +500,20 @@ class FunctionCallbackWrapper { reinterpret_cast(this); // All other pointers we need are stored in `_bundle` - napi_env env = bundle_->env; + v8impl::NodeApiBaseEnv* env = bundle_->env; napi_callback cb = bundle_->cb; napi_value result = nullptr; bool exceptionOccurred = false; - env->CallIntoModule([&](napi_env env) { result = cb(env, cbinfo_wrapper); }, - [&](napi_env env, v8::Local value) { - exceptionOccurred = true; - if (env->terminatedOrTerminating()) { - return; - } - env->isolate->ThrowException(value); - }); + env->CallIntoModule( + [&](NodeApiBaseEnv* env) { result = cb(env, cbinfo_wrapper); }, + [&](NodeApiBaseEnv* env, v8::Local value) { + exceptionOccurred = true; + if (env->terminatedOrTerminating()) { + return; + } + env->isolate->ThrowException(value); + }); if (!exceptionOccurred && (result != nullptr)) { cbinfo_.GetReturnValue().Set(V8LocalValueFromJsValue(result)); @@ -522,7 +525,7 @@ class FunctionCallbackWrapper { CallbackBundle* bundle_; }; -inline napi_status Wrap(napi_env env, +inline napi_status Wrap(NodeApiBaseEnv* env, napi_value js_object, void* native_object, napi_finalize finalize_cb, @@ -624,14 +627,14 @@ void Finalizer::CallFinalizer() { } } -TrackedFinalizer::TrackedFinalizer(napi_env env, +TrackedFinalizer::TrackedFinalizer(NodeApiBaseEnv* env, napi_finalize finalize_callback, void* finalize_data, void* finalize_hint) : RefTracker(), finalizer_(env, finalize_callback, finalize_data, finalize_hint) {} -TrackedFinalizer* TrackedFinalizer::New(napi_env env, +TrackedFinalizer* TrackedFinalizer::New(NodeApiBaseEnv* env, napi_finalize finalize_callback, void* finalize_data, void* finalize_hint) { @@ -656,7 +659,7 @@ void TrackedFinalizer::Finalize() { delete this; } -Reference::Reference(napi_env env, +Reference::Reference(NodeApiBaseEnv* env, v8::Local value, uint32_t initial_refcount, ReferenceOwnership ownership) @@ -678,7 +681,7 @@ Reference::~Reference() { Unlink(); } -Reference* Reference::New(napi_env env, +Reference* Reference::New(NodeApiBaseEnv* env, v8::Local value, uint32_t initial_refcount, ReferenceOwnership ownership) { @@ -711,7 +714,7 @@ uint32_t Reference::Unref() { return refcount_; } -v8::Local Reference::Get(napi_env env) { +v8::Local Reference::Get(NodeApiBaseEnv* env) { if (persistent_.IsEmpty()) { return v8::Local(); } else { @@ -764,7 +767,7 @@ void Reference::WeakCallback(const v8::WeakCallbackInfo& data) { reference->InvokeFinalizerFromGC(); } -ReferenceWithData* ReferenceWithData::New(napi_env env, +ReferenceWithData* ReferenceWithData::New(NodeApiBaseEnv* env, v8::Local value, uint32_t initial_refcount, ReferenceOwnership ownership, @@ -775,7 +778,7 @@ ReferenceWithData* ReferenceWithData::New(napi_env env, return reference; } -ReferenceWithData::ReferenceWithData(napi_env env, +ReferenceWithData::ReferenceWithData(NodeApiBaseEnv* env, v8::Local value, uint32_t initial_refcount, ReferenceOwnership ownership, @@ -783,7 +786,7 @@ ReferenceWithData::ReferenceWithData(napi_env env, : Reference(env, value, initial_refcount, ownership), data_(data) {} ReferenceWithFinalizer* ReferenceWithFinalizer::New( - napi_env env, + NodeApiBaseEnv* env, v8::Local value, uint32_t initial_refcount, ReferenceOwnership ownership, @@ -802,7 +805,7 @@ ReferenceWithFinalizer* ReferenceWithFinalizer::New( return reference; } -ReferenceWithFinalizer::ReferenceWithFinalizer(napi_env env, +ReferenceWithFinalizer::ReferenceWithFinalizer(NodeApiBaseEnv* env, v8::Local value, uint32_t initial_refcount, ReferenceOwnership ownership, @@ -844,7 +847,7 @@ class ExternalWrapper { } public: - static v8::Local New(napi_env env, void* data) { + static v8::Local New(NodeApiBaseEnv* env, void* data) { ExternalWrapper* wrapper = new ExternalWrapper(data); v8::Local external = v8::External::New( env->isolate, wrapper, v8::kExternalPointerTypeTagDefault); @@ -915,7 +918,7 @@ static const char* error_messages[] = { napi_status NAPI_CDECL napi_get_last_error_info( node_api_basic_env basic_env, const napi_extended_error_info** result) { - napi_env env = const_cast(basic_env); + v8impl::NodeApiBaseEnv* env = v8impl::AsNodeApiBaseEnv(basic_env); CHECK_ENV(env); CHECK_ARG(env, result); @@ -939,12 +942,13 @@ napi_status NAPI_CDECL napi_get_last_error_info( return napi_ok; } -napi_status NAPI_CDECL napi_create_function(napi_env env, +napi_status NAPI_CDECL napi_create_function(napi_env env_, const char* utf8name, size_t length, napi_callback cb, void* callback_data, napi_value* result) { + v8impl::NodeApiBaseEnv* env = v8impl::AsNodeApiBaseEnv(env_); NAPI_PREAMBLE(env); CHECK_ARG(env, result); CHECK_ARG(env, cb); @@ -968,7 +972,7 @@ napi_status NAPI_CDECL napi_create_function(napi_env env, } napi_status NAPI_CDECL -napi_define_class(napi_env env, +napi_define_class(napi_env env_, const char* utf8name, size_t length, napi_callback constructor, @@ -976,6 +980,7 @@ napi_define_class(napi_env env, size_t property_count, const napi_property_descriptor* properties, napi_value* result) { + v8impl::NodeApiBaseEnv* env = v8impl::AsNodeApiBaseEnv(env_); NAPI_PREAMBLE(env); CHECK_ARG(env, result); CHECK_ARG(env, constructor); @@ -1063,11 +1068,11 @@ napi_define_class(napi_env env, return GET_RETURN_STATUS(env); } -napi_status NAPI_CDECL napi_get_property_names(napi_env env, +napi_status NAPI_CDECL napi_get_property_names(napi_env env_, napi_value object, napi_value* result) { return napi_get_all_property_names( - env, + env_, object, napi_key_include_prototypes, static_cast(napi_key_enumerable | napi_key_skip_symbols), @@ -1076,12 +1081,13 @@ napi_status NAPI_CDECL napi_get_property_names(napi_env env, } napi_status NAPI_CDECL -napi_get_all_property_names(napi_env env, +napi_get_all_property_names(napi_env env_, napi_value object, napi_key_collection_mode key_mode, napi_key_filter key_filter, napi_key_conversion key_conversion, napi_value* result) { + v8impl::NodeApiBaseEnv* env = v8impl::AsNodeApiBaseEnv(env_); NAPI_PREAMBLE(env); CHECK_ARG(env, result); @@ -1150,10 +1156,11 @@ napi_get_all_property_names(napi_env env, return GET_RETURN_STATUS(env); } -napi_status NAPI_CDECL napi_set_property(napi_env env, +napi_status NAPI_CDECL napi_set_property(napi_env env_, napi_value object, napi_value key, napi_value value) { + v8impl::NodeApiBaseEnv* env = v8impl::AsNodeApiBaseEnv(env_); NAPI_PREAMBLE(env); CHECK_ARG(env, key); CHECK_ARG(env, value); @@ -1173,10 +1180,11 @@ napi_status NAPI_CDECL napi_set_property(napi_env env, return GET_RETURN_STATUS(env); } -napi_status NAPI_CDECL napi_has_property(napi_env env, +napi_status NAPI_CDECL napi_has_property(napi_env env_, napi_value object, napi_value key, bool* result) { + v8impl::NodeApiBaseEnv* env = v8impl::AsNodeApiBaseEnv(env_); NAPI_PREAMBLE(env); CHECK_ARG(env, result); CHECK_ARG(env, key); @@ -1195,10 +1203,11 @@ napi_status NAPI_CDECL napi_has_property(napi_env env, return GET_RETURN_STATUS(env); } -napi_status NAPI_CDECL napi_get_property(napi_env env, +napi_status NAPI_CDECL napi_get_property(napi_env env_, napi_value object, napi_value key, napi_value* result) { + v8impl::NodeApiBaseEnv* env = v8impl::AsNodeApiBaseEnv(env_); NAPI_PREAMBLE(env); CHECK_ARG(env, key); CHECK_ARG(env, result); @@ -1218,10 +1227,11 @@ napi_status NAPI_CDECL napi_get_property(napi_env env, return GET_RETURN_STATUS(env); } -napi_status NAPI_CDECL napi_delete_property(napi_env env, +napi_status NAPI_CDECL napi_delete_property(napi_env env_, napi_value object, napi_value key, bool* result) { + v8impl::NodeApiBaseEnv* env = v8impl::AsNodeApiBaseEnv(env_); NAPI_PREAMBLE(env); CHECK_ARG(env, key); @@ -1238,10 +1248,11 @@ napi_status NAPI_CDECL napi_delete_property(napi_env env, return GET_RETURN_STATUS(env); } -napi_status NAPI_CDECL napi_has_own_property(napi_env env, +napi_status NAPI_CDECL napi_has_own_property(napi_env env_, napi_value object, napi_value key, bool* result) { + v8impl::NodeApiBaseEnv* env = v8impl::AsNodeApiBaseEnv(env_); NAPI_PREAMBLE(env); CHECK_ARG(env, key); CHECK_ARG(env, result); @@ -1259,10 +1270,11 @@ napi_status NAPI_CDECL napi_has_own_property(napi_env env, return GET_RETURN_STATUS(env); } -napi_status NAPI_CDECL napi_set_named_property(napi_env env, +napi_status NAPI_CDECL napi_set_named_property(napi_env env_, napi_value object, const char* utf8name, napi_value value) { + v8impl::NodeApiBaseEnv* env = v8impl::AsNodeApiBaseEnv(env_); NAPI_PREAMBLE(env); CHECK_ARG(env, value); @@ -1283,10 +1295,11 @@ napi_status NAPI_CDECL napi_set_named_property(napi_env env, return GET_RETURN_STATUS(env); } -napi_status NAPI_CDECL napi_has_named_property(napi_env env, +napi_status NAPI_CDECL napi_has_named_property(napi_env env_, napi_value object, const char* utf8name, bool* result) { + v8impl::NodeApiBaseEnv* env = v8impl::AsNodeApiBaseEnv(env_); NAPI_PREAMBLE(env); CHECK_ARG(env, result); @@ -1306,10 +1319,11 @@ napi_status NAPI_CDECL napi_has_named_property(napi_env env, return GET_RETURN_STATUS(env); } -napi_status NAPI_CDECL napi_get_named_property(napi_env env, +napi_status NAPI_CDECL napi_get_named_property(napi_env env_, napi_value object, const char* utf8name, napi_value* result) { + v8impl::NodeApiBaseEnv* env = v8impl::AsNodeApiBaseEnv(env_); NAPI_PREAMBLE(env); CHECK_ARG(env, result); @@ -1331,10 +1345,11 @@ napi_status NAPI_CDECL napi_get_named_property(napi_env env, return GET_RETURN_STATUS(env); } -napi_status NAPI_CDECL napi_set_element(napi_env env, +napi_status NAPI_CDECL napi_set_element(napi_env env_, napi_value object, uint32_t index, napi_value value) { + v8impl::NodeApiBaseEnv* env = v8impl::AsNodeApiBaseEnv(env_); NAPI_PREAMBLE(env); CHECK_ARG(env, value); @@ -1352,10 +1367,11 @@ napi_status NAPI_CDECL napi_set_element(napi_env env, return GET_RETURN_STATUS(env); } -napi_status NAPI_CDECL napi_has_element(napi_env env, +napi_status NAPI_CDECL napi_has_element(napi_env env_, napi_value object, uint32_t index, bool* result) { + v8impl::NodeApiBaseEnv* env = v8impl::AsNodeApiBaseEnv(env_); NAPI_PREAMBLE(env); CHECK_ARG(env, result); @@ -1372,10 +1388,11 @@ napi_status NAPI_CDECL napi_has_element(napi_env env, return GET_RETURN_STATUS(env); } -napi_status NAPI_CDECL napi_get_element(napi_env env, +napi_status NAPI_CDECL napi_get_element(napi_env env_, napi_value object, uint32_t index, napi_value* result) { + v8impl::NodeApiBaseEnv* env = v8impl::AsNodeApiBaseEnv(env_); NAPI_PREAMBLE(env); CHECK_ARG(env, result); @@ -1392,10 +1409,11 @@ napi_status NAPI_CDECL napi_get_element(napi_env env, return GET_RETURN_STATUS(env); } -napi_status NAPI_CDECL napi_delete_element(napi_env env, +napi_status NAPI_CDECL napi_delete_element(napi_env env_, napi_value object, uint32_t index, bool* result) { + v8impl::NodeApiBaseEnv* env = v8impl::AsNodeApiBaseEnv(env_); NAPI_PREAMBLE(env); v8::Local context = env->context(); @@ -1411,10 +1429,11 @@ napi_status NAPI_CDECL napi_delete_element(napi_env env, } napi_status NAPI_CDECL -napi_define_properties(napi_env env, +napi_define_properties(napi_env env_, napi_value object, size_t property_count, const napi_property_descriptor* properties) { + v8impl::NodeApiBaseEnv* env = v8impl::AsNodeApiBaseEnv(env_); NAPI_PREAMBLE(env); if (property_count > 0) { CHECK_ARG(env, properties); @@ -1493,7 +1512,8 @@ napi_define_properties(napi_env env, return GET_RETURN_STATUS(env); } -napi_status NAPI_CDECL napi_object_freeze(napi_env env, napi_value object) { +napi_status NAPI_CDECL napi_object_freeze(napi_env env_, napi_value object) { + v8impl::NodeApiBaseEnv* env = v8impl::AsNodeApiBaseEnv(env_); NAPI_PREAMBLE(env); v8::Local context = env->context(); @@ -1510,7 +1530,8 @@ napi_status NAPI_CDECL napi_object_freeze(napi_env env, napi_value object) { return GET_RETURN_STATUS(env); } -napi_status NAPI_CDECL napi_object_seal(napi_env env, napi_value object) { +napi_status NAPI_CDECL napi_object_seal(napi_env env_, napi_value object) { + v8impl::NodeApiBaseEnv* env = v8impl::AsNodeApiBaseEnv(env_); NAPI_PREAMBLE(env); v8::Local context = env->context(); @@ -1527,9 +1548,10 @@ napi_status NAPI_CDECL napi_object_seal(napi_env env, napi_value object) { return GET_RETURN_STATUS(env); } -napi_status NAPI_CDECL napi_is_array(napi_env env, +napi_status NAPI_CDECL napi_is_array(napi_env env_, napi_value value, bool* result) { + v8impl::NodeApiBaseEnv* env = v8impl::AsNodeApiBaseEnv(env_); CHECK_ENV_NOT_IN_GC(env); CHECK_ARG(env, value); CHECK_ARG(env, result); @@ -1540,9 +1562,10 @@ napi_status NAPI_CDECL napi_is_array(napi_env env, return napi_clear_last_error(env); } -napi_status NAPI_CDECL napi_get_array_length(napi_env env, +napi_status NAPI_CDECL napi_get_array_length(napi_env env_, napi_value value, uint32_t* result) { + v8impl::NodeApiBaseEnv* env = v8impl::AsNodeApiBaseEnv(env_); NAPI_PREAMBLE(env); CHECK_ARG(env, value); CHECK_ARG(env, result); @@ -1556,10 +1579,11 @@ napi_status NAPI_CDECL napi_get_array_length(napi_env env, return GET_RETURN_STATUS(env); } -napi_status NAPI_CDECL napi_strict_equals(napi_env env, +napi_status NAPI_CDECL napi_strict_equals(napi_env env_, napi_value lhs, napi_value rhs, bool* result) { + v8impl::NodeApiBaseEnv* env = v8impl::AsNodeApiBaseEnv(env_); NAPI_PREAMBLE(env); CHECK_ARG(env, lhs); CHECK_ARG(env, rhs); @@ -1572,9 +1596,10 @@ napi_status NAPI_CDECL napi_strict_equals(napi_env env, return GET_RETURN_STATUS(env); } -napi_status NAPI_CDECL node_api_set_prototype(napi_env env, +napi_status NAPI_CDECL node_api_set_prototype(napi_env env_, napi_value object, napi_value value) { + v8impl::NodeApiBaseEnv* env = v8impl::AsNodeApiBaseEnv(env_); NAPI_PREAMBLE(env); CHECK_ARG(env, value); @@ -1592,9 +1617,10 @@ napi_status NAPI_CDECL node_api_set_prototype(napi_env env, return GET_RETURN_STATUS(env); } -napi_status NAPI_CDECL napi_get_prototype(napi_env env, +napi_status NAPI_CDECL napi_get_prototype(napi_env env_, napi_value object, napi_value* result) { + v8impl::NodeApiBaseEnv* env = v8impl::AsNodeApiBaseEnv(env_); NAPI_PREAMBLE(env); CHECK_ARG(env, result); @@ -1609,7 +1635,8 @@ napi_status NAPI_CDECL napi_get_prototype(napi_env env, return GET_RETURN_STATUS(env); } -napi_status NAPI_CDECL napi_create_object(napi_env env, napi_value* result) { +napi_status NAPI_CDECL napi_create_object(napi_env env_, napi_value* result) { + v8impl::NodeApiBaseEnv* env = v8impl::AsNodeApiBaseEnv(env_); CHECK_ENV_NOT_IN_GC(env); CHECK_ARG(env, result); @@ -1619,12 +1646,13 @@ napi_status NAPI_CDECL napi_create_object(napi_env env, napi_value* result) { } napi_status NAPI_CDECL -node_api_create_object_with_properties(napi_env env, +node_api_create_object_with_properties(napi_env env_, napi_value prototype_or_null, napi_value* property_names, napi_value* property_values, size_t property_count, napi_value* result) { + v8impl::NodeApiBaseEnv* env = v8impl::AsNodeApiBaseEnv(env_); CHECK_ENV_NOT_IN_GC(env); CHECK_ARG(env, result); @@ -1662,7 +1690,8 @@ node_api_create_object_with_properties(napi_env env, return napi_clear_last_error(env); } -napi_status NAPI_CDECL napi_create_array(napi_env env, napi_value* result) { +napi_status NAPI_CDECL napi_create_array(napi_env env_, napi_value* result) { + v8impl::NodeApiBaseEnv* env = v8impl::AsNodeApiBaseEnv(env_); CHECK_ENV_NOT_IN_GC(env); CHECK_ARG(env, result); @@ -1671,9 +1700,10 @@ napi_status NAPI_CDECL napi_create_array(napi_env env, napi_value* result) { return napi_clear_last_error(env); } -napi_status NAPI_CDECL napi_create_array_with_length(napi_env env, +napi_status NAPI_CDECL napi_create_array_with_length(napi_env env_, size_t length, napi_value* result) { + v8impl::NodeApiBaseEnv* env = v8impl::AsNodeApiBaseEnv(env_); CHECK_ENV_NOT_IN_GC(env); CHECK_ARG(env, result); @@ -1683,10 +1713,11 @@ napi_status NAPI_CDECL napi_create_array_with_length(napi_env env, return napi_clear_last_error(env); } -napi_status NAPI_CDECL napi_create_string_latin1(napi_env env, +napi_status NAPI_CDECL napi_create_string_latin1(napi_env env_, const char* str, size_t length, napi_value* result) { + v8impl::NodeApiBaseEnv* env = v8impl::AsNodeApiBaseEnv(env_); return v8impl::NewString(env, str, length, result, [&](v8::Isolate* isolate) { return v8::String::NewFromOneByte(isolate, reinterpret_cast(str), @@ -1695,20 +1726,22 @@ napi_status NAPI_CDECL napi_create_string_latin1(napi_env env, }); } -napi_status NAPI_CDECL napi_create_string_utf8(napi_env env, +napi_status NAPI_CDECL napi_create_string_utf8(napi_env env_, const char* str, size_t length, napi_value* result) { + v8impl::NodeApiBaseEnv* env = v8impl::AsNodeApiBaseEnv(env_); return v8impl::NewString(env, str, length, result, [&](v8::Isolate* isolate) { return v8::String::NewFromUtf8( isolate, str, v8::NewStringType::kNormal, static_cast(length)); }); } -napi_status NAPI_CDECL napi_create_string_utf16(napi_env env, +napi_status NAPI_CDECL napi_create_string_utf16(napi_env env_, const char16_t* str, size_t length, napi_value* result) { + v8impl::NodeApiBaseEnv* env = v8impl::AsNodeApiBaseEnv(env_); return v8impl::NewString(env, str, length, result, [&](v8::Isolate* isolate) { return v8::String::NewFromTwoByte(isolate, reinterpret_cast(str), @@ -1718,13 +1751,14 @@ napi_status NAPI_CDECL napi_create_string_utf16(napi_env env, } napi_status NAPI_CDECL node_api_create_external_string_latin1( - napi_env env, + napi_env env_, char* str, size_t length, node_api_basic_finalize basic_finalize_callback, void* finalize_hint, napi_value* result, bool* copied) { + v8impl::NodeApiBaseEnv* env = v8impl::AsNodeApiBaseEnv(env_); napi_finalize finalize_callback = reinterpret_cast(basic_finalize_callback); return v8impl::NewExternalString( @@ -1747,13 +1781,14 @@ napi_status NAPI_CDECL node_api_create_external_string_latin1( } napi_status NAPI_CDECL node_api_create_external_string_utf16( - napi_env env, + napi_env env_, char16_t* str, size_t length, node_api_basic_finalize basic_finalize_callback, void* finalize_hint, napi_value* result, bool* copied) { + v8impl::NodeApiBaseEnv* env = v8impl::AsNodeApiBaseEnv(env_); napi_finalize finalize_callback = reinterpret_cast(basic_finalize_callback); return v8impl::NewExternalString( @@ -1775,10 +1810,11 @@ napi_status NAPI_CDECL node_api_create_external_string_utf16( }); } -napi_status node_api_create_property_key_latin1(napi_env env, +napi_status node_api_create_property_key_latin1(napi_env env_, const char* str, size_t length, napi_value* result) { + v8impl::NodeApiBaseEnv* env = v8impl::AsNodeApiBaseEnv(env_); return v8impl::NewString(env, str, length, result, [&](v8::Isolate* isolate) { return v8::String::NewFromOneByte(isolate, reinterpret_cast(str), @@ -1787,10 +1823,11 @@ napi_status node_api_create_property_key_latin1(napi_env env, }); } -napi_status node_api_create_property_key_utf8(napi_env env, +napi_status node_api_create_property_key_utf8(napi_env env_, const char* str, size_t length, napi_value* result) { + v8impl::NodeApiBaseEnv* env = v8impl::AsNodeApiBaseEnv(env_); return v8impl::NewString(env, str, length, result, [&](v8::Isolate* isolate) { return v8::String::NewFromUtf8(isolate, str, @@ -1799,10 +1836,11 @@ napi_status node_api_create_property_key_utf8(napi_env env, }); } -napi_status NAPI_CDECL node_api_create_property_key_utf16(napi_env env, +napi_status NAPI_CDECL node_api_create_property_key_utf16(napi_env env_, const char16_t* str, size_t length, napi_value* result) { + v8impl::NodeApiBaseEnv* env = v8impl::AsNodeApiBaseEnv(env_); return v8impl::NewString(env, str, length, result, [&](v8::Isolate* isolate) { return v8::String::NewFromTwoByte(isolate, reinterpret_cast(str), @@ -1811,9 +1849,10 @@ napi_status NAPI_CDECL node_api_create_property_key_utf16(napi_env env, }); } -napi_status NAPI_CDECL napi_create_double(napi_env env, +napi_status NAPI_CDECL napi_create_double(napi_env env_, double value, napi_value* result) { + v8impl::NodeApiBaseEnv* env = v8impl::AsNodeApiBaseEnv(env_); CHECK_ENV_NOT_IN_GC(env); CHECK_ARG(env, result); @@ -1823,9 +1862,10 @@ napi_status NAPI_CDECL napi_create_double(napi_env env, return napi_clear_last_error(env); } -napi_status NAPI_CDECL napi_create_int32(napi_env env, +napi_status NAPI_CDECL napi_create_int32(napi_env env_, int32_t value, napi_value* result) { + v8impl::NodeApiBaseEnv* env = v8impl::AsNodeApiBaseEnv(env_); CHECK_ENV_NOT_IN_GC(env); CHECK_ARG(env, result); @@ -1835,9 +1875,10 @@ napi_status NAPI_CDECL napi_create_int32(napi_env env, return napi_clear_last_error(env); } -napi_status NAPI_CDECL napi_create_uint32(napi_env env, +napi_status NAPI_CDECL napi_create_uint32(napi_env env_, uint32_t value, napi_value* result) { + v8impl::NodeApiBaseEnv* env = v8impl::AsNodeApiBaseEnv(env_); CHECK_ENV_NOT_IN_GC(env); CHECK_ARG(env, result); @@ -1847,9 +1888,10 @@ napi_status NAPI_CDECL napi_create_uint32(napi_env env, return napi_clear_last_error(env); } -napi_status NAPI_CDECL napi_create_int64(napi_env env, +napi_status NAPI_CDECL napi_create_int64(napi_env env_, int64_t value, napi_value* result) { + v8impl::NodeApiBaseEnv* env = v8impl::AsNodeApiBaseEnv(env_); CHECK_ENV_NOT_IN_GC(env); CHECK_ARG(env, result); @@ -1859,9 +1901,10 @@ napi_status NAPI_CDECL napi_create_int64(napi_env env, return napi_clear_last_error(env); } -napi_status NAPI_CDECL napi_create_bigint_int64(napi_env env, +napi_status NAPI_CDECL napi_create_bigint_int64(napi_env env_, int64_t value, napi_value* result) { + v8impl::NodeApiBaseEnv* env = v8impl::AsNodeApiBaseEnv(env_); CHECK_ENV_NOT_IN_GC(env); CHECK_ARG(env, result); @@ -1871,9 +1914,10 @@ napi_status NAPI_CDECL napi_create_bigint_int64(napi_env env, return napi_clear_last_error(env); } -napi_status NAPI_CDECL napi_create_bigint_uint64(napi_env env, +napi_status NAPI_CDECL napi_create_bigint_uint64(napi_env env_, uint64_t value, napi_value* result) { + v8impl::NodeApiBaseEnv* env = v8impl::AsNodeApiBaseEnv(env_); CHECK_ENV_NOT_IN_GC(env); CHECK_ARG(env, result); @@ -1883,11 +1927,12 @@ napi_status NAPI_CDECL napi_create_bigint_uint64(napi_env env, return napi_clear_last_error(env); } -napi_status NAPI_CDECL napi_create_bigint_words(napi_env env, +napi_status NAPI_CDECL napi_create_bigint_words(napi_env env_, int sign_bit, size_t word_count, const uint64_t* words, napi_value* result) { + v8impl::NodeApiBaseEnv* env = v8impl::AsNodeApiBaseEnv(env_); NAPI_PREAMBLE(env); CHECK_ARG(env, words); CHECK_ARG(env, result); @@ -1905,9 +1950,10 @@ napi_status NAPI_CDECL napi_create_bigint_words(napi_env env, return GET_RETURN_STATUS(env); } -napi_status NAPI_CDECL napi_get_boolean(napi_env env, +napi_status NAPI_CDECL napi_get_boolean(napi_env env_, bool value, napi_value* result) { + v8impl::NodeApiBaseEnv* env = v8impl::AsNodeApiBaseEnv(env_); CHECK_ENV_NOT_IN_GC(env); CHECK_ARG(env, result); @@ -1922,9 +1968,10 @@ napi_status NAPI_CDECL napi_get_boolean(napi_env env, return napi_clear_last_error(env); } -napi_status NAPI_CDECL napi_create_symbol(napi_env env, +napi_status NAPI_CDECL napi_create_symbol(napi_env env_, napi_value description, napi_value* result) { + v8impl::NodeApiBaseEnv* env = v8impl::AsNodeApiBaseEnv(env_); CHECK_ENV_NOT_IN_GC(env); CHECK_ARG(env, result); @@ -1943,10 +1990,11 @@ napi_status NAPI_CDECL napi_create_symbol(napi_env env, return napi_clear_last_error(env); } -napi_status NAPI_CDECL node_api_symbol_for(napi_env env, +napi_status NAPI_CDECL node_api_symbol_for(napi_env env_, const char* utf8description, size_t length, napi_value* result) { + v8impl::NodeApiBaseEnv* env = v8impl::AsNodeApiBaseEnv(env_); CHECK_ENV_NOT_IN_GC(env); CHECK_ARG(env, result); @@ -1962,10 +2010,11 @@ napi_status NAPI_CDECL node_api_symbol_for(napi_env env, return napi_clear_last_error(env); } -static inline napi_status set_error_code(napi_env env, +static inline napi_status set_error_code(napi_env env_, v8::Local error, napi_value code, const char* code_cstring) { + v8impl::NodeApiBaseEnv* env = v8impl::AsNodeApiBaseEnv(env_); if ((code != nullptr) || (code_cstring != nullptr)) { v8::Local context = env->context(); v8::Local err_object = error.As(); @@ -1988,10 +2037,11 @@ static inline napi_status set_error_code(napi_env env, return napi_ok; } -napi_status NAPI_CDECL napi_create_error(napi_env env, +napi_status NAPI_CDECL napi_create_error(napi_env env_, napi_value code, napi_value msg, napi_value* result) { + v8impl::NodeApiBaseEnv* env = v8impl::AsNodeApiBaseEnv(env_); CHECK_ENV_NOT_IN_GC(env); CHECK_ARG(env, msg); CHECK_ARG(env, result); @@ -2008,10 +2058,11 @@ napi_status NAPI_CDECL napi_create_error(napi_env env, return napi_clear_last_error(env); } -napi_status NAPI_CDECL napi_create_type_error(napi_env env, +napi_status NAPI_CDECL napi_create_type_error(napi_env env_, napi_value code, napi_value msg, napi_value* result) { + v8impl::NodeApiBaseEnv* env = v8impl::AsNodeApiBaseEnv(env_); CHECK_ENV_NOT_IN_GC(env); CHECK_ARG(env, msg); CHECK_ARG(env, result); @@ -2028,10 +2079,11 @@ napi_status NAPI_CDECL napi_create_type_error(napi_env env, return napi_clear_last_error(env); } -napi_status NAPI_CDECL napi_create_range_error(napi_env env, +napi_status NAPI_CDECL napi_create_range_error(napi_env env_, napi_value code, napi_value msg, napi_value* result) { + v8impl::NodeApiBaseEnv* env = v8impl::AsNodeApiBaseEnv(env_); CHECK_ENV_NOT_IN_GC(env); CHECK_ARG(env, msg); CHECK_ARG(env, result); @@ -2048,10 +2100,11 @@ napi_status NAPI_CDECL napi_create_range_error(napi_env env, return napi_clear_last_error(env); } -napi_status NAPI_CDECL node_api_create_syntax_error(napi_env env, +napi_status NAPI_CDECL node_api_create_syntax_error(napi_env env_, napi_value code, napi_value msg, napi_value* result) { + v8impl::NodeApiBaseEnv* env = v8impl::AsNodeApiBaseEnv(env_); CHECK_ENV_NOT_IN_GC(env); CHECK_ARG(env, msg); CHECK_ARG(env, result); @@ -2068,11 +2121,12 @@ napi_status NAPI_CDECL node_api_create_syntax_error(napi_env env, return napi_clear_last_error(env); } -napi_status NAPI_CDECL napi_typeof(napi_env env, +napi_status NAPI_CDECL napi_typeof(napi_env env_, napi_value value, napi_valuetype* result) { // Omit NAPI_PREAMBLE and GET_RETURN_STATUS because V8 calls here cannot throw // JS exceptions. + v8impl::NodeApiBaseEnv* env = v8impl::AsNodeApiBaseEnv(env_); CHECK_ENV_NOT_IN_GC(env); CHECK_ARG(env, value); CHECK_ARG(env, result); @@ -2111,7 +2165,8 @@ napi_status NAPI_CDECL napi_typeof(napi_env env, return napi_clear_last_error(env); } -napi_status NAPI_CDECL napi_get_undefined(napi_env env, napi_value* result) { +napi_status NAPI_CDECL napi_get_undefined(napi_env env_, napi_value* result) { + v8impl::NodeApiBaseEnv* env = v8impl::AsNodeApiBaseEnv(env_); CHECK_ENV_NOT_IN_GC(env); CHECK_ARG(env, result); @@ -2120,7 +2175,8 @@ napi_status NAPI_CDECL napi_get_undefined(napi_env env, napi_value* result) { return napi_clear_last_error(env); } -napi_status NAPI_CDECL napi_get_null(napi_env env, napi_value* result) { +napi_status NAPI_CDECL napi_get_null(napi_env env_, napi_value* result) { + v8impl::NodeApiBaseEnv* env = v8impl::AsNodeApiBaseEnv(env_); CHECK_ENV_NOT_IN_GC(env); CHECK_ARG(env, result); @@ -2131,13 +2187,14 @@ napi_status NAPI_CDECL napi_get_null(napi_env env, napi_value* result) { // Gets all callback info in a single call. (Ugly, but faster.) napi_status NAPI_CDECL napi_get_cb_info( - napi_env env, // [in] Node-API environment handle + napi_env env_, // [in] Node-API environment handle napi_callback_info cbinfo, // [in] Opaque callback-info handle size_t* argc, // [in-out] Specifies the size of the provided argv array // and receives the actual count of args. napi_value* argv, // [out] Array of values napi_value* this_arg, // [out] Receives the JS 'this' arg for the call void** data) { // [out] Receives the data pointer for the callback. + v8impl::NodeApiBaseEnv* env = v8impl::AsNodeApiBaseEnv(env_); CHECK_ENV(env); CHECK_ARG(env, cbinfo); @@ -2161,9 +2218,10 @@ napi_status NAPI_CDECL napi_get_cb_info( return napi_clear_last_error(env); } -napi_status NAPI_CDECL napi_get_new_target(napi_env env, +napi_status NAPI_CDECL napi_get_new_target(napi_env env_, napi_callback_info cbinfo, napi_value* result) { + v8impl::NodeApiBaseEnv* env = v8impl::AsNodeApiBaseEnv(env_); CHECK_ENV_NOT_IN_GC(env); CHECK_ARG(env, cbinfo); CHECK_ARG(env, result); @@ -2175,12 +2233,13 @@ napi_status NAPI_CDECL napi_get_new_target(napi_env env, return napi_clear_last_error(env); } -napi_status NAPI_CDECL napi_call_function(napi_env env, +napi_status NAPI_CDECL napi_call_function(napi_env env_, napi_value recv, napi_value func, size_t argc, const napi_value* argv, napi_value* result) { + v8impl::NodeApiBaseEnv* env = v8impl::AsNodeApiBaseEnv(env_); NAPI_PREAMBLE(env); CHECK_ARG(env, recv); if (argc > 0) { @@ -2207,7 +2266,8 @@ napi_status NAPI_CDECL napi_call_function(napi_env env, return napi_clear_last_error(env); } -napi_status NAPI_CDECL napi_get_global(napi_env env, napi_value* result) { +napi_status NAPI_CDECL napi_get_global(napi_env env_, napi_value* result) { + v8impl::NodeApiBaseEnv* env = v8impl::AsNodeApiBaseEnv(env_); CHECK_ENV_NOT_IN_GC(env); CHECK_ARG(env, result); @@ -2216,7 +2276,8 @@ napi_status NAPI_CDECL napi_get_global(napi_env env, napi_value* result) { return napi_clear_last_error(env); } -napi_status NAPI_CDECL napi_throw(napi_env env, napi_value error) { +napi_status NAPI_CDECL napi_throw(napi_env env_, napi_value error) { + v8impl::NodeApiBaseEnv* env = v8impl::AsNodeApiBaseEnv(env_); NAPI_PREAMBLE(env); CHECK_ARG(env, error); @@ -2228,9 +2289,10 @@ napi_status NAPI_CDECL napi_throw(napi_env env, napi_value error) { return napi_clear_last_error(env); } -napi_status NAPI_CDECL napi_throw_error(napi_env env, +napi_status NAPI_CDECL napi_throw_error(napi_env env_, const char* code, const char* msg) { + v8impl::NodeApiBaseEnv* env = v8impl::AsNodeApiBaseEnv(env_); NAPI_PREAMBLE(env); v8::Isolate* isolate = env->isolate; @@ -2246,9 +2308,10 @@ napi_status NAPI_CDECL napi_throw_error(napi_env env, return napi_clear_last_error(env); } -napi_status NAPI_CDECL napi_throw_type_error(napi_env env, +napi_status NAPI_CDECL napi_throw_type_error(napi_env env_, const char* code, const char* msg) { + v8impl::NodeApiBaseEnv* env = v8impl::AsNodeApiBaseEnv(env_); NAPI_PREAMBLE(env); v8::Isolate* isolate = env->isolate; @@ -2264,9 +2327,10 @@ napi_status NAPI_CDECL napi_throw_type_error(napi_env env, return napi_clear_last_error(env); } -napi_status NAPI_CDECL napi_throw_range_error(napi_env env, +napi_status NAPI_CDECL napi_throw_range_error(napi_env env_, const char* code, const char* msg) { + v8impl::NodeApiBaseEnv* env = v8impl::AsNodeApiBaseEnv(env_); NAPI_PREAMBLE(env); v8::Isolate* isolate = env->isolate; @@ -2282,9 +2346,10 @@ napi_status NAPI_CDECL napi_throw_range_error(napi_env env, return napi_clear_last_error(env); } -napi_status NAPI_CDECL node_api_throw_syntax_error(napi_env env, +napi_status NAPI_CDECL node_api_throw_syntax_error(napi_env env_, const char* code, const char* msg) { + v8impl::NodeApiBaseEnv* env = v8impl::AsNodeApiBaseEnv(env_); NAPI_PREAMBLE(env); v8::Isolate* isolate = env->isolate; @@ -2300,11 +2365,12 @@ napi_status NAPI_CDECL node_api_throw_syntax_error(napi_env env, return napi_clear_last_error(env); } -napi_status NAPI_CDECL napi_is_error(napi_env env, +napi_status NAPI_CDECL napi_is_error(napi_env env_, napi_value value, bool* result) { // Omit NAPI_PREAMBLE and GET_RETURN_STATUS because V8 calls here cannot // throw JS exceptions. + v8impl::NodeApiBaseEnv* env = v8impl::AsNodeApiBaseEnv(env_); CHECK_ENV_NOT_IN_GC(env); CHECK_ARG(env, value); CHECK_ARG(env, result); @@ -2315,11 +2381,12 @@ napi_status NAPI_CDECL napi_is_error(napi_env env, return napi_clear_last_error(env); } -napi_status NAPI_CDECL napi_get_value_double(napi_env env, +napi_status NAPI_CDECL napi_get_value_double(napi_env env_, napi_value value, double* result) { // Omit NAPI_PREAMBLE and GET_RETURN_STATUS because V8 calls here cannot throw // JS exceptions. + v8impl::NodeApiBaseEnv* env = v8impl::AsNodeApiBaseEnv(env_); CHECK_ENV_NOT_IN_GC(env); CHECK_ARG(env, value); CHECK_ARG(env, result); @@ -2332,11 +2399,12 @@ napi_status NAPI_CDECL napi_get_value_double(napi_env env, return napi_clear_last_error(env); } -napi_status NAPI_CDECL napi_get_value_int32(napi_env env, +napi_status NAPI_CDECL napi_get_value_int32(napi_env env_, napi_value value, int32_t* result) { // Omit NAPI_PREAMBLE and GET_RETURN_STATUS because V8 calls here cannot throw // JS exceptions. + v8impl::NodeApiBaseEnv* env = v8impl::AsNodeApiBaseEnv(env_); CHECK_ENV_NOT_IN_GC(env); CHECK_ARG(env, value); CHECK_ARG(env, result); @@ -2356,11 +2424,12 @@ napi_status NAPI_CDECL napi_get_value_int32(napi_env env, return napi_clear_last_error(env); } -napi_status NAPI_CDECL napi_get_value_uint32(napi_env env, +napi_status NAPI_CDECL napi_get_value_uint32(napi_env env_, napi_value value, uint32_t* result) { // Omit NAPI_PREAMBLE and GET_RETURN_STATUS because V8 calls here cannot throw // JS exceptions. + v8impl::NodeApiBaseEnv* env = v8impl::AsNodeApiBaseEnv(env_); CHECK_ENV_NOT_IN_GC(env); CHECK_ARG(env, value); CHECK_ARG(env, result); @@ -2380,11 +2449,12 @@ napi_status NAPI_CDECL napi_get_value_uint32(napi_env env, return napi_clear_last_error(env); } -napi_status NAPI_CDECL napi_get_value_int64(napi_env env, +napi_status NAPI_CDECL napi_get_value_int64(napi_env env_, napi_value value, int64_t* result) { // Omit NAPI_PREAMBLE and GET_RETURN_STATUS because V8 calls here cannot throw // JS exceptions. + v8impl::NodeApiBaseEnv* env = v8impl::AsNodeApiBaseEnv(env_); CHECK_ENV_NOT_IN_GC(env); CHECK_ARG(env, value); CHECK_ARG(env, result); @@ -2414,10 +2484,11 @@ napi_status NAPI_CDECL napi_get_value_int64(napi_env env, return napi_clear_last_error(env); } -napi_status NAPI_CDECL napi_get_value_bigint_int64(napi_env env, +napi_status NAPI_CDECL napi_get_value_bigint_int64(napi_env env_, napi_value value, int64_t* result, bool* lossless) { + v8impl::NodeApiBaseEnv* env = v8impl::AsNodeApiBaseEnv(env_); CHECK_ENV_NOT_IN_GC(env); CHECK_ARG(env, value); CHECK_ARG(env, result); @@ -2432,10 +2503,11 @@ napi_status NAPI_CDECL napi_get_value_bigint_int64(napi_env env, return napi_clear_last_error(env); } -napi_status NAPI_CDECL napi_get_value_bigint_uint64(napi_env env, +napi_status NAPI_CDECL napi_get_value_bigint_uint64(napi_env env_, napi_value value, uint64_t* result, bool* lossless) { + v8impl::NodeApiBaseEnv* env = v8impl::AsNodeApiBaseEnv(env_); CHECK_ENV_NOT_IN_GC(env); CHECK_ARG(env, value); CHECK_ARG(env, result); @@ -2450,11 +2522,12 @@ napi_status NAPI_CDECL napi_get_value_bigint_uint64(napi_env env, return napi_clear_last_error(env); } -napi_status NAPI_CDECL napi_get_value_bigint_words(napi_env env, +napi_status NAPI_CDECL napi_get_value_bigint_words(napi_env env_, napi_value value, int* sign_bit, size_t* word_count, uint64_t* words) { + v8impl::NodeApiBaseEnv* env = v8impl::AsNodeApiBaseEnv(env_); CHECK_ENV_NOT_IN_GC(env); CHECK_ARG(env, value); CHECK_ARG(env, word_count); @@ -2480,11 +2553,12 @@ napi_status NAPI_CDECL napi_get_value_bigint_words(napi_env env, return napi_clear_last_error(env); } -napi_status NAPI_CDECL napi_get_value_bool(napi_env env, +napi_status NAPI_CDECL napi_get_value_bool(napi_env env_, napi_value value, bool* result) { // Omit NAPI_PREAMBLE and GET_RETURN_STATUS because V8 calls here cannot throw // JS exceptions. + v8impl::NodeApiBaseEnv* env = v8impl::AsNodeApiBaseEnv(env_); CHECK_ENV_NOT_IN_GC(env); CHECK_ARG(env, value); CHECK_ARG(env, result); @@ -2505,8 +2579,12 @@ napi_status NAPI_CDECL napi_get_value_bool(napi_env env, // If buf is NULL, this method returns the length of the string (in bytes) // via the result parameter. // The result argument is optional unless buf is NULL. -napi_status NAPI_CDECL napi_get_value_string_latin1( - napi_env env, napi_value value, char* buf, size_t bufsize, size_t* result) { +napi_status NAPI_CDECL napi_get_value_string_latin1(napi_env env_, + napi_value value, + char* buf, + size_t bufsize, + size_t* result) { + v8impl::NodeApiBaseEnv* env = v8impl::AsNodeApiBaseEnv(env_); CHECK_ENV_NOT_IN_GC(env); CHECK_ARG(env, value); @@ -2543,8 +2621,12 @@ napi_status NAPI_CDECL napi_get_value_string_latin1( // If buf is NULL, this method returns the length of the string (in bytes) // via the result parameter. // The result argument is optional unless buf is NULL. -napi_status NAPI_CDECL napi_get_value_string_utf8( - napi_env env, napi_value value, char* buf, size_t bufsize, size_t* result) { +napi_status NAPI_CDECL napi_get_value_string_utf8(napi_env env_, + napi_value value, + char* buf, + size_t bufsize, + size_t* result) { + v8impl::NodeApiBaseEnv* env = v8impl::AsNodeApiBaseEnv(env_); CHECK_ENV_NOT_IN_GC(env); CHECK_ARG(env, value); @@ -2581,11 +2663,12 @@ napi_status NAPI_CDECL napi_get_value_string_utf8( // If buf is NULL, this method returns the length of the string (in 2-byte // code units) via the result parameter. // The result argument is optional unless buf is NULL. -napi_status NAPI_CDECL napi_get_value_string_utf16(napi_env env, +napi_status NAPI_CDECL napi_get_value_string_utf16(napi_env env_, napi_value value, char16_t* buf, size_t bufsize, size_t* result) { + v8impl::NodeApiBaseEnv* env = v8impl::AsNodeApiBaseEnv(env_); CHECK_ENV_NOT_IN_GC(env); CHECK_ARG(env, value); @@ -2616,9 +2699,10 @@ napi_status NAPI_CDECL napi_get_value_string_utf16(napi_env env, return napi_clear_last_error(env); } -napi_status NAPI_CDECL napi_coerce_to_bool(napi_env env, +napi_status NAPI_CDECL napi_coerce_to_bool(napi_env env_, napi_value value, napi_value* result) { + v8impl::NodeApiBaseEnv* env = v8impl::AsNodeApiBaseEnv(env_); NAPI_PREAMBLE(env); CHECK_ARG(env, value); CHECK_ARG(env, result); @@ -2632,7 +2716,8 @@ napi_status NAPI_CDECL napi_coerce_to_bool(napi_env env, #define GEN_COERCE_FUNCTION(UpperCaseName, MixedCaseName, LowerCaseName) \ napi_status NAPI_CDECL napi_coerce_to_##LowerCaseName( \ - napi_env env, napi_value value, napi_value* result) { \ + napi_env env_, napi_value value, napi_value* result) { \ + v8impl::NodeApiBaseEnv* env = v8impl::AsNodeApiBaseEnv(env_); \ NAPI_PREAMBLE(env); \ CHECK_ARG(env, value); \ CHECK_ARG(env, result); \ @@ -2652,36 +2737,40 @@ GEN_COERCE_FUNCTION(STRING, String, string) #undef GEN_COERCE_FUNCTION -napi_status NAPI_CDECL napi_wrap(napi_env env, +napi_status NAPI_CDECL napi_wrap(napi_env env_, napi_value js_object, void* native_object, node_api_basic_finalize basic_finalize_cb, void* finalize_hint, napi_ref* result) { + v8impl::NodeApiBaseEnv* env = v8impl::AsNodeApiBaseEnv(env_); napi_finalize finalize_cb = reinterpret_cast(basic_finalize_cb); return v8impl::Wrap( env, js_object, native_object, finalize_cb, finalize_hint, result); } -napi_status NAPI_CDECL napi_unwrap(napi_env env, +napi_status NAPI_CDECL napi_unwrap(napi_env env_, napi_value obj, void** result) { + v8impl::NodeApiBaseEnv* env = v8impl::AsNodeApiBaseEnv(env_); return v8impl::Unwrap(env, obj, result, v8impl::KeepWrap); } -napi_status NAPI_CDECL napi_remove_wrap(napi_env env, +napi_status NAPI_CDECL napi_remove_wrap(napi_env env_, napi_value obj, void** result) { + v8impl::NodeApiBaseEnv* env = v8impl::AsNodeApiBaseEnv(env_); return v8impl::Unwrap(env, obj, result, v8impl::RemoveWrap); } napi_status NAPI_CDECL -napi_create_external(napi_env env, +napi_create_external(napi_env env_, void* data, node_api_basic_finalize basic_finalize_cb, void* finalize_hint, napi_value* result) { + v8impl::NodeApiBaseEnv* env = v8impl::AsNodeApiBaseEnv(env_); napi_finalize finalize_cb = reinterpret_cast(basic_finalize_cb); NAPI_PREAMBLE(env); @@ -2707,9 +2796,10 @@ napi_create_external(napi_env env, return napi_clear_last_error(env); } -napi_status NAPI_CDECL napi_type_tag_object(napi_env env, +napi_status NAPI_CDECL napi_type_tag_object(napi_env env_, napi_value object_or_external, const napi_type_tag* type_tag) { + v8impl::NodeApiBaseEnv* env = v8impl::AsNodeApiBaseEnv(env_); NAPI_PREAMBLE(env); v8::Local context = env->context(); @@ -2746,10 +2836,11 @@ napi_status NAPI_CDECL napi_type_tag_object(napi_env env, return GET_RETURN_STATUS(env); } -napi_status NAPI_CDECL napi_check_object_type_tag(napi_env env, +napi_status NAPI_CDECL napi_check_object_type_tag(napi_env env_, napi_value object_or_external, const napi_type_tag* type_tag, bool* result) { + v8impl::NodeApiBaseEnv* env = v8impl::AsNodeApiBaseEnv(env_); NAPI_PREAMBLE(env); v8::Local context = env->context(); @@ -2798,9 +2889,10 @@ napi_status NAPI_CDECL napi_check_object_type_tag(napi_env env, return GET_RETURN_STATUS(env); } -napi_status NAPI_CDECL napi_get_value_external(napi_env env, +napi_status NAPI_CDECL napi_get_value_external(napi_env env_, napi_value value, void** result) { + v8impl::NodeApiBaseEnv* env = v8impl::AsNodeApiBaseEnv(env_); CHECK_ENV_NOT_IN_GC(env); CHECK_ARG(env, value); CHECK_ARG(env, result); @@ -2815,12 +2907,13 @@ napi_status NAPI_CDECL napi_get_value_external(napi_env env, } // Set initial_refcount to 0 for a weak reference, >0 for a strong reference. -napi_status NAPI_CDECL napi_create_reference(napi_env env, +napi_status NAPI_CDECL napi_create_reference(napi_env env_, napi_value value, uint32_t initial_refcount, napi_ref* result) { // Omit NAPI_PREAMBLE and GET_RETURN_STATUS because V8 calls here cannot throw // JS exceptions. + v8impl::NodeApiBaseEnv* env = v8impl::AsNodeApiBaseEnv(env_); CHECK_ENV_NOT_IN_GC(env); CHECK_ARG(env, value); CHECK_ARG(env, result); @@ -2844,10 +2937,11 @@ napi_status NAPI_CDECL napi_create_reference(napi_env env, // there are other references to it. // For a napi_reference returned from `napi_wrap`, this must be called in the // finalizer. -napi_status NAPI_CDECL napi_delete_reference(node_api_basic_env env, +napi_status NAPI_CDECL napi_delete_reference(node_api_basic_env basic_env, napi_ref ref) { // Omit NAPI_PREAMBLE and GET_RETURN_STATUS because V8 calls here cannot throw // JS exceptions. + v8impl::NodeApiBaseEnv* env = v8impl::AsNodeApiBaseEnv(basic_env); CHECK_ENV(env); CHECK_ARG(env, ref); @@ -2861,11 +2955,12 @@ napi_status NAPI_CDECL napi_delete_reference(node_api_basic_env env, // refcount is >0, and the referenced object is effectively "pinned". // Calling this when the refcount is 0 and the object is unavailable // results in an error. -napi_status NAPI_CDECL napi_reference_ref(napi_env env, +napi_status NAPI_CDECL napi_reference_ref(napi_env env_, napi_ref ref, uint32_t* result) { // Omit NAPI_PREAMBLE and GET_RETURN_STATUS because V8 calls here cannot throw // JS exceptions. + v8impl::NodeApiBaseEnv* env = v8impl::AsNodeApiBaseEnv(env_); CHECK_ENV_NOT_IN_GC(env); CHECK_ARG(env, ref); @@ -2883,11 +2978,12 @@ napi_status NAPI_CDECL napi_reference_ref(napi_env env, // the result is 0 the reference is now weak and the object may be GC'd at any // time if there are no other references. Calling this when the refcount is // already 0 results in an error. -napi_status NAPI_CDECL napi_reference_unref(napi_env env, +napi_status NAPI_CDECL napi_reference_unref(napi_env env_, napi_ref ref, uint32_t* result) { // Omit NAPI_PREAMBLE and GET_RETURN_STATUS because V8 calls here cannot throw // JS exceptions. + v8impl::NodeApiBaseEnv* env = v8impl::AsNodeApiBaseEnv(env_); CHECK_ENV_NOT_IN_GC(env); CHECK_ARG(env, ref); @@ -2909,11 +3005,12 @@ napi_status NAPI_CDECL napi_reference_unref(napi_env env, // Attempts to get a referenced value. If the reference is weak, the value might // no longer be available, in that case the call is still successful but the // result is NULL. -napi_status NAPI_CDECL napi_get_reference_value(napi_env env, +napi_status NAPI_CDECL napi_get_reference_value(napi_env env_, napi_ref ref, napi_value* result) { // Omit NAPI_PREAMBLE and GET_RETURN_STATUS because V8 calls here cannot throw // JS exceptions. + v8impl::NodeApiBaseEnv* env = v8impl::AsNodeApiBaseEnv(env_); CHECK_ENV_NOT_IN_GC(env); CHECK_ARG(env, ref); CHECK_ARG(env, result); @@ -2924,10 +3021,11 @@ napi_status NAPI_CDECL napi_get_reference_value(napi_env env, return napi_clear_last_error(env); } -napi_status NAPI_CDECL napi_open_handle_scope(napi_env env, +napi_status NAPI_CDECL napi_open_handle_scope(napi_env env_, napi_handle_scope* result) { // Omit NAPI_PREAMBLE and GET_RETURN_STATUS because V8 calls here cannot throw // JS exceptions. + v8impl::NodeApiBaseEnv* env = v8impl::AsNodeApiBaseEnv(env_); CHECK_ENV_NOT_IN_GC(env); CHECK_ARG(env, result); @@ -2937,10 +3035,11 @@ napi_status NAPI_CDECL napi_open_handle_scope(napi_env env, return napi_clear_last_error(env); } -napi_status NAPI_CDECL napi_close_handle_scope(napi_env env, +napi_status NAPI_CDECL napi_close_handle_scope(napi_env env_, napi_handle_scope scope) { // Omit NAPI_PREAMBLE and GET_RETURN_STATUS because V8 calls here cannot throw // JS exceptions. + v8impl::NodeApiBaseEnv* env = v8impl::AsNodeApiBaseEnv(env_); CHECK_ENV_NOT_IN_GC(env); CHECK_ARG(env, scope); if (env->open_handle_scopes == 0) { @@ -2953,9 +3052,10 @@ napi_status NAPI_CDECL napi_close_handle_scope(napi_env env, } napi_status NAPI_CDECL napi_open_escapable_handle_scope( - napi_env env, napi_escapable_handle_scope* result) { + napi_env env_, napi_escapable_handle_scope* result) { // Omit NAPI_PREAMBLE and GET_RETURN_STATUS because V8 calls here cannot throw // JS exceptions. + v8impl::NodeApiBaseEnv* env = v8impl::AsNodeApiBaseEnv(env_); CHECK_ENV_NOT_IN_GC(env); CHECK_ARG(env, result); @@ -2966,9 +3066,10 @@ napi_status NAPI_CDECL napi_open_escapable_handle_scope( } napi_status NAPI_CDECL napi_close_escapable_handle_scope( - napi_env env, napi_escapable_handle_scope scope) { + napi_env env_, napi_escapable_handle_scope scope) { // Omit NAPI_PREAMBLE and GET_RETURN_STATUS because V8 calls here cannot throw // JS exceptions. + v8impl::NodeApiBaseEnv* env = v8impl::AsNodeApiBaseEnv(env_); CHECK_ENV_NOT_IN_GC(env); CHECK_ARG(env, scope); if (env->open_handle_scopes == 0) { @@ -2980,12 +3081,13 @@ napi_status NAPI_CDECL napi_close_escapable_handle_scope( return napi_clear_last_error(env); } -napi_status NAPI_CDECL napi_escape_handle(napi_env env, +napi_status NAPI_CDECL napi_escape_handle(napi_env env_, napi_escapable_handle_scope scope, napi_value escapee, napi_value* result) { // Omit NAPI_PREAMBLE and GET_RETURN_STATUS because V8 calls here cannot throw // JS exceptions. + v8impl::NodeApiBaseEnv* env = v8impl::AsNodeApiBaseEnv(env_); CHECK_ENV_NOT_IN_GC(env); CHECK_ARG(env, scope); CHECK_ARG(env, escapee); @@ -3001,11 +3103,12 @@ napi_status NAPI_CDECL napi_escape_handle(napi_env env, return napi_set_last_error(env, napi_escape_called_twice); } -napi_status NAPI_CDECL napi_new_instance(napi_env env, +napi_status NAPI_CDECL napi_new_instance(napi_env env_, napi_value constructor, size_t argc, const napi_value* argv, napi_value* result) { + v8impl::NodeApiBaseEnv* env = v8impl::AsNodeApiBaseEnv(env_); NAPI_PREAMBLE(env); CHECK_ARG(env, constructor); if (argc > 0) { @@ -3029,10 +3132,11 @@ napi_status NAPI_CDECL napi_new_instance(napi_env env, return GET_RETURN_STATUS(env); } -napi_status NAPI_CDECL napi_instanceof(napi_env env, +napi_status NAPI_CDECL napi_instanceof(napi_env env_, napi_value object, napi_value constructor, bool* result) { + v8impl::NodeApiBaseEnv* env = v8impl::AsNodeApiBaseEnv(env_); NAPI_PREAMBLE(env); CHECK_ARG(env, object); CHECK_ARG(env, result); @@ -3061,9 +3165,10 @@ napi_status NAPI_CDECL napi_instanceof(napi_env env, } // Methods to support catching exceptions -napi_status NAPI_CDECL napi_is_exception_pending(napi_env env, bool* result) { +napi_status NAPI_CDECL napi_is_exception_pending(napi_env env_, bool* result) { // NAPI_PREAMBLE is not used here: this function must execute when there is a // pending exception. + v8impl::NodeApiBaseEnv* env = v8impl::AsNodeApiBaseEnv(env_); CHECK_ENV_NOT_IN_GC(env); CHECK_ARG(env, result); @@ -3071,10 +3176,11 @@ napi_status NAPI_CDECL napi_is_exception_pending(napi_env env, bool* result) { return napi_clear_last_error(env); } -napi_status NAPI_CDECL napi_get_and_clear_last_exception(napi_env env, +napi_status NAPI_CDECL napi_get_and_clear_last_exception(napi_env env_, napi_value* result) { // NAPI_PREAMBLE is not used here: this function must execute when there is a // pending exception. + v8impl::NodeApiBaseEnv* env = v8impl::AsNodeApiBaseEnv(env_); CHECK_ENV_NOT_IN_GC(env); CHECK_ARG(env, result); @@ -3089,9 +3195,10 @@ napi_status NAPI_CDECL napi_get_and_clear_last_exception(napi_env env, return napi_clear_last_error(env); } -napi_status NAPI_CDECL napi_is_arraybuffer(napi_env env, +napi_status NAPI_CDECL napi_is_arraybuffer(napi_env env_, napi_value value, bool* result) { + v8impl::NodeApiBaseEnv* env = v8impl::AsNodeApiBaseEnv(env_); CHECK_ENV_NOT_IN_GC(env); CHECK_ARG(env, value); CHECK_ARG(env, result); @@ -3102,10 +3209,11 @@ napi_status NAPI_CDECL napi_is_arraybuffer(napi_env env, return napi_clear_last_error(env); } -napi_status NAPI_CDECL napi_create_arraybuffer(napi_env env, +napi_status NAPI_CDECL napi_create_arraybuffer(napi_env env_, size_t byte_length, void** data, napi_value* result) { + v8impl::NodeApiBaseEnv* env = v8impl::AsNodeApiBaseEnv(env_); NAPI_PREAMBLE(env); CHECK_ARG(env, result); @@ -3124,7 +3232,7 @@ napi_status NAPI_CDECL napi_create_arraybuffer(napi_env env, } napi_status NAPI_CDECL -napi_create_external_arraybuffer(napi_env env, +napi_create_external_arraybuffer(napi_env env_, void* external_data, size_t byte_length, node_api_basic_finalize finalize_cb, @@ -3135,18 +3243,19 @@ napi_create_external_arraybuffer(napi_env env, // `Buffer` variant for easier implementation. napi_value buffer; STATUS_CALL(napi_create_external_buffer( - env, byte_length, external_data, finalize_cb, finalize_hint, &buffer)); + env_, byte_length, external_data, finalize_cb, finalize_hint, &buffer)); return napi_get_typedarray_info( - env, buffer, nullptr, nullptr, nullptr, result, nullptr); + env_, buffer, nullptr, nullptr, nullptr, result, nullptr); } napi_status NAPI_CDECL -node_api_create_external_sharedarraybuffer(napi_env env, +node_api_create_external_sharedarraybuffer(napi_env env_, void* external_data, size_t byte_length, node_api_noenv_finalize finalize_cb, void* finalize_hint, napi_value* result) { + v8impl::NodeApiBaseEnv* env = v8impl::AsNodeApiBaseEnv(env_); NAPI_PREAMBLE(env); CHECK_ARG(env, result); #ifdef V8_ENABLE_SANDBOX @@ -3182,10 +3291,11 @@ node_api_create_external_sharedarraybuffer(napi_env env, #endif // V8_ENABLE_SANDBOX } -napi_status NAPI_CDECL napi_get_arraybuffer_info(napi_env env, +napi_status NAPI_CDECL napi_get_arraybuffer_info(napi_env env_, napi_value arraybuffer, void** data, size_t* byte_length) { + v8impl::NodeApiBaseEnv* env = v8impl::AsNodeApiBaseEnv(env_); CHECK_ENV_NOT_IN_GC(env); CHECK_ARG(env, arraybuffer); @@ -3218,9 +3328,10 @@ napi_status NAPI_CDECL napi_get_arraybuffer_info(napi_env env, return napi_clear_last_error(env); } -napi_status NAPI_CDECL node_api_is_sharedarraybuffer(napi_env env, +napi_status NAPI_CDECL node_api_is_sharedarraybuffer(napi_env env_, napi_value value, bool* result) { + v8impl::NodeApiBaseEnv* env = v8impl::AsNodeApiBaseEnv(env_); CHECK_ENV_NOT_IN_GC(env); CHECK_ARG(env, value); CHECK_ARG(env, result); @@ -3231,10 +3342,11 @@ napi_status NAPI_CDECL node_api_is_sharedarraybuffer(napi_env env, return napi_clear_last_error(env); } -napi_status NAPI_CDECL node_api_create_sharedarraybuffer(napi_env env, +napi_status NAPI_CDECL node_api_create_sharedarraybuffer(napi_env env_, size_t byte_length, void** data, napi_value* result) { + v8impl::NodeApiBaseEnv* env = v8impl::AsNodeApiBaseEnv(env_); NAPI_PREAMBLE(env); CHECK_ARG(env, result); @@ -3252,9 +3364,10 @@ napi_status NAPI_CDECL node_api_create_sharedarraybuffer(napi_env env, return GET_RETURN_STATUS(env); } -napi_status NAPI_CDECL napi_is_typedarray(napi_env env, +napi_status NAPI_CDECL napi_is_typedarray(napi_env env_, napi_value value, bool* result) { + v8impl::NodeApiBaseEnv* env = v8impl::AsNodeApiBaseEnv(env_); CHECK_ENV_NOT_IN_GC(env); CHECK_ARG(env, value); CHECK_ARG(env, result); @@ -3265,12 +3378,13 @@ napi_status NAPI_CDECL napi_is_typedarray(napi_env env, return napi_clear_last_error(env); } -napi_status NAPI_CDECL napi_create_typedarray(napi_env env, +napi_status NAPI_CDECL napi_create_typedarray(napi_env env_, napi_typedarray_type type, size_t length, napi_value arraybuffer, size_t byte_offset, napi_value* result) { + v8impl::NodeApiBaseEnv* env = v8impl::AsNodeApiBaseEnv(env_); NAPI_PREAMBLE(env); CHECK_ARG(env, arraybuffer); CHECK_ARG(env, result); @@ -3345,13 +3459,14 @@ napi_status NAPI_CDECL napi_create_typedarray(napi_env env, } } -napi_status NAPI_CDECL napi_get_typedarray_info(napi_env env, +napi_status NAPI_CDECL napi_get_typedarray_info(napi_env env_, napi_value typedarray, napi_typedarray_type* type, size_t* length, void** data, napi_value* arraybuffer, size_t* byte_offset) { + v8impl::NodeApiBaseEnv* env = v8impl::AsNodeApiBaseEnv(env_); CHECK_ENV_NOT_IN_GC(env); CHECK_ARG(env, typedarray); @@ -3414,11 +3529,12 @@ napi_status NAPI_CDECL napi_get_typedarray_info(napi_env env, return napi_clear_last_error(env); } -napi_status NAPI_CDECL napi_create_dataview(napi_env env, +napi_status NAPI_CDECL napi_create_dataview(napi_env env_, size_t byte_length, napi_value arraybuffer, size_t byte_offset, napi_value* result) { + v8impl::NodeApiBaseEnv* env = v8impl::AsNodeApiBaseEnv(env_); NAPI_PREAMBLE(env); CHECK_ARG(env, arraybuffer); CHECK_ARG(env, result); @@ -3450,9 +3566,10 @@ napi_status NAPI_CDECL napi_create_dataview(napi_env env, } } -napi_status NAPI_CDECL napi_is_dataview(napi_env env, +napi_status NAPI_CDECL napi_is_dataview(napi_env env_, napi_value value, bool* result) { + v8impl::NodeApiBaseEnv* env = v8impl::AsNodeApiBaseEnv(env_); CHECK_ENV_NOT_IN_GC(env); CHECK_ARG(env, value); CHECK_ARG(env, result); @@ -3463,12 +3580,13 @@ napi_status NAPI_CDECL napi_is_dataview(napi_env env, return napi_clear_last_error(env); } -napi_status NAPI_CDECL napi_get_dataview_info(napi_env env, +napi_status NAPI_CDECL napi_get_dataview_info(napi_env env_, napi_value dataview, size_t* byte_length, void** data, napi_value* arraybuffer, size_t* byte_offset) { + v8impl::NodeApiBaseEnv* env = v8impl::AsNodeApiBaseEnv(env_); CHECK_ENV_NOT_IN_GC(env); CHECK_ARG(env, dataview); @@ -3503,17 +3621,19 @@ napi_status NAPI_CDECL napi_get_dataview_info(napi_env env, return napi_clear_last_error(env); } -napi_status NAPI_CDECL napi_get_version(node_api_basic_env env, +napi_status NAPI_CDECL napi_get_version(node_api_basic_env basic_env, uint32_t* result) { + v8impl::NodeApiBaseEnv* env = v8impl::AsNodeApiBaseEnv(basic_env); CHECK_ENV(env); CHECK_ARG(env, result); *result = NODE_API_SUPPORTED_VERSION_MAX; return napi_clear_last_error(env); } -napi_status NAPI_CDECL napi_create_promise(napi_env env, +napi_status NAPI_CDECL napi_create_promise(napi_env env_, napi_deferred* deferred, napi_value* promise) { + v8impl::NodeApiBaseEnv* env = v8impl::AsNodeApiBaseEnv(env_); NAPI_PREAMBLE(env); CHECK_ARG(env, deferred); CHECK_ARG(env, promise); @@ -3530,21 +3650,24 @@ napi_status NAPI_CDECL napi_create_promise(napi_env env, return GET_RETURN_STATUS(env); } -napi_status NAPI_CDECL napi_resolve_deferred(napi_env env, +napi_status NAPI_CDECL napi_resolve_deferred(napi_env env_, napi_deferred deferred, napi_value resolution) { + v8impl::NodeApiBaseEnv* env = v8impl::AsNodeApiBaseEnv(env_); return v8impl::ConcludeDeferred(env, deferred, resolution, true); } -napi_status NAPI_CDECL napi_reject_deferred(napi_env env, +napi_status NAPI_CDECL napi_reject_deferred(napi_env env_, napi_deferred deferred, napi_value resolution) { + v8impl::NodeApiBaseEnv* env = v8impl::AsNodeApiBaseEnv(env_); return v8impl::ConcludeDeferred(env, deferred, resolution, false); } -napi_status NAPI_CDECL napi_is_promise(napi_env env, +napi_status NAPI_CDECL napi_is_promise(napi_env env_, napi_value value, bool* is_promise) { + v8impl::NodeApiBaseEnv* env = v8impl::AsNodeApiBaseEnv(env_); CHECK_ENV_NOT_IN_GC(env); CHECK_ARG(env, value); CHECK_ARG(env, is_promise); @@ -3554,9 +3677,10 @@ napi_status NAPI_CDECL napi_is_promise(napi_env env, return napi_clear_last_error(env); } -napi_status NAPI_CDECL napi_create_date(napi_env env, +napi_status NAPI_CDECL napi_create_date(napi_env env_, double time, napi_value* result) { + v8impl::NodeApiBaseEnv* env = v8impl::AsNodeApiBaseEnv(env_); NAPI_PREAMBLE(env); CHECK_ARG(env, result); @@ -3568,9 +3692,10 @@ napi_status NAPI_CDECL napi_create_date(napi_env env, return GET_RETURN_STATUS(env); } -napi_status NAPI_CDECL napi_is_date(napi_env env, +napi_status NAPI_CDECL napi_is_date(napi_env env_, napi_value value, bool* is_date) { + v8impl::NodeApiBaseEnv* env = v8impl::AsNodeApiBaseEnv(env_); CHECK_ENV_NOT_IN_GC(env); CHECK_ARG(env, value); CHECK_ARG(env, is_date); @@ -3580,9 +3705,10 @@ napi_status NAPI_CDECL napi_is_date(napi_env env, return napi_clear_last_error(env); } -napi_status NAPI_CDECL napi_get_date_value(napi_env env, +napi_status NAPI_CDECL napi_get_date_value(napi_env env_, napi_value value, double* result) { + v8impl::NodeApiBaseEnv* env = v8impl::AsNodeApiBaseEnv(env_); NAPI_PREAMBLE(env); CHECK_ARG(env, value); CHECK_ARG(env, result); @@ -3596,9 +3722,10 @@ napi_status NAPI_CDECL napi_get_date_value(napi_env env, return GET_RETURN_STATUS(env); } -napi_status NAPI_CDECL napi_run_script(napi_env env, +napi_status NAPI_CDECL napi_run_script(napi_env env_, napi_value script, napi_value* result) { + v8impl::NodeApiBaseEnv* env = v8impl::AsNodeApiBaseEnv(env_); NAPI_PREAMBLE(env); CHECK_ARG(env, script); CHECK_ARG(env, result); @@ -3622,7 +3749,7 @@ napi_status NAPI_CDECL napi_run_script(napi_env env, } napi_status NAPI_CDECL -napi_add_finalizer(napi_env env, +napi_add_finalizer(napi_env env_, napi_value js_object, void* finalize_data, node_api_basic_finalize basic_finalize_cb, @@ -3630,6 +3757,7 @@ napi_add_finalizer(napi_env env, napi_ref* result) { // Omit NAPI_PREAMBLE and GET_RETURN_STATUS because V8 calls here cannot throw // JS exceptions. + v8impl::NodeApiBaseEnv* env = v8impl::AsNodeApiBaseEnv(env_); napi_finalize finalize_cb = reinterpret_cast(basic_finalize_cb); CHECK_ENV_NOT_IN_GC(env); @@ -3659,7 +3787,7 @@ napi_status NAPI_CDECL node_api_post_finalizer(node_api_basic_env basic_env, napi_finalize finalize_cb, void* finalize_data, void* finalize_hint) { - napi_env env = const_cast(basic_env); + v8impl::NodeApiBaseEnv* env = v8impl::AsNodeApiBaseEnv(basic_env); CHECK_ENV(env); env->EnqueueFinalizer(v8impl::TrackedFinalizer::New( env, finalize_cb, finalize_data, finalize_hint)); @@ -3668,9 +3796,10 @@ napi_status NAPI_CDECL node_api_post_finalizer(node_api_basic_env basic_env, #endif -napi_status NAPI_CDECL napi_adjust_external_memory(node_api_basic_env env, +napi_status NAPI_CDECL napi_adjust_external_memory(node_api_basic_env basic_env, int64_t change_in_bytes, int64_t* adjusted_value) { + v8impl::NodeApiBaseEnv* env = v8impl::AsNodeApiBaseEnv(basic_env); CHECK_ENV(env); CHECK_ARG(env, adjusted_value); @@ -3684,7 +3813,7 @@ napi_status NAPI_CDECL napi_set_instance_data(node_api_basic_env basic_env, void* data, napi_finalize finalize_cb, void* finalize_hint) { - napi_env env = const_cast(basic_env); + v8impl::NodeApiBaseEnv* env = v8impl::AsNodeApiBaseEnv(basic_env); CHECK_ENV(env); v8impl::TrackedFinalizer* old_data = @@ -3701,8 +3830,9 @@ napi_status NAPI_CDECL napi_set_instance_data(node_api_basic_env basic_env, return napi_clear_last_error(env); } -napi_status NAPI_CDECL napi_get_instance_data(node_api_basic_env env, +napi_status NAPI_CDECL napi_get_instance_data(node_api_basic_env basic_env, void** data) { + v8impl::NodeApiBaseEnv* env = v8impl::AsNodeApiBaseEnv(basic_env); CHECK_ENV(env); CHECK_ARG(env, data); @@ -3714,8 +3844,9 @@ napi_status NAPI_CDECL napi_get_instance_data(node_api_basic_env env, return napi_clear_last_error(env); } -napi_status NAPI_CDECL napi_detach_arraybuffer(napi_env env, +napi_status NAPI_CDECL napi_detach_arraybuffer(napi_env env_, napi_value arraybuffer) { + v8impl::NodeApiBaseEnv* env = v8impl::AsNodeApiBaseEnv(env_); CHECK_ENV_NOT_IN_GC(env); CHECK_ARG(env, arraybuffer); @@ -3732,9 +3863,10 @@ napi_status NAPI_CDECL napi_detach_arraybuffer(napi_env env, return napi_clear_last_error(env); } -napi_status NAPI_CDECL napi_is_detached_arraybuffer(napi_env env, +napi_status NAPI_CDECL napi_is_detached_arraybuffer(napi_env env_, napi_value arraybuffer, bool* result) { + v8impl::NodeApiBaseEnv* env = v8impl::AsNodeApiBaseEnv(env_); CHECK_ENV_NOT_IN_GC(env); CHECK_ARG(env, arraybuffer); CHECK_ARG(env, result); @@ -3746,3 +3878,143 @@ napi_status NAPI_CDECL napi_is_detached_arraybuffer(napi_env env, return napi_clear_last_error(env); } + +namespace v8impl { + +static const node_api_js_vtable g_js_vtable = { + napi_get_last_error_info, + napi_get_undefined, + napi_get_null, + napi_get_global, + napi_get_boolean, + napi_create_object, + napi_create_array, + napi_create_array_with_length, + napi_create_double, + napi_create_int32, + napi_create_uint32, + napi_create_int64, + napi_create_string_latin1, + napi_create_string_utf8, + napi_create_string_utf16, + napi_create_symbol, + napi_create_function, + napi_create_error, + napi_create_type_error, + napi_create_range_error, + napi_typeof, + napi_get_value_double, + napi_get_value_int32, + napi_get_value_uint32, + napi_get_value_int64, + napi_get_value_bool, + napi_get_value_string_latin1, + napi_get_value_string_utf8, + napi_get_value_string_utf16, + napi_coerce_to_bool, + napi_coerce_to_number, + napi_coerce_to_object, + napi_coerce_to_string, + napi_get_prototype, + napi_get_property_names, + napi_set_property, + napi_has_property, + napi_get_property, + napi_delete_property, + napi_has_own_property, + napi_set_named_property, + napi_has_named_property, + napi_get_named_property, + napi_set_element, + napi_has_element, + napi_get_element, + napi_delete_element, + napi_define_properties, + napi_is_array, + napi_get_array_length, + napi_strict_equals, + napi_call_function, + napi_new_instance, + napi_instanceof, + napi_get_cb_info, + napi_get_new_target, + napi_define_class, + napi_wrap, + napi_unwrap, + napi_remove_wrap, + napi_create_external, + napi_get_value_external, + napi_create_reference, + napi_delete_reference, + napi_reference_ref, + napi_reference_unref, + napi_get_reference_value, + napi_open_handle_scope, + napi_close_handle_scope, + napi_open_escapable_handle_scope, + napi_close_escapable_handle_scope, + napi_escape_handle, + napi_throw, + napi_throw_error, + napi_throw_type_error, + napi_throw_range_error, + napi_is_error, + napi_is_exception_pending, + napi_get_and_clear_last_exception, + napi_is_arraybuffer, + napi_create_arraybuffer, + napi_create_external_arraybuffer, + napi_get_arraybuffer_info, + napi_is_typedarray, + napi_create_typedarray, + napi_get_typedarray_info, + napi_create_dataview, + napi_is_dataview, + napi_get_dataview_info, + napi_get_version, + napi_create_promise, + napi_resolve_deferred, + napi_reject_deferred, + napi_is_promise, + napi_run_script, + napi_adjust_external_memory, + napi_create_date, + napi_is_date, + napi_get_date_value, + napi_add_finalizer, + napi_create_bigint_int64, + napi_create_bigint_uint64, + napi_create_bigint_words, + napi_get_value_bigint_int64, + napi_get_value_bigint_uint64, + napi_get_value_bigint_words, + napi_get_all_property_names, + napi_set_instance_data, + napi_get_instance_data, + napi_detach_arraybuffer, + napi_is_detached_arraybuffer, + napi_type_tag_object, + napi_check_object_type_tag, + napi_object_freeze, + napi_object_seal, + node_api_symbol_for, + node_api_create_syntax_error, + node_api_throw_syntax_error, + node_api_create_external_string_latin1, + node_api_create_external_string_utf16, + node_api_create_property_key_latin1, + node_api_create_property_key_utf8, + node_api_create_property_key_utf16, + node_api_create_object_with_properties, + node_api_is_sharedarraybuffer, + node_api_create_sharedarraybuffer, + node_api_set_prototype, + node_api_create_external_sharedarraybuffer, + node_api_post_finalizer, +}; + +const node_api_js_vtable* GetNodeApiJsVTable() { + return &g_js_vtable; +} + +} // namespace v8impl diff --git a/src/js_native_api_v8.h b/src/js_native_api_v8.h index 262916c09b5b78..0db3b46703bcc0 100644 --- a/src/js_native_api_v8.h +++ b/src/js_native_api_v8.h @@ -4,7 +4,7 @@ #include "js_native_api_types.h" #include "js_native_api_v8_internals.h" -inline napi_status napi_clear_last_error(node_api_basic_env env); +extern napi_status napi_clear_last_error(node_api_basic_env basic_env); namespace v8impl { @@ -48,12 +48,13 @@ class RefTracker { RefList* prev_ = nullptr; }; -} // end of namespace v8impl - -struct napi_env__ { - explicit napi_env__(v8::Local context, - int32_t module_api_version) - : isolate(v8::Isolate::GetCurrent()), +struct NodeApiBaseEnv : public napi_env__ { + explicit NodeApiBaseEnv(v8::Local context, + int32_t module_api_version) + : napi_env__{NODE_API_VT_SENTINEL, + GetNodeApiJsVTable(), + GetNodeApiModuleVTable()}, + isolate(v8::Isolate::GetCurrent()), context_persistent(isolate, context), module_api_version(module_api_version) { napi_clear_last_error(this); @@ -70,7 +71,8 @@ struct napi_env__ { virtual bool can_call_into_js() const { return true; } - static inline void HandleThrow(napi_env env, v8::Local value) { + static inline void HandleThrow(NodeApiBaseEnv* env, + v8::Local value) { if (env->terminatedOrTerminating()) { return; } @@ -104,7 +106,7 @@ struct napi_env__ { // Invoke finalizer from V8 garbage collector. void InvokeFinalizerFromGC(v8impl::RefTracker* finalizer); - // Enqueue the finalizer to the napi_env's own queue of the second pass + // Enqueue the finalizer to the NodeApiBaseEnv's own queue of the second pass // weak callback. // Implementation should drain the queue at the time it is safe to call // into JavaScript. @@ -149,7 +151,7 @@ struct napi_env__ { // We store references in two different lists, depending on whether they have // `napi_finalizer` callbacks, because we must first finalize the ones that - // have such a callback. See `~napi_env__()` above for details. + // have such a callback. See `~NodeApiBaseEnv()` above for details. v8impl::RefTracker::RefList reflist; v8impl::RefTracker::RefList finalizing_reflist; // The invocation order of the finalizers is not determined. @@ -163,13 +165,23 @@ struct napi_env__ { bool in_gc_finalizer = false; protected: - // Should not be deleted directly. Delete with `napi_env__::DeleteMe()` + // Should not be deleted directly. Delete with `NodeApiBaseEnv::DeleteMe()` // instead. - virtual ~napi_env__() = default; + virtual ~NodeApiBaseEnv() = default; }; +inline NodeApiBaseEnv* AsNodeApiBaseEnv(napi_env env) { + return static_cast(env); +} + +inline NodeApiBaseEnv* AsNodeApiBaseEnv(node_api_basic_env env) { + return static_cast(const_cast(env)); +} + +} // end of namespace v8impl + inline napi_status napi_clear_last_error(node_api_basic_env basic_env) { - napi_env env = const_cast(basic_env); + v8impl::NodeApiBaseEnv* env = v8impl::AsNodeApiBaseEnv(basic_env); env->last_error.error_code = napi_ok; env->last_error.engine_error_code = 0; env->last_error.engine_reserved = nullptr; @@ -181,7 +193,7 @@ inline napi_status napi_set_last_error(node_api_basic_env basic_env, napi_status error_code, uint32_t engine_error_code = 0, void* engine_reserved = nullptr) { - napi_env env = const_cast(basic_env); + v8impl::NodeApiBaseEnv* env = v8impl::AsNodeApiBaseEnv(basic_env); env->last_error.error_code = error_code; env->last_error.engine_error_code = engine_error_code; env->last_error.engine_reserved = engine_reserved; @@ -320,7 +332,7 @@ inline v8::Local V8LocalValueFromJsValue(napi_value v) { // Adapter for napi_finalize callbacks. class Finalizer { public: - Finalizer(napi_env env, + Finalizer(NodeApiBaseEnv* env, napi_finalize finalize_callback, void* finalize_data, void* finalize_hint) @@ -329,7 +341,7 @@ class Finalizer { finalize_data_(finalize_data), finalize_hint_(finalize_hint) {} - napi_env env() { return env_; } + NodeApiBaseEnv* env() { return env_; } void* data() { return finalize_data_; } void ResetEnv(); @@ -337,7 +349,7 @@ class Finalizer { void CallFinalizer(); private: - napi_env env_; + NodeApiBaseEnv* env_; napi_finalize finalize_callback_; void* finalize_data_; void* finalize_hint_; @@ -345,7 +357,8 @@ class Finalizer { class TryCatch : public v8::TryCatch { public: - explicit TryCatch(napi_env env) : v8::TryCatch(env->isolate), _env(env) {} + explicit TryCatch(NodeApiBaseEnv* env) + : v8::TryCatch(env->isolate), _env(env) {} ~TryCatch() { if (HasCaught()) { @@ -354,13 +367,13 @@ class TryCatch : public v8::TryCatch { } private: - napi_env _env; + NodeApiBaseEnv* _env; }; // Wrapper around Finalizer that can be tracked. class TrackedFinalizer final : public RefTracker { public: - static TrackedFinalizer* New(napi_env env, + static TrackedFinalizer* New(NodeApiBaseEnv* env, napi_finalize finalize_callback, void* finalize_data, void* finalize_hint); @@ -369,7 +382,7 @@ class TrackedFinalizer final : public RefTracker { void* data() { return finalizer_.data(); } private: - TrackedFinalizer(napi_env env, + TrackedFinalizer(NodeApiBaseEnv* env, napi_finalize finalize_callback, void* finalize_data, void* finalize_hint); @@ -392,7 +405,7 @@ enum class ReferenceOwnership : uint8_t { // Wrapper around v8impl::Persistent. class Reference : public RefTracker { public: - static Reference* New(napi_env env, + static Reference* New(NodeApiBaseEnv* env, v8::Local value, uint32_t initial_refcount, ReferenceOwnership ownership); @@ -400,7 +413,7 @@ class Reference : public RefTracker { uint32_t Ref(); uint32_t Unref(); - v8::Local Get(napi_env env); + v8::Local Get(NodeApiBaseEnv* env); virtual void ResetFinalizer() {} virtual void* Data() { return nullptr; } @@ -409,7 +422,7 @@ class Reference : public RefTracker { ReferenceOwnership ownership() { return ownership_; } protected: - Reference(napi_env env, + Reference(NodeApiBaseEnv* env, v8::Local value, uint32_t initial_refcount, ReferenceOwnership ownership); @@ -431,7 +444,7 @@ class Reference : public RefTracker { // Reference that can store additional data. class ReferenceWithData final : public Reference { public: - static ReferenceWithData* New(napi_env env, + static ReferenceWithData* New(NodeApiBaseEnv* env, v8::Local value, uint32_t initial_refcount, ReferenceOwnership ownership, @@ -440,7 +453,7 @@ class ReferenceWithData final : public Reference { void* Data() override { return data_; } private: - ReferenceWithData(napi_env env, + ReferenceWithData(NodeApiBaseEnv* env, v8::Local value, uint32_t initial_refcount, ReferenceOwnership ownership, @@ -453,7 +466,7 @@ class ReferenceWithData final : public Reference { // Reference that has a user finalizer callback. class ReferenceWithFinalizer final : public Reference { public: - static ReferenceWithFinalizer* New(napi_env env, + static ReferenceWithFinalizer* New(NodeApiBaseEnv* env, v8::Local value, uint32_t initial_refcount, ReferenceOwnership ownership, @@ -466,7 +479,7 @@ class ReferenceWithFinalizer final : public Reference { void* Data() override { return finalizer_.data(); } private: - ReferenceWithFinalizer(napi_env env, + ReferenceWithFinalizer(NodeApiBaseEnv* env, v8::Local value, uint32_t initial_refcount, ReferenceOwnership ownership, diff --git a/src/js_native_api_v8_internals.h b/src/js_native_api_v8_internals.h index 0914cf8504adc5..15013b96c0f795 100644 --- a/src/js_native_api_v8_internals.h +++ b/src/js_native_api_v8_internals.h @@ -40,6 +40,12 @@ using PersistentToLocal = node::PersistentToLocal; node::OnFatalError(location, message); } +// Defined in node_api.cc +extern const struct node_api_module_vtable* GetNodeApiModuleVTable(); + +// Defined in js_native_api_v8.cc +extern const struct node_api_js_vtable* GetNodeApiJsVTable(); + } // end of namespace v8impl #endif // SRC_JS_NATIVE_API_V8_INTERNALS_H_ diff --git a/src/node_api.cc b/src/node_api.cc index d80569d9e92e00..9d8bcc025ff453 100644 --- a/src/node_api.cc +++ b/src/node_api.cc @@ -1,12 +1,10 @@ + +#include "node_api.h" #include "async_context_frame.h" #include "async_wrap-inl.h" #include "env-inl.h" -#ifndef NAPI_EXPERIMENTAL -#define NAPI_EXPERIMENTAL -#endif #include "js_native_api_v8.h" #include "memory_tracker-inl.h" -#include "node_api.h" #include "node_api_internals.h" #include "node_binding.h" #include "node_buffer.h" @@ -34,12 +32,11 @@ static void ThrowNodeApiVersionError(node::Environment* node_env, error_message += NODE_STRINGIFY(NODE_API_SUPPORTED_VERSION_MAX) " add-ons."; node_env->ThrowError(error_message.c_str()); } -} // namespace v8impl -/*static*/ napi_env node_napi_env__::New(v8::Local context, - const std::string& module_filename, - int32_t module_api_version) { - node_napi_env result; +/*static*/ NodeApiBaseEnv* NodeApiEnv::New(v8::Local context, + const std::string& module_filename, + int32_t module_api_version) { + NodeApiEnv* result; // Validate module_api_version. if (module_api_version < NODE_API_DEFAULT_MODULE_API_VERSION) { @@ -53,7 +50,7 @@ static void ThrowNodeApiVersionError(node::Environment* node_env, return nullptr; } - result = new node_napi_env__(context, module_filename, module_api_version); + result = new NodeApiEnv(context, module_filename, module_api_version); // TODO(addaleax): There was previously code that tried to delete the // napi_env when its v8::Context was garbage collected; // However, as long as Node-API addons using this napi_env are in place, @@ -62,47 +59,47 @@ static void ThrowNodeApiVersionError(node::Environment* node_env, // once all Node-API addons using this napi_env are unloaded. // For now, a per-Environment cleanup hook is the best we can do. result->node_env()->AddCleanupHook( - [](void* arg) { static_cast(arg)->Unref(); }, + [](void* arg) { static_cast(arg)->Unref(); }, static_cast(result)); return result; } -node_napi_env__::node_napi_env__(v8::Local context, - const std::string& module_filename, - int32_t module_api_version) - : napi_env__(context, module_api_version), filename(module_filename) { +NodeApiEnv::NodeApiEnv(v8::Local context, + const std::string& module_filename, + int32_t module_api_version) + : NodeApiBaseEnv(context, module_api_version), filename(module_filename) { CHECK_NOT_NULL(node_env()); } -void node_napi_env__::DeleteMe() { +void NodeApiEnv::DeleteMe() { destructing = true; DrainFinalizerQueue(); - napi_env__::DeleteMe(); + NodeApiBaseEnv::DeleteMe(); } -bool node_napi_env__::can_call_into_js() const { +bool NodeApiEnv::can_call_into_js() const { return node_env()->can_call_into_js(); } -void node_napi_env__::CallFinalizer(napi_finalize cb, void* data, void* hint) { +void NodeApiEnv::CallFinalizer(napi_finalize cb, void* data, void* hint) { CallFinalizer(cb, data, hint); } template -void node_napi_env__::CallFinalizer(napi_finalize cb, void* data, void* hint) { +void NodeApiEnv::CallFinalizer(napi_finalize cb, void* data, void* hint) { v8::HandleScope handle_scope(isolate); v8::Context::Scope context_scope(context()); CallbackIntoModule( [&](napi_env env) { cb(env, data, hint); }); } -void node_napi_env__::EnqueueFinalizer(v8impl::RefTracker* finalizer) { - napi_env__::EnqueueFinalizer(finalizer); +void NodeApiEnv::EnqueueFinalizer(v8impl::RefTracker* finalizer) { + NodeApiBaseEnv::EnqueueFinalizer(finalizer); // Schedule a second pass only when it has not been scheduled, and not // destructing the env. // When the env is being destructed, queued finalizers are drained in the - // loop of `node_napi_env__::DrainFinalizerQueue`. + // loop of `NodeApiEnv::DrainFinalizerQueue`. if (!finalization_scheduled && !destructing) { finalization_scheduled = true; Ref(); @@ -114,7 +111,7 @@ void node_napi_env__::EnqueueFinalizer(v8impl::RefTracker* finalizer) { } } -void node_napi_env__::DrainFinalizerQueue() { +void NodeApiEnv::DrainFinalizerQueue() { // As userland code can delete additional references in one finalizer, // the list of pending finalizers may be mutated as we execute them, so // we keep iterating it until it is empty. @@ -125,7 +122,7 @@ void node_napi_env__::DrainFinalizerQueue() { } } -void node_napi_env__::trigger_fatal_exception(v8::Local local_err) { +void NodeApiEnv::trigger_fatal_exception(v8::Local local_err) { v8::Local local_msg = v8::Exception::CreateMessage(isolate, local_err); node::errors::TriggerUncaughtException(isolate, local_err, local_msg); @@ -134,9 +131,9 @@ void node_napi_env__::trigger_fatal_exception(v8::Local local_err) { // The option enforceUncaughtExceptionPolicy is added for not breaking existing // running Node-API add-ons. template -void node_napi_env__::CallbackIntoModule(T&& call) { +void NodeApiEnv::CallbackIntoModule(T&& call) { CallIntoModule(call, [](napi_env env_, v8::Local local_err) { - node_napi_env__* env = static_cast(env_); + NodeApiEnv* env = static_cast(env_); if (env->terminatedOrTerminating()) { return; } @@ -163,13 +160,11 @@ void node_napi_env__::CallbackIntoModule(T&& call) { }); } -namespace v8impl { - namespace { class BufferFinalizer : private Finalizer { public: - static BufferFinalizer* New(napi_env env, + static BufferFinalizer* New(NodeApiBaseEnv* env, napi_finalize finalize_callback, void* finalize_data, void* finalize_hint) { @@ -189,7 +184,7 @@ class BufferFinalizer : private Finalizer { }; private: - BufferFinalizer(napi_env env, + BufferFinalizer(NodeApiBaseEnv* env, napi_finalize finalize_callback, void* finalize_data, void* finalize_hint) @@ -200,7 +195,7 @@ class BufferFinalizer : private Finalizer { ~BufferFinalizer() { env()->Unref(); } }; -class ThreadSafeFunction { +class ThreadSafeFunction : public napi_threadsafe_function__ { public: ThreadSafeFunction(v8::Local func, v8::Local resource, @@ -208,11 +203,13 @@ class ThreadSafeFunction { size_t thread_count_, void* context_, size_t max_queue_size_, - node_napi_env env_, + NodeApiEnv* env_, void* finalize_data_, napi_finalize finalize_cb_, napi_threadsafe_function_call_js call_js_cb_) - : async_resource(std::in_place, + : napi_threadsafe_function__{NODE_API_VT_SENTINEL, + GetNodeApiModuleVTable()}, + async_resource(std::in_place, env_->isolate, resource, node::Utf8Value(env_->isolate, name).ToStringView()), @@ -577,7 +574,7 @@ class ThreadSafeFunction { // These are variables accessed only from the loop thread. v8impl::Persistent ref; - node_napi_env env; + NodeApiEnv* env; void* finalize_data; napi_finalize finalize_cb; napi_threadsafe_function_call_js call_js_cb; @@ -592,7 +589,7 @@ class ThreadSafeFunction { */ class AsyncContext { public: - AsyncContext(node_napi_env env, + AsyncContext(NodeApiEnv* env, v8::Local resource_object, v8::Local resource_name) : env_(env) { @@ -641,7 +638,7 @@ class AsyncContext { return {async_id_, trigger_async_id_}; } - static inline void CloseCallbackScope(node_napi_env env, + static inline void CloseCallbackScope(NodeApiEnv* env, napi_callback_scope s) { delete HeapAllocatedCallbackScope::FromOpaque(s); CHECK_GT(env->open_callback_scopes, 0); @@ -667,7 +664,7 @@ class AsyncContext { node::CallbackScope cs_; }; - node_napi_env env_; + NodeApiEnv* env_; double async_id_; double trigger_async_id_; v8::Global resource_; @@ -675,7 +672,6 @@ class AsyncContext { }; } // end of anonymous namespace - } // end of namespace v8impl // Intercepts the Node-V8 module registration callback. Converts parameters @@ -766,8 +762,8 @@ void napi_module_register_by_symbol(v8::Local exports, } // Create a new napi_env for this specific module. - napi_env env = - node_napi_env__::New(context, module_filename, module_api_version); + v8impl::NodeApiBaseEnv* env = + v8impl::NodeApiEnv::New(context, module_filename, module_api_version); napi_value _exports = nullptr; env->CallIntoModule([&](napi_env env) { @@ -807,9 +803,10 @@ void NAPI_CDECL napi_module_register(napi_module* mod) { node::node_module_register(nm); } -napi_status NAPI_CDECL napi_add_env_cleanup_hook(node_api_basic_env env, +napi_status NAPI_CDECL napi_add_env_cleanup_hook(node_api_basic_env basic_env, napi_cleanup_hook fun, void* arg) { + v8impl::NodeApiBaseEnv* env = v8impl::AsNodeApiBaseEnv(basic_env); CHECK_ENV(env); CHECK_ARG(env, fun); @@ -818,9 +815,9 @@ napi_status NAPI_CDECL napi_add_env_cleanup_hook(node_api_basic_env env, return napi_ok; } -napi_status NAPI_CDECL napi_remove_env_cleanup_hook(node_api_basic_env env, - napi_cleanup_hook fun, - void* arg) { +napi_status NAPI_CDECL napi_remove_env_cleanup_hook( + node_api_basic_env basic_env, napi_cleanup_hook fun, void* arg) { + v8impl::NodeApiBaseEnv* env = v8impl::AsNodeApiBaseEnv(basic_env); CHECK_ENV(env); CHECK_ARG(env, fun); @@ -829,52 +826,62 @@ napi_status NAPI_CDECL napi_remove_env_cleanup_hook(node_api_basic_env env, return napi_ok; } -struct napi_async_cleanup_hook_handle__ { - napi_async_cleanup_hook_handle__(napi_env env, - napi_async_cleanup_hook user_hook, - void* user_data) - : env_(env), user_hook_(user_hook), user_data_(user_data) { +namespace v8impl { +namespace { + +struct NodeApiAsyncCleanupHook : public napi_async_cleanup_hook_handle__ { + NodeApiAsyncCleanupHook(NodeApiBaseEnv* env, + napi_async_cleanup_hook user_hook, + void* user_data) + : napi_async_cleanup_hook_handle__{NODE_API_VT_SENTINEL, + GetNodeApiModuleVTable()}, + env_(env), + user_hook_(user_hook), + user_data_(user_data) { handle_ = node::AddEnvironmentCleanupHook(env->isolate, Hook, this); env->Ref(); } - ~napi_async_cleanup_hook_handle__() { + ~NodeApiAsyncCleanupHook() { node::RemoveEnvironmentCleanupHook(std::move(handle_)); if (done_cb_ != nullptr) done_cb_(done_data_); // Release the `env` handle asynchronously since it would be surprising if // a call to a Node-API function would destroy `env` synchronously. - static_cast(env_)->node_env()->SetImmediate( + static_cast(env_)->node_env()->SetImmediate( [env = env_](node::Environment*) { env->Unref(); }); } static void Hook(void* data, void (*done_cb)(void*), void* done_data) { - napi_async_cleanup_hook_handle__* handle = - static_cast(data); + NodeApiAsyncCleanupHook* handle = + static_cast(data); handle->done_cb_ = done_cb; handle->done_data_ = done_data; handle->user_hook_(handle, handle->user_data_); } node::AsyncCleanupHookHandle handle_; - napi_env env_ = nullptr; + NodeApiBaseEnv* env_ = nullptr; napi_async_cleanup_hook user_hook_ = nullptr; void* user_data_ = nullptr; void (*done_cb_)(void*) = nullptr; void* done_data_ = nullptr; }; +} // end of anonymous namespace +} // end of namespace v8impl + napi_status NAPI_CDECL napi_add_async_cleanup_hook(node_api_basic_env basic_env, napi_async_cleanup_hook hook, void* arg, napi_async_cleanup_hook_handle* remove_handle) { - napi_env env = const_cast(basic_env); + v8impl::NodeApiBaseEnv* env = v8impl::AsNodeApiBaseEnv(basic_env); CHECK_ENV(env); CHECK_ARG(env, hook); - napi_async_cleanup_hook_handle__* handle = - new napi_async_cleanup_hook_handle__(env, hook, arg); + v8impl::NodeApiAsyncCleanupHook* handle = + new v8impl::NodeApiAsyncCleanupHook(env, hook, arg); if (remove_handle != nullptr) *remove_handle = handle; @@ -885,17 +892,18 @@ napi_status NAPI_CDECL napi_remove_async_cleanup_hook(napi_async_cleanup_hook_handle remove_handle) { if (remove_handle == nullptr) return napi_invalid_arg; - delete remove_handle; + delete static_cast(remove_handle); return napi_ok; } -napi_status NAPI_CDECL napi_fatal_exception(napi_env env, napi_value err) { +napi_status NAPI_CDECL napi_fatal_exception(napi_env env_, napi_value err) { + v8impl::NodeApiBaseEnv* env = v8impl::AsNodeApiBaseEnv(env_); NAPI_PREAMBLE(env); CHECK_ARG(env, err); v8::Local local_err = v8impl::V8LocalValueFromJsValue(err); - static_cast(env)->trigger_fatal_exception(local_err); + static_cast(env)->trigger_fatal_exception(local_err); return napi_clear_last_error(env); } @@ -923,12 +931,13 @@ NAPI_NO_RETURN void NAPI_CDECL napi_fatal_error(const char* location, } napi_status NAPI_CDECL -napi_open_callback_scope(napi_env env, +napi_open_callback_scope(napi_env env_, napi_value /** ignored */, napi_async_context async_context_handle, napi_callback_scope* result) { // Omit NAPI_PREAMBLE and GET_RETURN_STATUS because V8 calls here cannot throw // JS exceptions. + v8impl::NodeApiBaseEnv* env = v8impl::AsNodeApiBaseEnv(env_); CHECK_ENV(env); CHECK_ARG(env, result); @@ -940,26 +949,28 @@ napi_open_callback_scope(napi_env env, return napi_clear_last_error(env); } -napi_status NAPI_CDECL napi_close_callback_scope(napi_env env, +napi_status NAPI_CDECL napi_close_callback_scope(napi_env env_, napi_callback_scope scope) { // Omit NAPI_PREAMBLE and GET_RETURN_STATUS because V8 calls here cannot throw // JS exceptions. + v8impl::NodeApiBaseEnv* env = v8impl::AsNodeApiBaseEnv(env_); CHECK_ENV(env); CHECK_ARG(env, scope); if (env->open_callback_scopes == 0) { return napi_callback_scope_mismatch; } - v8impl::AsyncContext::CloseCallbackScope(reinterpret_cast(env), - scope); + v8impl::AsyncContext::CloseCallbackScope( + static_cast(env), scope); return napi_clear_last_error(env); } -napi_status NAPI_CDECL napi_async_init(napi_env env, +napi_status NAPI_CDECL napi_async_init(napi_env env_, napi_value async_resource, napi_value async_resource_name, napi_async_context* result) { + v8impl::NodeApiBaseEnv* env = v8impl::AsNodeApiBaseEnv(env_); CHECK_ENV_NOT_IN_GC(env); CHECK_ARG(env, async_resource_name); CHECK_ARG(env, result); @@ -978,15 +989,16 @@ napi_status NAPI_CDECL napi_async_init(napi_env env, CHECK_TO_STRING(env, context, v8_resource_name, async_resource_name); v8impl::AsyncContext* async_context = new v8impl::AsyncContext( - reinterpret_cast(env), v8_resource, v8_resource_name); + static_cast(env), v8_resource, v8_resource_name); *result = reinterpret_cast(async_context); return napi_clear_last_error(env); } -napi_status NAPI_CDECL napi_async_destroy(napi_env env, +napi_status NAPI_CDECL napi_async_destroy(napi_env env_, napi_async_context async_context) { + v8impl::NodeApiBaseEnv* env = v8impl::AsNodeApiBaseEnv(env_); CHECK_ENV_NOT_IN_GC(env); CHECK_ARG(env, async_context); @@ -998,13 +1010,14 @@ napi_status NAPI_CDECL napi_async_destroy(napi_env env, return napi_clear_last_error(env); } -napi_status NAPI_CDECL napi_make_callback(napi_env env, +napi_status NAPI_CDECL napi_make_callback(napi_env env_, napi_async_context async_context, napi_value recv, napi_value func, size_t argc, const napi_value* argv, napi_value* result) { + v8impl::NodeApiBaseEnv* env = v8impl::AsNodeApiBaseEnv(env_); NAPI_PREAMBLE(env); CHECK_ARG(env, recv); if (argc > 0) { @@ -1052,10 +1065,11 @@ napi_status NAPI_CDECL napi_make_callback(napi_env env, return GET_RETURN_STATUS(env); } -napi_status NAPI_CDECL napi_create_buffer(napi_env env, +napi_status NAPI_CDECL napi_create_buffer(napi_env env_, size_t length, void** data, napi_value* result) { + v8impl::NodeApiBaseEnv* env = v8impl::AsNodeApiBaseEnv(env_); NAPI_PREAMBLE(env); CHECK_ARG(env, result); @@ -1075,12 +1089,13 @@ napi_status NAPI_CDECL napi_create_buffer(napi_env env, } napi_status NAPI_CDECL -napi_create_external_buffer(napi_env env, +napi_create_external_buffer(napi_env env_, size_t length, void* data, node_api_basic_finalize basic_finalize_cb, void* finalize_hint, napi_value* result) { + v8impl::NodeApiBaseEnv* env = v8impl::AsNodeApiBaseEnv(env_); napi_finalize finalize_cb = reinterpret_cast(basic_finalize_cb); NAPI_PREAMBLE(env); @@ -1113,11 +1128,12 @@ napi_create_external_buffer(napi_env env, #endif // V8_ENABLE_SANDBOX } -napi_status NAPI_CDECL napi_create_buffer_copy(napi_env env, +napi_status NAPI_CDECL napi_create_buffer_copy(napi_env env_, size_t length, const void* data, void** result_data, napi_value* result) { + v8impl::NodeApiBaseEnv* env = v8impl::AsNodeApiBaseEnv(env_); NAPI_PREAMBLE(env); CHECK_ARG(env, result); @@ -1136,9 +1152,10 @@ napi_status NAPI_CDECL napi_create_buffer_copy(napi_env env, return GET_RETURN_STATUS(env); } -napi_status NAPI_CDECL napi_is_buffer(napi_env env, +napi_status NAPI_CDECL napi_is_buffer(napi_env env_, napi_value value, bool* result) { + v8impl::NodeApiBaseEnv* env = v8impl::AsNodeApiBaseEnv(env_); CHECK_ENV_NOT_IN_GC(env); CHECK_ARG(env, value); CHECK_ARG(env, result); @@ -1147,10 +1164,11 @@ napi_status NAPI_CDECL napi_is_buffer(napi_env env, return napi_clear_last_error(env); } -napi_status NAPI_CDECL napi_get_buffer_info(napi_env env, +napi_status NAPI_CDECL napi_get_buffer_info(napi_env env_, napi_value value, void** data, size_t* length) { + v8impl::NodeApiBaseEnv* env = v8impl::AsNodeApiBaseEnv(env_); CHECK_ENV_NOT_IN_GC(env); CHECK_ARG(env, value); @@ -1168,8 +1186,9 @@ napi_status NAPI_CDECL napi_get_buffer_info(napi_env env, return napi_clear_last_error(env); } -napi_status NAPI_CDECL napi_get_node_version(node_api_basic_env env, +napi_status NAPI_CDECL napi_get_node_version(node_api_basic_env basic_env, const napi_node_version** result) { + v8impl::NodeApiBaseEnv* env = v8impl::AsNodeApiBaseEnv(basic_env); CHECK_ENV(env); CHECK_ARG(env, result); static const napi_node_version version = { @@ -1197,7 +1216,7 @@ static napi_status ConvertUVErrorCode(int code) { // Wrapper around uv_work_t which calls user-provided callbacks. class Work : public node::AsyncResource, public node::ThreadPoolWork { private: - explicit Work(node_napi_env env, + explicit Work(v8impl::NodeApiEnv* env, v8::Local async_resource, v8::Local async_resource_name, napi_async_execute_callback execute, @@ -1216,7 +1235,7 @@ class Work : public node::AsyncResource, public node::ThreadPoolWork { ~Work() override = default; public: - static Work* New(node_napi_env env, + static Work* New(v8impl::NodeApiEnv* env, v8::Local async_resource, v8::Local async_resource_name, napi_async_execute_callback execute, @@ -1248,7 +1267,7 @@ class Work : public node::AsyncResource, public node::ThreadPoolWork { } private: - node_napi_env _env; + v8impl::NodeApiEnv* _env; void* _data; napi_async_execute_callback _execute; napi_async_complete_callback _complete; @@ -1267,13 +1286,14 @@ class Work : public node::AsyncResource, public node::ThreadPoolWork { } while (0) napi_status NAPI_CDECL -napi_create_async_work(napi_env env, +napi_create_async_work(napi_env env_, napi_value async_resource, napi_value async_resource_name, napi_async_execute_callback execute, napi_async_complete_callback complete, void* data, napi_async_work* result) { + v8impl::NodeApiBaseEnv* env = v8impl::AsNodeApiBaseEnv(env_); CHECK_ENV_NOT_IN_GC(env); CHECK_ARG(env, execute); CHECK_ARG(env, result); @@ -1290,7 +1310,7 @@ napi_create_async_work(napi_env env, v8::Local resource_name; CHECK_TO_STRING(env, context, resource_name, async_resource_name); - uvimpl::Work* work = uvimpl::Work::New(reinterpret_cast(env), + uvimpl::Work* work = uvimpl::Work::New(static_cast(env), resource, resource_name, execute, @@ -1302,8 +1322,9 @@ napi_create_async_work(napi_env env, return napi_clear_last_error(env); } -napi_status NAPI_CDECL napi_delete_async_work(napi_env env, +napi_status NAPI_CDECL napi_delete_async_work(napi_env env_, napi_async_work work) { + v8impl::NodeApiBaseEnv* env = v8impl::AsNodeApiBaseEnv(env_); CHECK_ENV_NOT_IN_GC(env); CHECK_ARG(env, work); @@ -1314,15 +1335,16 @@ napi_status NAPI_CDECL napi_delete_async_work(napi_env env, napi_status NAPI_CDECL napi_get_uv_event_loop(node_api_basic_env basic_env, uv_loop_t** loop) { - napi_env env = const_cast(basic_env); + v8impl::NodeApiBaseEnv* env = v8impl::AsNodeApiBaseEnv(basic_env); CHECK_ENV(env); CHECK_ARG(env, loop); - *loop = reinterpret_cast(env)->node_env()->event_loop(); + *loop = static_cast(env)->node_env()->event_loop(); return napi_clear_last_error(env); } -napi_status NAPI_CDECL napi_queue_async_work(node_api_basic_env env, +napi_status NAPI_CDECL napi_queue_async_work(node_api_basic_env basic_env, napi_async_work work) { + v8impl::NodeApiBaseEnv* env = v8impl::AsNodeApiBaseEnv(basic_env); CHECK_ENV(env); CHECK_ARG(env, work); @@ -1336,8 +1358,9 @@ napi_status NAPI_CDECL napi_queue_async_work(node_api_basic_env env, return napi_clear_last_error(env); } -napi_status NAPI_CDECL napi_cancel_async_work(node_api_basic_env env, +napi_status NAPI_CDECL napi_cancel_async_work(node_api_basic_env basic_env, napi_async_work work) { + v8impl::NodeApiBaseEnv* env = v8impl::AsNodeApiBaseEnv(basic_env); CHECK_ENV(env); CHECK_ARG(env, work); @@ -1349,7 +1372,7 @@ napi_status NAPI_CDECL napi_cancel_async_work(node_api_basic_env env, } napi_status NAPI_CDECL -napi_create_threadsafe_function(napi_env env, +napi_create_threadsafe_function(napi_env env_, napi_value func, napi_value async_resource, napi_value async_resource_name, @@ -1360,6 +1383,7 @@ napi_create_threadsafe_function(napi_env env, void* context, napi_threadsafe_function_call_js call_js_cb, napi_threadsafe_function* result) { + v8impl::NodeApiBaseEnv* env = v8impl::AsNodeApiBaseEnv(env_); CHECK_ENV_NOT_IN_GC(env); CHECK_ARG(env, async_resource_name); RETURN_STATUS_IF_FALSE(env, initial_thread_count > 0, napi_invalid_arg); @@ -1393,7 +1417,7 @@ napi_create_threadsafe_function(napi_env env, initial_thread_count, context, max_queue_size, - reinterpret_cast(env), + static_cast(env), thread_finalize_data, thread_finalize_cb, call_js_cb); @@ -1404,7 +1428,7 @@ napi_create_threadsafe_function(napi_env env, // Init deletes ts_fn upon failure. status = ts_fn->Init(); if (status == napi_ok) { - *result = reinterpret_cast(ts_fn); + *result = ts_fn; } } @@ -1416,7 +1440,7 @@ napi_status NAPI_CDECL napi_get_threadsafe_function_context( CHECK_NOT_NULL(func); CHECK_NOT_NULL(result); - *result = reinterpret_cast(func)->Context(); + *result = static_cast(func)->Context(); return napi_ok; } @@ -1425,52 +1449,51 @@ napi_call_threadsafe_function(napi_threadsafe_function func, void* data, napi_threadsafe_function_call_mode is_blocking) { CHECK_NOT_NULL(func); - return reinterpret_cast(func)->Push(data, - is_blocking); + return static_cast(func)->Push(data, + is_blocking); } napi_status NAPI_CDECL napi_acquire_threadsafe_function(napi_threadsafe_function func) { CHECK_NOT_NULL(func); - return reinterpret_cast(func)->Acquire(); + return static_cast(func)->Acquire(); } napi_status NAPI_CDECL napi_release_threadsafe_function( napi_threadsafe_function func, napi_threadsafe_function_release_mode mode) { CHECK_NOT_NULL(func); - return reinterpret_cast(func)->Release(mode); + return static_cast(func)->Release(mode); } napi_status NAPI_CDECL napi_unref_threadsafe_function( node_api_basic_env env, napi_threadsafe_function func) { CHECK_NOT_NULL(func); - return reinterpret_cast(func)->Unref(); + return static_cast(func)->Unref(); } napi_status NAPI_CDECL napi_ref_threadsafe_function( node_api_basic_env env, napi_threadsafe_function func) { CHECK_NOT_NULL(func); - return reinterpret_cast(func)->Ref(); + return static_cast(func)->Ref(); } napi_status NAPI_CDECL node_api_get_module_file_name( node_api_basic_env basic_env, const char** result) { - napi_env env = const_cast(basic_env); + v8impl::NodeApiBaseEnv* env = v8impl::AsNodeApiBaseEnv(basic_env); CHECK_ENV(env); CHECK_ARG(env, result); - *result = static_cast(env)->GetFilename(); + *result = static_cast(env)->GetFilename(); return napi_clear_last_error(env); } -#ifdef NAPI_EXPERIMENTAL - napi_status NAPI_CDECL -node_api_create_buffer_from_arraybuffer(napi_env env, +node_api_create_buffer_from_arraybuffer(napi_env env_, napi_value arraybuffer, size_t byte_offset, size_t byte_length, napi_value* result) { + v8impl::NodeApiBaseEnv* env = v8impl::AsNodeApiBaseEnv(env_); NAPI_PREAMBLE(env); CHECK_ARG(env, arraybuffer); CHECK_ARG(env, result); @@ -1496,4 +1519,45 @@ node_api_create_buffer_from_arraybuffer(napi_env env, return napi_ok; } -#endif +namespace v8impl { + +static const node_api_module_vtable g_module_vtable = { + napi_module_register, + napi_fatal_error, + napi_async_init, + napi_async_destroy, + napi_make_callback, + napi_create_buffer, + napi_create_external_buffer, + napi_create_buffer_copy, + napi_is_buffer, + napi_get_buffer_info, + napi_create_async_work, + napi_delete_async_work, + napi_queue_async_work, + napi_cancel_async_work, + napi_get_node_version, + napi_get_uv_event_loop, + napi_fatal_exception, + napi_add_env_cleanup_hook, + napi_remove_env_cleanup_hook, + napi_open_callback_scope, + napi_close_callback_scope, + napi_create_threadsafe_function, + napi_get_threadsafe_function_context, + napi_call_threadsafe_function, + napi_acquire_threadsafe_function, + napi_release_threadsafe_function, + napi_unref_threadsafe_function, + napi_ref_threadsafe_function, + napi_add_async_cleanup_hook, + napi_remove_async_cleanup_hook, + node_api_get_module_file_name, + node_api_create_buffer_from_arraybuffer, +}; + +const node_api_module_vtable* GetNodeApiModuleVTable() { + return &g_module_vtable; +} + +} // namespace v8impl diff --git a/src/node_api.h b/src/node_api.h index 46dbb02b47d24b..c450ef1c176450 100644 --- a/src/node_api.h +++ b/src/node_api.h @@ -9,11 +9,10 @@ #define NAPI_EXTERN __attribute__((__import_module__("napi"))) #endif #endif + #include "js_native_api.h" #include "node_api_types.h" -struct uv_loop_s; // Forward declaration. - #ifdef _WIN32 #define NAPI_MODULE_EXPORT __declspec(dllexport) #else @@ -33,17 +32,6 @@ struct uv_loop_s; // Forward declaration. #define NAPI_NO_RETURN #endif -// Used by deprecated registration method napi_module_register. -typedef struct napi_module { - int nm_version; - unsigned int nm_flags; - const char* nm_filename; - napi_addon_register_func nm_register_func; - const char* nm_modname; - void* nm_priv; - void* reserved[4]; -} napi_module; - #define NAPI_MODULE_VERSION 1 #define NAPI_MODULE_INITIALIZER_X(base, version) \ @@ -65,6 +53,37 @@ typedef struct napi_module { NAPI_MODULE_INITIALIZER_X(NODE_API_MODULE_GET_API_VERSION_BASE, \ NAPI_MODULE_VERSION) +#ifdef NODE_API_MODULE_USE_VTABLE_IMPL + +#ifndef NODE_API_MODULE_NO_VTABLE_FALLBACK +#define NODE_API_VTABLE_FALLBACK_GLOBALS \ + node_api_js_vtable g_node_api_js_vtable_fallback = {0}; \ + node_api_module_vtable g_node_api_module_vtable_fallback = {0}; +#else +#define NODE_API_VTABLE_FALLBACK_GLOBALS +#endif + +#define NODE_API_MODULE_INITIALIZER_IMPL NAPI_MODULE_INITIALIZER##_impl + +// NOLINTBEGIN (readability/null_usage) - must be compilable by C compiler +#define NODE_API_MODULE_INITIALIZER_IMPL_EX \ + NODE_API_VTABLE_FALLBACK_GLOBALS \ + const node_api_module_vtable* g_node_api_module_vtable = NULL; \ + napi_value NODE_API_MODULE_INITIALIZER_IMPL(napi_env env, \ + napi_value exports); \ + napi_value NAPI_MODULE_INITIALIZER(napi_env env, napi_value exports) { \ + if (env && env->sentinel == NODE_API_VT_SENTINEL) { \ + g_node_api_module_vtable = env->module_vtable; \ + } \ + return NODE_API_MODULE_INITIALIZER_IMPL(env, exports); \ + } +// NOLINTEND (readability/null_usage) + +#else // NODE_API_MODULE_USE_VTABLE_IMPL +#define NODE_API_MODULE_INITIALIZER_IMPL_EX +#define NODE_API_MODULE_INITIALIZER_IMPL NAPI_MODULE_INITIALIZER +#endif // NODE_API_MODULE_USE_VTABLE_IMPL + #define NAPI_MODULE_INIT() \ EXTERN_C_START \ NAPI_MODULE_EXPORT int32_t NODE_API_MODULE_GET_API_VERSION(void) { \ @@ -73,7 +92,8 @@ typedef struct napi_module { NAPI_MODULE_EXPORT napi_value NAPI_MODULE_INITIALIZER(napi_env env, \ napi_value exports); \ EXTERN_C_END \ - napi_value NAPI_MODULE_INITIALIZER(napi_env env, napi_value exports) + NODE_API_MODULE_INITIALIZER_IMPL_EX \ + napi_value NODE_API_MODULE_INITIALIZER_IMPL(napi_env env, napi_value exports) #define NAPI_MODULE(modname, regfunc) \ NAPI_MODULE_INIT() { return regfunc(env, exports); } @@ -84,49 +104,110 @@ typedef struct napi_module { EXTERN_C_START +#ifdef NODE_API_MODULE_USE_VTABLE_IMPL + +extern const node_api_module_vtable* g_node_api_module_vtable; + +#ifndef NODE_API_MODULE_NO_VTABLE_FALLBACK +extern node_api_module_vtable g_node_api_module_vtable_fallback; +#endif // NODE_API_MODULE_NO_VTABLE_FALLBACK + +#define NODE_API_GLOBAL_MODULE_VTABLE_IMPL(func_name, method_name, ...) \ + { \ + NODE_API_VTABLE_IMPL_FALLBACK( \ + , module_vtable, func_name, method_name, __VA_ARGS__); \ + } + +#define NODE_API_MODULE_VTABLE_IMPL(func_name, method_name, obj, ...) \ + NODE_API_VTABLE_IMPL_BASE( \ + module_vtable, func_name, method_name, obj, obj, __VA_ARGS__) + +#define NODE_API_MODULE_VTABLE_IMPL_NOARGS(func_name, method_name, obj) \ + NODE_API_VTABLE_IMPL_BASE(module_vtable, func_name, method_name, obj, obj) + +#else // NODE_API_MODULE_USE_VTABLE_IMPL + +#define NODE_API_GLOBAL_MODULE_VTABLE_IMPL(...) +#define NODE_API_MODULE_VTABLE_IMPL(...) +#define NODE_API_MODULE_VTABLE_IMPL_NOARGS(...) + +#endif // NODE_API_MODULE_USE_VTABLE_IMPL + // Deprecated. Replaced by symbol-based registration defined by NAPI_MODULE // and NAPI_MODULE_INIT macros. -NAPI_EXTERN void NAPI_CDECL -napi_module_register(napi_module* mod); - -NAPI_EXTERN NAPI_NO_RETURN void NAPI_CDECL -napi_fatal_error(const char* location, - size_t location_len, - const char* message, - size_t message_len); +NAPI_EXTERN void NAPI_CDECL napi_module_register(napi_module* mod) + NODE_API_GLOBAL_MODULE_VTABLE_IMPL(napi_module_register, + module_register, + mod); + +NAPI_EXTERN void NAPI_NO_RETURN NAPI_CDECL napi_fatal_error( + const char* location, + size_t location_len, + const char* message, + size_t message_len) NODE_API_GLOBAL_MODULE_VTABLE_IMPL(napi_fatal_error, + fatal_error, + location, + location_len, + message, + message_len); // Methods for custom handling of async operations -NAPI_EXTERN napi_status NAPI_CDECL -napi_async_init(napi_env env, - napi_value async_resource, - napi_value async_resource_name, - napi_async_context* result); +NAPI_EXTERN napi_status NAPI_CDECL napi_async_init( + napi_env env, + napi_value async_resource, + napi_value async_resource_name, + napi_async_context* result) NODE_API_MODULE_VTABLE_IMPL(napi_async_init, + async_init, + env, + async_resource, + async_resource_name, + result); NAPI_EXTERN napi_status NAPI_CDECL -napi_async_destroy(napi_env env, napi_async_context async_context); +napi_async_destroy(napi_env env, napi_async_context async_context) + NODE_API_MODULE_VTABLE_IMPL(napi_async_destroy, + async_destroy, + env, + async_context); + +NAPI_EXTERN napi_status NAPI_CDECL napi_make_callback( + napi_env env, + napi_async_context async_context, + napi_value recv, + napi_value func, + size_t argc, + const napi_value* argv, + napi_value* result) NODE_API_MODULE_VTABLE_IMPL(napi_make_callback, + make_callback, + env, + async_context, + recv, + func, + argc, + argv, + result); +// Methods to provide node::Buffer functionality with napi types NAPI_EXTERN napi_status NAPI_CDECL -napi_make_callback(napi_env env, - napi_async_context async_context, - napi_value recv, - napi_value func, - size_t argc, - const napi_value* argv, - napi_value* result); +napi_create_buffer(napi_env env, size_t length, void** data, napi_value* result) + NODE_API_MODULE_VTABLE_IMPL( + napi_create_buffer, create_buffer, env, length, data, result); -// Methods to provide node::Buffer functionality with napi types -NAPI_EXTERN napi_status NAPI_CDECL napi_create_buffer(napi_env env, - size_t length, - void** data, - napi_value* result); #ifndef NODE_API_NO_EXTERNAL_BUFFERS_ALLOWED -NAPI_EXTERN napi_status NAPI_CDECL -napi_create_external_buffer(napi_env env, - size_t length, - void* data, - node_api_basic_finalize finalize_cb, - void* finalize_hint, - napi_value* result); +NAPI_EXTERN napi_status NAPI_CDECL napi_create_external_buffer( + napi_env env, + size_t length, + void* data, + node_api_basic_finalize finalize_cb, + void* finalize_hint, + napi_value* result) NODE_API_MODULE_VTABLE_IMPL(napi_create_external_buffer, + create_external_buffer, + env, + length, + data, + finalize_cb, + finalize_hint, + result); #endif // NODE_API_NO_EXTERNAL_BUFFERS_ALLOWED #if NAPI_VERSION >= 10 @@ -136,69 +217,137 @@ node_api_create_buffer_from_arraybuffer(napi_env env, napi_value arraybuffer, size_t byte_offset, size_t byte_length, - napi_value* result); + napi_value* result) + NODE_API_MODULE_VTABLE_IMPL(node_api_create_buffer_from_arraybuffer, + create_buffer_from_arraybuffer, + env, + arraybuffer, + byte_offset, + byte_length, + result); #endif // NAPI_VERSION >= 10 NAPI_EXTERN napi_status NAPI_CDECL napi_create_buffer_copy(napi_env env, size_t length, const void* data, void** result_data, - napi_value* result); + napi_value* result) + NODE_API_MODULE_VTABLE_IMPL(napi_create_buffer_copy, + create_buffer_copy, + env, + length, + data, + result_data, + result); + NAPI_EXTERN napi_status NAPI_CDECL napi_is_buffer(napi_env env, napi_value value, - bool* result); + bool* result) + NODE_API_MODULE_VTABLE_IMPL(napi_is_buffer, is_buffer, env, value, result); + NAPI_EXTERN napi_status NAPI_CDECL napi_get_buffer_info(napi_env env, napi_value value, void** data, - size_t* length); + size_t* length) + NODE_API_MODULE_VTABLE_IMPL( + napi_get_buffer_info, get_buffer_info, env, value, data, length); // Methods to manage simple async operations -NAPI_EXTERN napi_status NAPI_CDECL -napi_create_async_work(napi_env env, - napi_value async_resource, - napi_value async_resource_name, - napi_async_execute_callback execute, - napi_async_complete_callback complete, - void* data, - napi_async_work* result); +NAPI_EXTERN napi_status NAPI_CDECL napi_create_async_work( + napi_env env, + napi_value async_resource, + napi_value async_resource_name, + napi_async_execute_callback execute, + napi_async_complete_callback complete, + void* data, + napi_async_work* result) NODE_API_MODULE_VTABLE_IMPL(napi_create_async_work, + create_async_work, + env, + async_resource, + async_resource_name, + execute, + complete, + data, + result); + NAPI_EXTERN napi_status NAPI_CDECL napi_delete_async_work(napi_env env, - napi_async_work work); + napi_async_work work) + NODE_API_MODULE_VTABLE_IMPL(napi_delete_async_work, + delete_async_work, + env, + work); + NAPI_EXTERN napi_status NAPI_CDECL napi_queue_async_work(node_api_basic_env env, - napi_async_work work); + napi_async_work work) + NODE_API_MODULE_VTABLE_IMPL(napi_queue_async_work, + queue_async_work, + env, + work); + NAPI_EXTERN napi_status NAPI_CDECL -napi_cancel_async_work(node_api_basic_env env, napi_async_work work); +napi_cancel_async_work(node_api_basic_env env, napi_async_work work) + NODE_API_MODULE_VTABLE_IMPL(napi_cancel_async_work, + cancel_async_work, + env, + work); // version management -NAPI_EXTERN napi_status NAPI_CDECL napi_get_node_version( - node_api_basic_env env, const napi_node_version** version); +NAPI_EXTERN napi_status NAPI_CDECL +napi_get_node_version(node_api_basic_env env, const napi_node_version** version) + NODE_API_MODULE_VTABLE_IMPL(napi_get_node_version, + get_node_version, + env, + version); #if NAPI_VERSION >= 2 // Return the current libuv event loop for a given environment NAPI_EXTERN napi_status NAPI_CDECL -napi_get_uv_event_loop(node_api_basic_env env, struct uv_loop_s** loop); +napi_get_uv_event_loop(node_api_basic_env env, struct uv_loop_s** loop) + NODE_API_MODULE_VTABLE_IMPL(napi_get_uv_event_loop, + get_uv_event_loop, + env, + loop); #endif // NAPI_VERSION >= 2 #if NAPI_VERSION >= 3 NAPI_EXTERN napi_status NAPI_CDECL napi_fatal_exception(napi_env env, - napi_value err); + napi_value err) + NODE_API_MODULE_VTABLE_IMPL(napi_fatal_exception, + fatal_exception, + env, + err); NAPI_EXTERN napi_status NAPI_CDECL napi_add_env_cleanup_hook( - node_api_basic_env env, napi_cleanup_hook fun, void* arg); + node_api_basic_env env, napi_cleanup_hook fun, void* arg) + NODE_API_MODULE_VTABLE_IMPL( + napi_add_env_cleanup_hook, add_env_cleanup_hook, env, fun, arg); NAPI_EXTERN napi_status NAPI_CDECL napi_remove_env_cleanup_hook( - node_api_basic_env env, napi_cleanup_hook fun, void* arg); + node_api_basic_env env, napi_cleanup_hook fun, void* arg) + NODE_API_MODULE_VTABLE_IMPL( + napi_remove_env_cleanup_hook, remove_env_cleanup_hook, env, fun, arg); NAPI_EXTERN napi_status NAPI_CDECL napi_open_callback_scope(napi_env env, napi_value resource_object, napi_async_context context, - napi_callback_scope* result); + napi_callback_scope* result) + NODE_API_MODULE_VTABLE_IMPL(napi_open_callback_scope, + open_callback_scope, + env, + resource_object, + context, + result); NAPI_EXTERN napi_status NAPI_CDECL -napi_close_callback_scope(napi_env env, napi_callback_scope scope); +napi_close_callback_scope(napi_env env, napi_callback_scope scope) + NODE_API_MODULE_VTABLE_IMPL(napi_close_callback_scope, + close_callback_scope, + env, + scope); #endif // NAPI_VERSION >= 3 @@ -216,27 +365,64 @@ napi_create_threadsafe_function(napi_env env, napi_finalize thread_finalize_cb, void* context, napi_threadsafe_function_call_js call_js_cb, - napi_threadsafe_function* result); + napi_threadsafe_function* result) + NODE_API_MODULE_VTABLE_IMPL(napi_create_threadsafe_function, + create_threadsafe_function, + env, + func, + async_resource, + async_resource_name, + max_queue_size, + initial_thread_count, + thread_finalize_data, + thread_finalize_cb, + context, + call_js_cb, + result); NAPI_EXTERN napi_status NAPI_CDECL napi_get_threadsafe_function_context( - napi_threadsafe_function func, void** result); + napi_threadsafe_function func, void** result) + NODE_API_MODULE_VTABLE_IMPL(napi_get_threadsafe_function_context, + get_threadsafe_function_context, + func, + result); NAPI_EXTERN napi_status NAPI_CDECL napi_call_threadsafe_function(napi_threadsafe_function func, void* data, - napi_threadsafe_function_call_mode is_blocking); + napi_threadsafe_function_call_mode is_blocking) + NODE_API_MODULE_VTABLE_IMPL(napi_call_threadsafe_function, + call_threadsafe_function, + func, + data, + is_blocking); NAPI_EXTERN napi_status NAPI_CDECL -napi_acquire_threadsafe_function(napi_threadsafe_function func); +napi_acquire_threadsafe_function(napi_threadsafe_function func) + NODE_API_MODULE_VTABLE_IMPL_NOARGS(napi_acquire_threadsafe_function, + acquire_threadsafe_function, + func); NAPI_EXTERN napi_status NAPI_CDECL napi_release_threadsafe_function( - napi_threadsafe_function func, napi_threadsafe_function_release_mode mode); + napi_threadsafe_function func, napi_threadsafe_function_release_mode mode) + NODE_API_MODULE_VTABLE_IMPL(napi_release_threadsafe_function, + release_threadsafe_function, + func, + mode); NAPI_EXTERN napi_status NAPI_CDECL napi_unref_threadsafe_function( - node_api_basic_env env, napi_threadsafe_function func); + node_api_basic_env env, napi_threadsafe_function func) + NODE_API_MODULE_VTABLE_IMPL(napi_unref_threadsafe_function, + unref_threadsafe_function, + env, + func); NAPI_EXTERN napi_status NAPI_CDECL napi_ref_threadsafe_function( - node_api_basic_env env, napi_threadsafe_function func); + node_api_basic_env env, napi_threadsafe_function func) + NODE_API_MODULE_VTABLE_IMPL(napi_ref_threadsafe_function, + ref_threadsafe_function, + env, + func); #endif // NAPI_VERSION >= 4 @@ -246,17 +432,30 @@ NAPI_EXTERN napi_status NAPI_CDECL napi_add_async_cleanup_hook(node_api_basic_env env, napi_async_cleanup_hook hook, void* arg, - napi_async_cleanup_hook_handle* remove_handle); + napi_async_cleanup_hook_handle* remove_handle) + NODE_API_MODULE_VTABLE_IMPL(napi_add_async_cleanup_hook, + add_async_cleanup_hook, + env, + hook, + arg, + remove_handle); NAPI_EXTERN napi_status NAPI_CDECL -napi_remove_async_cleanup_hook(napi_async_cleanup_hook_handle remove_handle); +napi_remove_async_cleanup_hook(napi_async_cleanup_hook_handle remove_handle) + NODE_API_MODULE_VTABLE_IMPL_NOARGS(napi_remove_async_cleanup_hook, + remove_async_cleanup_hook, + remove_handle); #endif // NAPI_VERSION >= 8 #if NAPI_VERSION >= 9 NAPI_EXTERN napi_status NAPI_CDECL -node_api_get_module_file_name(node_api_basic_env env, const char** result); +node_api_get_module_file_name(node_api_basic_env env, const char** result) + NODE_API_MODULE_VTABLE_IMPL(node_api_get_module_file_name, + get_module_file_name, + env, + result); #endif // NAPI_VERSION >= 9 diff --git a/src/node_api_internals.h b/src/node_api_internals.h index 43d28211ddb3d4..070522ccf0ab68 100644 --- a/src/node_api_internals.h +++ b/src/node_api_internals.h @@ -10,14 +10,16 @@ #include "node_api.h" #include "util-inl.h" -struct node_napi_env__ : public napi_env__ { - static napi_env New(v8::Local context, - const std::string& module_filename, - int32_t module_api_version); +namespace v8impl { - node_napi_env__(v8::Local context, - const std::string& module_filename, - int32_t module_api_version); +struct NodeApiEnv : public NodeApiBaseEnv { + static NodeApiBaseEnv* New(v8::Local context, + const std::string& module_filename, + int32_t module_api_version); + + NodeApiEnv(v8::Local context, + const std::string& module_filename, + int32_t module_api_version); bool can_call_into_js() const override; void CallFinalizer(napi_finalize cb, void* data, void* hint) override; @@ -43,6 +45,6 @@ struct node_napi_env__ : public napi_env__ { bool finalization_scheduled = false; }; -using node_napi_env = node_napi_env__*; +} // end of namespace v8impl #endif // SRC_NODE_API_INTERNALS_H_ diff --git a/src/node_api_types.h b/src/node_api_types.h index 79123f0423d6dd..dd650e8a12e556 100644 --- a/src/node_api_types.h +++ b/src/node_api_types.h @@ -3,6 +3,8 @@ #include "js_native_api_types.h" +struct uv_loop_s; // Forward declaration. + typedef napi_value(NAPI_CDECL* napi_addon_register_func)(napi_env env, napi_value exports); // False positive: https://github.com/cpplint/cpplint/issues/409 @@ -55,4 +57,206 @@ typedef void(NAPI_CDECL* napi_async_cleanup_hook)( napi_async_cleanup_hook_handle handle, void* data); #endif // NAPI_VERSION >= 8 +// Used by deprecated registration method napi_module_register. +typedef struct napi_module { + int nm_version; + unsigned int nm_flags; + const char* nm_filename; + napi_addon_register_func nm_register_func; + const char* nm_modname; + void* nm_priv; + void* reserved[4]; +} napi_module; + +#if defined(NODE_API_MODULE_USE_VTABLE) || defined(NODE_API_RUNTIME_USE_VTABLE) + +// Vtable for Node.js module-specific functions +// New functions must be added at the end to maintain backward compatibility. +typedef struct node_api_module_vtable { + void(NAPI_CDECL* module_register)(napi_module* mod); + + void(NAPI_CDECL* fatal_error)(const char* location, + size_t location_len, + const char* message, + size_t message_len); + + napi_status(NAPI_CDECL* async_init)(napi_env env, + napi_value async_resource, + napi_value async_resource_name, + napi_async_context* result); + + napi_status(NAPI_CDECL* async_destroy)(napi_env env, + napi_async_context async_context); + + napi_status(NAPI_CDECL* make_callback)(napi_env env, + napi_async_context async_context, + napi_value recv, + napi_value func, + size_t argc, + const napi_value* argv, + napi_value* result); + + napi_status(NAPI_CDECL* create_buffer)(napi_env env, + size_t length, + void** data, + napi_value* result); + napi_status(NAPI_CDECL* create_external_buffer)( + napi_env env, + size_t length, + void* data, + node_api_basic_finalize finalize_cb, + void* finalize_hint, + napi_value* result); + + napi_status(NAPI_CDECL* create_buffer_copy)(napi_env env, + size_t length, + const void* data, + void** result_data, + napi_value* result); + napi_status(NAPI_CDECL* is_buffer)(napi_env env, + napi_value value, + bool* result); + napi_status(NAPI_CDECL* get_buffer_info)(napi_env env, + napi_value value, + void** data, + size_t* length); + + napi_status(NAPI_CDECL* create_async_work)( + napi_env env, + napi_value async_resource, + napi_value async_resource_name, + napi_async_execute_callback execute, + napi_async_complete_callback complete, + void* data, + napi_async_work* result); + napi_status(NAPI_CDECL* delete_async_work)(napi_env env, + napi_async_work work); + napi_status(NAPI_CDECL* queue_async_work)(node_api_basic_env env, + napi_async_work work); + napi_status(NAPI_CDECL* cancel_async_work)(node_api_basic_env env, + napi_async_work work); + + napi_status(NAPI_CDECL* get_node_version)(node_api_basic_env env, + const napi_node_version** version); + +#if NAPI_VERSION >= 2 + + napi_status(NAPI_CDECL* get_uv_event_loop)(node_api_basic_env env, + struct uv_loop_s** loop); + +#endif // NAPI_VERSION >= 2 + +#if NAPI_VERSION >= 3 + + napi_status(NAPI_CDECL* fatal_exception)(napi_env env, napi_value err); + + napi_status(NAPI_CDECL* add_env_cleanup_hook)(node_api_basic_env env, + napi_cleanup_hook fun, + void* arg); + + napi_status(NAPI_CDECL* remove_env_cleanup_hook)(node_api_basic_env env, + napi_cleanup_hook fun, + void* arg); + + napi_status(NAPI_CDECL* open_callback_scope)(napi_env env, + napi_value resource_object, + napi_async_context context, + napi_callback_scope* result); + + napi_status(NAPI_CDECL* close_callback_scope)(napi_env env, + napi_callback_scope scope); + +#endif // NAPI_VERSION >= 3 + +#if NAPI_VERSION >= 4 + + napi_status(NAPI_CDECL* create_threadsafe_function)( + napi_env env, + napi_value func, + napi_value async_resource, + napi_value async_resource_name, + size_t max_queue_size, + size_t initial_thread_count, + void* thread_finalize_data, + napi_finalize thread_finalize_cb, + void* context, + napi_threadsafe_function_call_js call_js_cb, + napi_threadsafe_function* result); + + napi_status(NAPI_CDECL* get_threadsafe_function_context)( + napi_threadsafe_function func, void** result); + + napi_status(NAPI_CDECL* call_threadsafe_function)( + napi_threadsafe_function func, + void* data, + napi_threadsafe_function_call_mode is_blocking); + + napi_status(NAPI_CDECL* acquire_threadsafe_function)( + napi_threadsafe_function func); + + napi_status(NAPI_CDECL* release_threadsafe_function)( + napi_threadsafe_function func, + napi_threadsafe_function_release_mode mode); + + napi_status(NAPI_CDECL* unref_threadsafe_function)( + node_api_basic_env env, napi_threadsafe_function func); + + napi_status(NAPI_CDECL* ref_threadsafe_function)( + node_api_basic_env env, napi_threadsafe_function func); + +#endif // NAPI_VERSION >= 4 + +#if NAPI_VERSION >= 8 + + napi_status(NAPI_CDECL* add_async_cleanup_hook)( + node_api_basic_env env, + napi_async_cleanup_hook hook, + void* arg, + napi_async_cleanup_hook_handle* remove_handle); + + napi_status(NAPI_CDECL* remove_async_cleanup_hook)( + napi_async_cleanup_hook_handle remove_handle); + +#endif // NAPI_VERSION >= 8 + +#if NAPI_VERSION >= 9 + + napi_status(NAPI_CDECL* get_module_file_name)(node_api_basic_env env, + const char** result); + +#endif // NAPI_VERSION >= 9 + +#if NAPI_VERSION >= 10 + + napi_status(NAPI_CDECL* create_buffer_from_arraybuffer)( + napi_env env, + napi_value arraybuffer, + size_t byte_offset, + size_t byte_length, + napi_value* result); + +#endif // NAPI_VERSION >= 10 +} node_api_module_vtable; + +#if NAPI_VERSION >= 4 + +struct napi_threadsafe_function__ { + uint64_t sentinel; // Should be NODE_API_VT_SENTINEL + const struct node_api_module_vtable* module_vtable; +}; + +#endif // NAPI_VERSION >= 4 + +#if NAPI_VERSION >= 8 + +struct napi_async_cleanup_hook_handle__ { + uint64_t sentinel; // Should be NODE_API_VT_SENTINEL + const struct node_api_module_vtable* module_vtable; +}; + +#endif // NAPI_VERSION >= 8 + +#endif // defined(NODE_API_MODULE_USE_VTABLE) || + // defined(NODE_API_RUNTIME_USE_VTABLE) + #endif // SRC_NODE_API_TYPES_H_ diff --git a/test/cctest/test_node_api.cc b/test/cctest/test_node_api.cc index 902776c157e9ed..893c50f728da9d 100644 --- a/test/cctest/test_node_api.cc +++ b/test/cctest/test_node_api.cc @@ -37,6 +37,7 @@ TEST_F(NodeApiTest, CreateNodeApiEnv) { napi_module_register_by_symbol( exports_obj, module_obj, env->context(), init, NAPI_VERSION); ASSERT_NE(addon_env, nullptr); - node_napi_env internal_env = reinterpret_cast(addon_env); + v8impl::NodeApiEnv* internal_env = + static_cast(addon_env); EXPECT_EQ(internal_env->node_env(), env); } diff --git a/test/js-native-api/test_vtable/binding.gyp b/test/js-native-api/test_vtable/binding.gyp new file mode 100644 index 00000000000000..8cf7d2c8b8edf5 --- /dev/null +++ b/test/js-native-api/test_vtable/binding.gyp @@ -0,0 +1,9 @@ +{ + "targets": [ + { + "target_name": "binding", + "defines": [ "NAPI_VERSION=10", "NODE_API_MODULE_USE_VTABLE" ], + "sources": [ "test_vtable.c" ] + } + ] +} diff --git a/test/js-native-api/test_vtable/test.js b/test/js-native-api/test_vtable/test.js new file mode 100644 index 00000000000000..48ab2084cdd577 --- /dev/null +++ b/test/js-native-api/test_vtable/test.js @@ -0,0 +1,14 @@ +'use strict'; +// Showcase: a js-native-api addon built with NODE_API_MODULE_USE_VTABLE that +// exercises the JS v-table (string and number interop). +const common = require('../../common'); +const assert = require('assert'); + +const binding = require(`./build/${common.buildType}/binding`); + +// napi_create_string_utf8 through the v-table. +assert.strictEqual(binding.hello(), 'world'); + +// napi_get_value_double + napi_create_double round-trip through the v-table. +assert.strictEqual(binding.double(21), 42); +assert.strictEqual(binding.double(-1.5), -3); diff --git a/test/js-native-api/test_vtable/test_vtable.c b/test/js-native-api/test_vtable/test_vtable.c new file mode 100644 index 00000000000000..2d5152cbba1906 --- /dev/null +++ b/test/js-native-api/test_vtable/test_vtable.c @@ -0,0 +1,49 @@ +#include +#include "../common.h" +#include "../entry_point.h" + +// Showcase for the Node-API JS v-table. +// +// This is an ordinary js-native-api addon. The `NODE_API_MODULE_USE_VTABLE` +// define in binding.gyp turns every `napi_*` call below into a thin wrapper +// that dispatches through the `js_vtable` the runtime injected into +// `napi_env`, instead of binding to runtime-exported symbols. The source is +// unchanged from a classic addon. +// +// The functions exercised here (napi_create_string_utf8, napi_get_cb_info, +// napi_get_value_double, napi_create_double, napi_define_properties) all live +// in the JS v-table. + +static napi_value Hello(napi_env env, napi_callback_info info) { + napi_value result; + NODE_API_CALL( + env, napi_create_string_utf8(env, "world", NAPI_AUTO_LENGTH, &result)); + return result; +} + +// Round-trips a number through the v-table: returns its argument doubled. +static napi_value Double(napi_env env, napi_callback_info info) { + size_t argc = 1; + napi_value argv[1]; + NODE_API_CALL(env, napi_get_cb_info(env, info, &argc, argv, NULL, NULL)); + + double value; + NODE_API_CALL(env, napi_get_value_double(env, argv[0], &value)); + + napi_value result; + NODE_API_CALL(env, napi_create_double(env, value * 2, &result)); + return result; +} + +EXTERN_C_START +napi_value Init(napi_env env, napi_value exports) { + napi_property_descriptor props[] = { + DECLARE_NODE_API_PROPERTY("hello", Hello), + DECLARE_NODE_API_PROPERTY("double", Double), + }; + NODE_API_CALL(env, + napi_define_properties( + env, exports, sizeof(props) / sizeof(*props), props)); + return exports; +} +EXTERN_C_END diff --git a/test/node-api/test_vtable/binding.c b/test/node-api/test_vtable/binding.c new file mode 100644 index 00000000000000..9d4b488bd4fb97 --- /dev/null +++ b/test/node-api/test_vtable/binding.c @@ -0,0 +1,69 @@ +#include +#include +#include "../../js-native-api/common.h" + +// Showcase for the Node-API module v-table. +// +// This is an ordinary Node-API addon. The only thing that makes it use the +// v-table is the `NODE_API_MODULE_USE_VTABLE` define in binding.gyp: with it, +// every `napi_*` call below is a thin wrapper that dispatches through the +// `module_vtable`/`js_vtable` the runtime injected into `napi_env`, instead of +// binding to runtime-exported symbols. The source itself is unchanged from a +// classic addon, which is the whole point of the feature. +// +// The functions exercised here (napi_create_buffer, napi_create_buffer_copy, +// napi_is_buffer, napi_get_buffer_info) live in the module v-table. + +static const char kData[] = "vtable-buffer"; + +// Returns a fresh Buffer initialized with kData. +static napi_value CreateBuffer(napi_env env, napi_callback_info info) { + void* data = NULL; + napi_value result; + NODE_API_CALL(env, napi_create_buffer(env, sizeof(kData), &data, &result)); + memcpy(data, kData, sizeof(kData)); + return result; +} + +// Returns a Buffer copied from kData. +static napi_value CopyBuffer(napi_env env, napi_callback_info info) { + void* data = NULL; + napi_value result; + NODE_API_CALL( + env, napi_create_buffer_copy(env, sizeof(kData), kData, &data, &result)); + return result; +} + +// Returns true when the argument is a Buffer whose contents match kData. +static napi_value CheckBuffer(napi_env env, napi_callback_info info) { + size_t argc = 1; + napi_value argv[1]; + NODE_API_CALL(env, napi_get_cb_info(env, info, &argc, argv, NULL, NULL)); + + bool is_buffer = false; + NODE_API_CALL(env, napi_is_buffer(env, argv[0], &is_buffer)); + + bool matches = false; + if (is_buffer) { + void* data = NULL; + size_t length = 0; + NODE_API_CALL(env, napi_get_buffer_info(env, argv[0], &data, &length)); + matches = length == sizeof(kData) && memcmp(data, kData, length) == 0; + } + + napi_value result; + NODE_API_CALL(env, napi_get_boolean(env, is_buffer && matches, &result)); + return result; +} + +NAPI_MODULE_INIT() { + napi_property_descriptor props[] = { + DECLARE_NODE_API_PROPERTY("createBuffer", CreateBuffer), + DECLARE_NODE_API_PROPERTY("copyBuffer", CopyBuffer), + DECLARE_NODE_API_PROPERTY("checkBuffer", CheckBuffer), + }; + NODE_API_CALL(env, + napi_define_properties( + env, exports, sizeof(props) / sizeof(*props), props)); + return exports; +} diff --git a/test/node-api/test_vtable/binding.gyp b/test/node-api/test_vtable/binding.gyp new file mode 100644 index 00000000000000..825bc37deaa61f --- /dev/null +++ b/test/node-api/test_vtable/binding.gyp @@ -0,0 +1,9 @@ +{ + "targets": [ + { + "target_name": "binding", + "defines": [ "NODE_API_MODULE_USE_VTABLE" ], + "sources": [ "binding.c" ] + } + ] +} diff --git a/test/node-api/test_vtable/test.js b/test/node-api/test_vtable/test.js new file mode 100644 index 00000000000000..1be2bd68d295e9 --- /dev/null +++ b/test/node-api/test_vtable/test.js @@ -0,0 +1,21 @@ +'use strict'; +// Showcase: a node-api addon built with NODE_API_MODULE_USE_VTABLE that +// exercises the module v-table (Buffer APIs). +const common = require('../../common'); +const assert = require('assert'); + +const binding = require(`./build/${common.buildType}/binding`); + +// napi_create_buffer + napi_get_buffer_info round-trip through the v-table. +const buf = binding.createBuffer(); +assert(Buffer.isBuffer(buf)); +assert.strictEqual(binding.checkBuffer(buf), true); + +// napi_create_buffer_copy likewise. +const copy = binding.copyBuffer(); +assert(Buffer.isBuffer(copy)); +assert.strictEqual(binding.checkBuffer(copy), true); + +// napi_is_buffer distinguishes non-buffers and mismatched contents. +assert.strictEqual(binding.checkBuffer(Buffer.from('nope')), false); +assert.strictEqual(binding.checkBuffer({}), false);