Skip to content

Commit

Permalink
update API and add tests
Browse files Browse the repository at this point in the history
  • Loading branch information
vmoroz committed Dec 16, 2022
1 parent 2bf90d4 commit 09b349b
Show file tree
Hide file tree
Showing 18 changed files with 704 additions and 61 deletions.
2 changes: 1 addition & 1 deletion src/js_native_api_v8.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2496,7 +2496,7 @@ napi_status NAPI_CDECL napi_create_reference(napi_env env,
CHECK_ARG(env, result);

v8::Local<v8::Value> v8_value = v8impl::V8LocalValueFromJsValue(value);
if (env->node_api_version <= 8) {
if (env->module_api_version <= 8) {
if (!(v8_value->IsObject() || v8_value->IsFunction() ||
v8_value->IsSymbol())) {
return napi_set_last_error(env, napi_invalid_arg);
Expand Down
8 changes: 5 additions & 3 deletions src/js_native_api_v8.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,10 +51,12 @@ class RefTracker {

struct napi_env__ {
explicit napi_env__(v8::Local<v8::Context> context,
int32_t node_api_version)
int32_t module_api_version)
: isolate(context->GetIsolate()),
context_persistent(isolate, context),
node_api_version(node_api_version) {
module_api_version(module_api_version != 0
? module_api_version
: NAPI_DEFAULT_MODULE_API_VERSION) {
CHECK_EQ(isolate, context->GetIsolate());
napi_clear_last_error(this);
}
Expand Down Expand Up @@ -125,7 +127,7 @@ struct napi_env__ {
int open_callback_scopes = 0;
int refs = 1;
void* instance_data = nullptr;
int node_api_version = NAPI_DEFAULT_MODULE_API_VERSION;
int32_t module_api_version = NAPI_DEFAULT_MODULE_API_VERSION;

protected:
// Should not be deleted directly. Delete with `napi_env__::DeleteMe()`
Expand Down
29 changes: 12 additions & 17 deletions src/node_api.cc
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@

node_napi_env__::node_napi_env__(v8::Local<v8::Context> context,
const std::string& module_filename,
int32_t node_api_version)
: napi_env__(context, node_api_version), filename(module_filename) {
int32_t module_api_version)
: napi_env__(context, module_api_version), filename(module_filename) {
CHECK_NOT_NULL(node_env());
}

Expand Down Expand Up @@ -128,10 +128,10 @@ class BufferFinalizer : private Finalizer {

inline napi_env NewEnv(v8::Local<v8::Context> context,
const std::string& module_filename,
int32_t node_api_version) {
int32_t module_api_version) {
node_napi_env result;

result = new node_napi_env__(context, module_filename, node_api_version);
result = new node_napi_env__(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 N-API addons using this napi_env are in place,
Expand Down Expand Up @@ -600,15 +600,15 @@ static void napi_module_register_cb(v8::Local<v8::Object> exports,
module,
context,
static_cast<const napi_module*>(priv)->nm_register_func,
static_cast<const napi_module*>(priv)->nm_api_version_func);
static_cast<int32_t>(
static_cast<const napi_module*>(priv)->nm_api_version));
}

void napi_module_register_by_symbol(
v8::Local<v8::Object> exports,
v8::Local<v8::Value> module,
v8::Local<v8::Context> context,
napi_addon_register_func init,
napi_addon_api_version_func get_api_version) {
void napi_module_register_by_symbol(v8::Local<v8::Object> exports,
v8::Local<v8::Value> module,
v8::Local<v8::Context> context,
napi_addon_register_func init,
int32_t module_api_version) {
node::Environment* node_env = node::Environment::GetCurrent(context);
std::string module_filename = "";
if (init == nullptr) {
Expand All @@ -617,11 +617,6 @@ void napi_module_register_by_symbol(
return;
}

int32_t node_api_version = NAPI_DEFAULT_MODULE_API_VERSION;
if (get_api_version != nullptr) {
node_api_version = get_api_version();
}

// We set `env->filename` from `module.filename` here, but we could just as
// easily add a private property to `exports` in `process.dlopen`, which
// receives the file name from JS, and retrieve *that* here. Thus, we are not
Expand All @@ -641,7 +636,7 @@ void napi_module_register_by_symbol(
}

// Create a new napi_env for this specific module.
napi_env env = v8impl::NewEnv(context, module_filename, node_api_version);
napi_env env = v8impl::NewEnv(context, module_filename, module_api_version);

napi_value _exports = nullptr;
env->CallIntoModule([&](napi_env env) {
Expand Down
105 changes: 85 additions & 20 deletions src/node_api.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ struct uv_loop_s; // Forward declaration.
typedef napi_value(NAPI_CDECL* napi_addon_register_func)(napi_env env,
napi_value exports);

typedef int32_t(NAPI_CDECL* napi_addon_api_version_func)();
#ifndef NAPI_EXPERIMENTAL

typedef struct napi_module {
int nm_version;
Expand All @@ -40,10 +40,26 @@ typedef struct napi_module {
napi_addon_register_func nm_register_func;
const char* nm_modname;
void* nm_priv;
napi_addon_api_version_func nm_api_version_func;
void* reserved[4];
} napi_module;

#else

typedef int32_t(NAPI_CDECL* napi_addon_get_api_version_func)();

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;
uintptr_t nm_api_version;
void* reserved[3];
} napi_module;

#endif // NAPI_EXPERIMENTAL

#define NAPI_MODULE_VERSION 1

#if defined(_MSC_VER)
Expand Down Expand Up @@ -76,7 +92,57 @@ typedef struct napi_module {
static void fn(void)
#endif

#define NAPI_MODULE_XV(modname, regfunc, apiversionfunc, priv, flags) \
#ifndef NAPI_EXPERIMENTAL

#define NAPI_MODULE_X(modname, regfunc, priv, flags) \
EXTERN_C_START \
static napi_module _module = { \
NAPI_MODULE_VERSION, \
flags, \
__FILE__, \
regfunc, \
#modname, \
priv, \
{0}, \
}; \
NAPI_C_CTOR(_register_##modname) { napi_module_register(&_module); } \
EXTERN_C_END

#define NAPI_MODULE_INITIALIZER_X(base, version) \
NAPI_MODULE_INITIALIZER_X_HELPER(base, version)
#define NAPI_MODULE_INITIALIZER_X_HELPER(base, version) base##version

#ifdef __wasm32__
#define NAPI_WASM_INITIALIZER \
NAPI_MODULE_INITIALIZER_X(napi_register_wasm_v, NAPI_MODULE_VERSION)
#define NAPI_MODULE(modname, regfunc) \
EXTERN_C_START \
NAPI_MODULE_EXPORT napi_value NAPI_WASM_INITIALIZER(napi_env env, \
napi_value exports) { \
return regfunc(env, exports); \
} \
EXTERN_C_END
#else
#define NAPI_MODULE(modname, regfunc) \
NAPI_MODULE_X(modname, regfunc, NULL, 0) // NOLINT (readability/null_usage)
#endif

#define NAPI_MODULE_INITIALIZER_BASE napi_register_module_v

#define NAPI_MODULE_INITIALIZER \
NAPI_MODULE_INITIALIZER_X(NAPI_MODULE_INITIALIZER_BASE, NAPI_MODULE_VERSION)

#define NAPI_MODULE_INIT() \
EXTERN_C_START \
NAPI_MODULE_EXPORT napi_value NAPI_MODULE_INITIALIZER(napi_env env, \
napi_value exports); \
EXTERN_C_END \
NAPI_MODULE(NODE_GYP_MODULE_NAME, NAPI_MODULE_INITIALIZER) \
napi_value NAPI_MODULE_INITIALIZER(napi_env env, napi_value exports)

#else

#define NAPI_MODULE_XV(modname, regfunc, api_version, priv, flags) \
EXTERN_C_START \
static napi_module _module = { \
NAPI_MODULE_VERSION, \
Expand All @@ -85,64 +151,63 @@ typedef struct napi_module {
regfunc, \
#modname, \
priv, \
apiversionfunc, \
(uintptr_t)api_version, \
{0}, \
}; \
NAPI_C_CTOR(_register_##modname) { napi_module_register(&_module); } \
EXTERN_C_END

#define NAPI_MODULE_X(modname, regfunc, priv, flags) \
NAPI_MODULE_XV(modname, regfunc, NAPI_VERSION, priv, flags)

#define NAPI_CONCAT_HELPER(text1, text2) text1##text2
#define NAPI_CONCAT(text1, text2) NAPI_CONCAT_HELPER(text1, text2)

#define NAPI_MODULE_INITIALIZER_BASE napi_register_module_v
#define NAPI_MODULE_API_VERSION_BASE napi_module_api_version_v
#define NAPI_MODULE_GET_API_VERSION_BASE napi_module_get_api_version_v

#define NAPI_MODULE_INITIALIZER \
NAPI_CONCAT(NAPI_MODULE_INITIALIZER_BASE, NAPI_MODULE_VERSION)

#define NAPI_MODULE_API_VERSION \
NAPI_CONCAT(NAPI_MODULE_API_VERSION_BASE, NAPI_MODULE_VERSION)

#define NAPI_MODULE_X(modname, regfunc, priv, flags) \
EXTERN_C_START \
NAPI_MODULE_EXPORT int32_t NAPI_MODULE_API_VERSION() { \
return NAPI_VERSION; \
} \
EXTERN_C_END \
NAPI_MODULE_XV(modname, regfunc, NAPI_MODULE_API_VERSION, priv, flags)
#define NAPI_MODULE_GET_API_VERSION \
NAPI_CONCAT(NAPI_MODULE_GET_API_VERSION_BASE, NAPI_MODULE_VERSION)

#define NAPI_MODULE_INIT() \
EXTERN_C_START \
NAPI_MODULE_EXPORT napi_value NAPI_MODULE_INITIALIZER(napi_env env, \
napi_value exports); \
NAPI_MODULE_EXPORT int32_t NAPI_MODULE_API_VERSION() { \
NAPI_MODULE_EXPORT int32_t NAPI_MODULE_GET_API_VERSION() { \
return NAPI_VERSION; \
} \
EXTERN_C_END \
napi_value NAPI_MODULE_INITIALIZER(napi_env env, napi_value exports)

#ifdef __wasm32__

#define NAPI_WASM_INITIALIZER \
NAPI_CONCAT(napi_register_wasm_v, NAPI_MODULE_VERSION)
#define NAPI_WASM_API_VERSION \
NAPI_CONCAT(napi_wasm_api_version_v, NAPI_MODULE_VERSION)
#define NAPI_WASM_GET_API_VERSION \
NAPI_CONCAT(napi_wasm_get_api_version_v, NAPI_MODULE_VERSION)
#define NAPI_MODULE(modname, regfunc) \
EXTERN_C_START \
NAPI_MODULE_EXPORT napi_value NAPI_WASM_INITIALIZER(napi_env env, \
napi_value exports) { \
return regfunc(env, exports); \
} \
NAPI_MODULE_EXPORT int32_t NAPI_WASM_API_VERSION() { \
NAPI_MODULE_EXPORT int32_t NAPI_WASM_GET_API_VERSION() { \
return NAPI_VERSION; \
} \
EXTERN_C_END
#else

#define NAPI_MODULE(modname, regfunc) \
NAPI_MODULE_INIT() { \
return regfunc(env, exports); \
}

#endif
#endif // __wasm32__

#endif // NAPI_EXPERIMENTAL

EXTERN_C_START

Expand Down
2 changes: 1 addition & 1 deletion src/node_api_internals.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
struct node_napi_env__ : public napi_env__ {
node_napi_env__(v8::Local<v8::Context> context,
const std::string& module_filename,
int32_t node_api_version);
int32_t module_api_version);

bool can_call_into_js() const override;
v8::Maybe<bool> mark_arraybuffer_as_untransferable(
Expand Down
20 changes: 10 additions & 10 deletions src/node_binding.cc
Original file line number Diff line number Diff line change
Expand Up @@ -402,11 +402,10 @@ inline napi_addon_register_func GetNapiInitializerCallback(DLib* dlib) {
dlib->GetSymbolAddress(name));
}

inline napi_addon_api_version_func GetNapiAddonApiVersionCallback(DLib* dlib) {
const char* name =
STRINGIFY(NAPI_MODULE_API_VERSION_BASE) STRINGIFY(NAPI_MODULE_VERSION);
return reinterpret_cast<napi_addon_api_version_func>(
dlib->GetSymbolAddress(name));
inline napi_addon_get_api_version_func GetNapiAddonGetApiVersionCallback(
DLib* dlib) {
return reinterpret_cast<napi_addon_get_api_version_func>(
dlib->GetSymbolAddress(STRINGIFY(NAPI_MODULE_GET_API_VERSION)));
}

// DLOpen is process.dlopen(module, filename, flags).
Expand Down Expand Up @@ -485,11 +484,12 @@ void DLOpen(const FunctionCallbackInfo<Value>& args) {
callback(exports, module, context);
return true;
} else if (auto napi_callback = GetNapiInitializerCallback(dlib)) {
napi_module_register_by_symbol(exports,
module,
context,
napi_callback,
GetNapiAddonApiVersionCallback(dlib));
int32_t module_api_version = 0;
if (auto get_version = GetNapiAddonGetApiVersionCallback(dlib)) {
module_api_version = get_version();
}
napi_module_register_by_symbol(
exports, module, context, napi_callback, module_api_version);
return true;
} else {
mp = dlib->GetSavedModuleFromGlobalHandleMap();
Expand Down
13 changes: 6 additions & 7 deletions src/node_binding.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ enum {

// Make sure our internal values match the public API's values.
static_assert(static_cast<int>(NM_F_LINKED) ==
static_cast<int>(node::ModuleFlags::kLinked),
static_cast<int>(node::ModuleFlags::kLinked),
"NM_F_LINKED != node::ModuleFlags::kLinked");

#define NODE_BINDING_CONTEXT_AWARE_CPP(modname, regfunc, priv, flags) \
Expand All @@ -37,12 +37,11 @@ static_assert(static_cast<int>(NM_F_LINKED) ==
nullptr}; \
void _register_##modname() { node_module_register(&_module); }

void napi_module_register_by_symbol(
v8::Local<v8::Object> exports,
v8::Local<v8::Value> module,
v8::Local<v8::Context> context,
napi_addon_register_func init,
napi_addon_api_version_func get_api_version);
void napi_module_register_by_symbol(v8::Local<v8::Object> exports,
v8::Local<v8::Value> module,
v8::Local<v8::Context> context,
napi_addon_register_func init,
int32_t module_api_version);

namespace node {

Expand Down
2 changes: 1 addition & 1 deletion test/cctest/test_js_native_api_v8.cc
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ TEST_F(JsNativeApiV8Test, Reference) {
Local<Object> module_obj = Object::New(isolate_);
Local<Object> exports_obj = Object::New(isolate_);
napi_module_register_by_symbol(
exports_obj, module_obj, env->context(), init, nullptr);
exports_obj, module_obj, env->context(), init, 0);
ASSERT_NE(addon_env, nullptr);
node_napi_env internal_env = reinterpret_cast<node_napi_env>(addon_env);
EXPECT_EQ(internal_env->node_env(), env);
Expand Down
2 changes: 1 addition & 1 deletion test/cctest/test_node_api.cc
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ TEST_F(NodeApiTest, CreateNodeApiEnv) {
Local<Object> module_obj = Object::New(isolate_);
Local<Object> exports_obj = Object::New(isolate_);
napi_module_register_by_symbol(
exports_obj, module_obj, env->context(), init, nullptr);
exports_obj, module_obj, env->context(), init, 0);
ASSERT_NE(addon_env, nullptr);
node_napi_env internal_env = reinterpret_cast<node_napi_env>(addon_env);
EXPECT_EQ(internal_env->node_env(), env);
Expand Down
8 changes: 8 additions & 0 deletions test/node-api/test_null_init/binding.gyp
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
'targets': [
{
'target_name': 'test_null_init',
'sources': [ 'test_null_init.c' ]
}
]
}
7 changes: 7 additions & 0 deletions test/node-api/test_null_init/test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
'use strict';
const common = require('../../common');
const assert = require('assert');

assert.throws(
() => require(`./build/${common.buildType}/test_null_init`),
/Module has no declared entry point[.]/);
3 changes: 3 additions & 0 deletions test/node-api/test_null_init/test_null_init.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#include <node_api.h>

NAPI_MODULE(NODE_GYP_MODULE_NAME, NULL)
9 changes: 9 additions & 0 deletions test/node-api/test_reference_all_types/binding.gyp
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"targets": [
{
"target_name": "test_reference_all_types",
"sources": [ "test_reference_all_types.c" ],
"defines": [ 'NAPI_EXPERIMENTAL' ]
}
]
}

0 comments on commit 09b349b

Please sign in to comment.