Skip to content

Commit 09b349b

Browse files
committed
update API and add tests
1 parent 2bf90d4 commit 09b349b

18 files changed

+704
-61
lines changed

src/js_native_api_v8.cc

+1-1
Original file line numberDiff line numberDiff line change
@@ -2496,7 +2496,7 @@ napi_status NAPI_CDECL napi_create_reference(napi_env env,
24962496
CHECK_ARG(env, result);
24972497

24982498
v8::Local<v8::Value> v8_value = v8impl::V8LocalValueFromJsValue(value);
2499-
if (env->node_api_version <= 8) {
2499+
if (env->module_api_version <= 8) {
25002500
if (!(v8_value->IsObject() || v8_value->IsFunction() ||
25012501
v8_value->IsSymbol())) {
25022502
return napi_set_last_error(env, napi_invalid_arg);

src/js_native_api_v8.h

+5-3
Original file line numberDiff line numberDiff line change
@@ -51,10 +51,12 @@ class RefTracker {
5151

5252
struct napi_env__ {
5353
explicit napi_env__(v8::Local<v8::Context> context,
54-
int32_t node_api_version)
54+
int32_t module_api_version)
5555
: isolate(context->GetIsolate()),
5656
context_persistent(isolate, context),
57-
node_api_version(node_api_version) {
57+
module_api_version(module_api_version != 0
58+
? module_api_version
59+
: NAPI_DEFAULT_MODULE_API_VERSION) {
5860
CHECK_EQ(isolate, context->GetIsolate());
5961
napi_clear_last_error(this);
6062
}
@@ -125,7 +127,7 @@ struct napi_env__ {
125127
int open_callback_scopes = 0;
126128
int refs = 1;
127129
void* instance_data = nullptr;
128-
int node_api_version = NAPI_DEFAULT_MODULE_API_VERSION;
130+
int32_t module_api_version = NAPI_DEFAULT_MODULE_API_VERSION;
129131

130132
protected:
131133
// Should not be deleted directly. Delete with `napi_env__::DeleteMe()`

src/node_api.cc

+12-17
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,8 @@
2121

2222
node_napi_env__::node_napi_env__(v8::Local<v8::Context> context,
2323
const std::string& module_filename,
24-
int32_t node_api_version)
25-
: napi_env__(context, node_api_version), filename(module_filename) {
24+
int32_t module_api_version)
25+
: napi_env__(context, module_api_version), filename(module_filename) {
2626
CHECK_NOT_NULL(node_env());
2727
}
2828

@@ -128,10 +128,10 @@ class BufferFinalizer : private Finalizer {
128128

129129
inline napi_env NewEnv(v8::Local<v8::Context> context,
130130
const std::string& module_filename,
131-
int32_t node_api_version) {
131+
int32_t module_api_version) {
132132
node_napi_env result;
133133

134-
result = new node_napi_env__(context, module_filename, node_api_version);
134+
result = new node_napi_env__(context, module_filename, module_api_version);
135135
// TODO(addaleax): There was previously code that tried to delete the
136136
// napi_env when its v8::Context was garbage collected;
137137
// However, as long as N-API addons using this napi_env are in place,
@@ -600,15 +600,15 @@ static void napi_module_register_cb(v8::Local<v8::Object> exports,
600600
module,
601601
context,
602602
static_cast<const napi_module*>(priv)->nm_register_func,
603-
static_cast<const napi_module*>(priv)->nm_api_version_func);
603+
static_cast<int32_t>(
604+
static_cast<const napi_module*>(priv)->nm_api_version));
604605
}
605606

606-
void napi_module_register_by_symbol(
607-
v8::Local<v8::Object> exports,
608-
v8::Local<v8::Value> module,
609-
v8::Local<v8::Context> context,
610-
napi_addon_register_func init,
611-
napi_addon_api_version_func get_api_version) {
607+
void napi_module_register_by_symbol(v8::Local<v8::Object> exports,
608+
v8::Local<v8::Value> module,
609+
v8::Local<v8::Context> context,
610+
napi_addon_register_func init,
611+
int32_t module_api_version) {
612612
node::Environment* node_env = node::Environment::GetCurrent(context);
613613
std::string module_filename = "";
614614
if (init == nullptr) {
@@ -617,11 +617,6 @@ void napi_module_register_by_symbol(
617617
return;
618618
}
619619

620-
int32_t node_api_version = NAPI_DEFAULT_MODULE_API_VERSION;
621-
if (get_api_version != nullptr) {
622-
node_api_version = get_api_version();
623-
}
624-
625620
// We set `env->filename` from `module.filename` here, but we could just as
626621
// easily add a private property to `exports` in `process.dlopen`, which
627622
// receives the file name from JS, and retrieve *that* here. Thus, we are not
@@ -641,7 +636,7 @@ void napi_module_register_by_symbol(
641636
}
642637

643638
// Create a new napi_env for this specific module.
644-
napi_env env = v8impl::NewEnv(context, module_filename, node_api_version);
639+
napi_env env = v8impl::NewEnv(context, module_filename, module_api_version);
645640

646641
napi_value _exports = nullptr;
647642
env->CallIntoModule([&](napi_env env) {

src/node_api.h

+85-20
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ struct uv_loop_s; // Forward declaration.
3131
typedef napi_value(NAPI_CDECL* napi_addon_register_func)(napi_env env,
3232
napi_value exports);
3333

34-
typedef int32_t(NAPI_CDECL* napi_addon_api_version_func)();
34+
#ifndef NAPI_EXPERIMENTAL
3535

3636
typedef struct napi_module {
3737
int nm_version;
@@ -40,10 +40,26 @@ typedef struct napi_module {
4040
napi_addon_register_func nm_register_func;
4141
const char* nm_modname;
4242
void* nm_priv;
43-
napi_addon_api_version_func nm_api_version_func;
43+
void* reserved[4];
44+
} napi_module;
45+
46+
#else
47+
48+
typedef int32_t(NAPI_CDECL* napi_addon_get_api_version_func)();
49+
50+
typedef struct napi_module {
51+
int nm_version;
52+
unsigned int nm_flags;
53+
const char* nm_filename;
54+
napi_addon_register_func nm_register_func;
55+
const char* nm_modname;
56+
void* nm_priv;
57+
uintptr_t nm_api_version;
4458
void* reserved[3];
4559
} napi_module;
4660

61+
#endif // NAPI_EXPERIMENTAL
62+
4763
#define NAPI_MODULE_VERSION 1
4864

4965
#if defined(_MSC_VER)
@@ -76,7 +92,57 @@ typedef struct napi_module {
7692
static void fn(void)
7793
#endif
7894

79-
#define NAPI_MODULE_XV(modname, regfunc, apiversionfunc, priv, flags) \
95+
#ifndef NAPI_EXPERIMENTAL
96+
97+
#define NAPI_MODULE_X(modname, regfunc, priv, flags) \
98+
EXTERN_C_START \
99+
static napi_module _module = { \
100+
NAPI_MODULE_VERSION, \
101+
flags, \
102+
__FILE__, \
103+
regfunc, \
104+
#modname, \
105+
priv, \
106+
{0}, \
107+
}; \
108+
NAPI_C_CTOR(_register_##modname) { napi_module_register(&_module); } \
109+
EXTERN_C_END
110+
111+
#define NAPI_MODULE_INITIALIZER_X(base, version) \
112+
NAPI_MODULE_INITIALIZER_X_HELPER(base, version)
113+
#define NAPI_MODULE_INITIALIZER_X_HELPER(base, version) base##version
114+
115+
#ifdef __wasm32__
116+
#define NAPI_WASM_INITIALIZER \
117+
NAPI_MODULE_INITIALIZER_X(napi_register_wasm_v, NAPI_MODULE_VERSION)
118+
#define NAPI_MODULE(modname, regfunc) \
119+
EXTERN_C_START \
120+
NAPI_MODULE_EXPORT napi_value NAPI_WASM_INITIALIZER(napi_env env, \
121+
napi_value exports) { \
122+
return regfunc(env, exports); \
123+
} \
124+
EXTERN_C_END
125+
#else
126+
#define NAPI_MODULE(modname, regfunc) \
127+
NAPI_MODULE_X(modname, regfunc, NULL, 0) // NOLINT (readability/null_usage)
128+
#endif
129+
130+
#define NAPI_MODULE_INITIALIZER_BASE napi_register_module_v
131+
132+
#define NAPI_MODULE_INITIALIZER \
133+
NAPI_MODULE_INITIALIZER_X(NAPI_MODULE_INITIALIZER_BASE, NAPI_MODULE_VERSION)
134+
135+
#define NAPI_MODULE_INIT() \
136+
EXTERN_C_START \
137+
NAPI_MODULE_EXPORT napi_value NAPI_MODULE_INITIALIZER(napi_env env, \
138+
napi_value exports); \
139+
EXTERN_C_END \
140+
NAPI_MODULE(NODE_GYP_MODULE_NAME, NAPI_MODULE_INITIALIZER) \
141+
napi_value NAPI_MODULE_INITIALIZER(napi_env env, napi_value exports)
142+
143+
#else
144+
145+
#define NAPI_MODULE_XV(modname, regfunc, api_version, priv, flags) \
80146
EXTERN_C_START \
81147
static napi_module _module = { \
82148
NAPI_MODULE_VERSION, \
@@ -85,64 +151,63 @@ typedef struct napi_module {
85151
regfunc, \
86152
#modname, \
87153
priv, \
88-
apiversionfunc, \
154+
(uintptr_t)api_version, \
89155
{0}, \
90156
}; \
91157
NAPI_C_CTOR(_register_##modname) { napi_module_register(&_module); } \
92158
EXTERN_C_END
93159

160+
#define NAPI_MODULE_X(modname, regfunc, priv, flags) \
161+
NAPI_MODULE_XV(modname, regfunc, NAPI_VERSION, priv, flags)
162+
94163
#define NAPI_CONCAT_HELPER(text1, text2) text1##text2
95164
#define NAPI_CONCAT(text1, text2) NAPI_CONCAT_HELPER(text1, text2)
96165

97166
#define NAPI_MODULE_INITIALIZER_BASE napi_register_module_v
98-
#define NAPI_MODULE_API_VERSION_BASE napi_module_api_version_v
167+
#define NAPI_MODULE_GET_API_VERSION_BASE napi_module_get_api_version_v
99168

100169
#define NAPI_MODULE_INITIALIZER \
101170
NAPI_CONCAT(NAPI_MODULE_INITIALIZER_BASE, NAPI_MODULE_VERSION)
102171

103-
#define NAPI_MODULE_API_VERSION \
104-
NAPI_CONCAT(NAPI_MODULE_API_VERSION_BASE, NAPI_MODULE_VERSION)
105-
106-
#define NAPI_MODULE_X(modname, regfunc, priv, flags) \
107-
EXTERN_C_START \
108-
NAPI_MODULE_EXPORT int32_t NAPI_MODULE_API_VERSION() { \
109-
return NAPI_VERSION; \
110-
} \
111-
EXTERN_C_END \
112-
NAPI_MODULE_XV(modname, regfunc, NAPI_MODULE_API_VERSION, priv, flags)
172+
#define NAPI_MODULE_GET_API_VERSION \
173+
NAPI_CONCAT(NAPI_MODULE_GET_API_VERSION_BASE, NAPI_MODULE_VERSION)
113174

114175
#define NAPI_MODULE_INIT() \
115176
EXTERN_C_START \
116177
NAPI_MODULE_EXPORT napi_value NAPI_MODULE_INITIALIZER(napi_env env, \
117178
napi_value exports); \
118-
NAPI_MODULE_EXPORT int32_t NAPI_MODULE_API_VERSION() { \
179+
NAPI_MODULE_EXPORT int32_t NAPI_MODULE_GET_API_VERSION() { \
119180
return NAPI_VERSION; \
120181
} \
121182
EXTERN_C_END \
122183
napi_value NAPI_MODULE_INITIALIZER(napi_env env, napi_value exports)
123184

124185
#ifdef __wasm32__
186+
125187
#define NAPI_WASM_INITIALIZER \
126188
NAPI_CONCAT(napi_register_wasm_v, NAPI_MODULE_VERSION)
127-
#define NAPI_WASM_API_VERSION \
128-
NAPI_CONCAT(napi_wasm_api_version_v, NAPI_MODULE_VERSION)
189+
#define NAPI_WASM_GET_API_VERSION \
190+
NAPI_CONCAT(napi_wasm_get_api_version_v, NAPI_MODULE_VERSION)
129191
#define NAPI_MODULE(modname, regfunc) \
130192
EXTERN_C_START \
131193
NAPI_MODULE_EXPORT napi_value NAPI_WASM_INITIALIZER(napi_env env, \
132194
napi_value exports) { \
133195
return regfunc(env, exports); \
134196
} \
135-
NAPI_MODULE_EXPORT int32_t NAPI_WASM_API_VERSION() { \
197+
NAPI_MODULE_EXPORT int32_t NAPI_WASM_GET_API_VERSION() { \
136198
return NAPI_VERSION; \
137199
} \
138200
EXTERN_C_END
139201
#else
202+
140203
#define NAPI_MODULE(modname, regfunc) \
141204
NAPI_MODULE_INIT() { \
142205
return regfunc(env, exports); \
143206
}
144207

145-
#endif
208+
#endif // __wasm32__
209+
210+
#endif // NAPI_EXPERIMENTAL
146211

147212
EXTERN_C_START
148213

src/node_api_internals.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
struct node_napi_env__ : public napi_env__ {
1212
node_napi_env__(v8::Local<v8::Context> context,
1313
const std::string& module_filename,
14-
int32_t node_api_version);
14+
int32_t module_api_version);
1515

1616
bool can_call_into_js() const override;
1717
v8::Maybe<bool> mark_arraybuffer_as_untransferable(

src/node_binding.cc

+10-10
Original file line numberDiff line numberDiff line change
@@ -402,11 +402,10 @@ inline napi_addon_register_func GetNapiInitializerCallback(DLib* dlib) {
402402
dlib->GetSymbolAddress(name));
403403
}
404404

405-
inline napi_addon_api_version_func GetNapiAddonApiVersionCallback(DLib* dlib) {
406-
const char* name =
407-
STRINGIFY(NAPI_MODULE_API_VERSION_BASE) STRINGIFY(NAPI_MODULE_VERSION);
408-
return reinterpret_cast<napi_addon_api_version_func>(
409-
dlib->GetSymbolAddress(name));
405+
inline napi_addon_get_api_version_func GetNapiAddonGetApiVersionCallback(
406+
DLib* dlib) {
407+
return reinterpret_cast<napi_addon_get_api_version_func>(
408+
dlib->GetSymbolAddress(STRINGIFY(NAPI_MODULE_GET_API_VERSION)));
410409
}
411410

412411
// DLOpen is process.dlopen(module, filename, flags).
@@ -485,11 +484,12 @@ void DLOpen(const FunctionCallbackInfo<Value>& args) {
485484
callback(exports, module, context);
486485
return true;
487486
} else if (auto napi_callback = GetNapiInitializerCallback(dlib)) {
488-
napi_module_register_by_symbol(exports,
489-
module,
490-
context,
491-
napi_callback,
492-
GetNapiAddonApiVersionCallback(dlib));
487+
int32_t module_api_version = 0;
488+
if (auto get_version = GetNapiAddonGetApiVersionCallback(dlib)) {
489+
module_api_version = get_version();
490+
}
491+
napi_module_register_by_symbol(
492+
exports, module, context, napi_callback, module_api_version);
493493
return true;
494494
} else {
495495
mp = dlib->GetSavedModuleFromGlobalHandleMap();

src/node_binding.h

+6-7
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ enum {
2121

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

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

40-
void napi_module_register_by_symbol(
41-
v8::Local<v8::Object> exports,
42-
v8::Local<v8::Value> module,
43-
v8::Local<v8::Context> context,
44-
napi_addon_register_func init,
45-
napi_addon_api_version_func get_api_version);
40+
void napi_module_register_by_symbol(v8::Local<v8::Object> exports,
41+
v8::Local<v8::Value> module,
42+
v8::Local<v8::Context> context,
43+
napi_addon_register_func init,
44+
int32_t module_api_version);
4645

4746
namespace node {
4847

test/cctest/test_js_native_api_v8.cc

+1-1
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ TEST_F(JsNativeApiV8Test, Reference) {
4949
Local<Object> module_obj = Object::New(isolate_);
5050
Local<Object> exports_obj = Object::New(isolate_);
5151
napi_module_register_by_symbol(
52-
exports_obj, module_obj, env->context(), init, nullptr);
52+
exports_obj, module_obj, env->context(), init, 0);
5353
ASSERT_NE(addon_env, nullptr);
5454
node_napi_env internal_env = reinterpret_cast<node_napi_env>(addon_env);
5555
EXPECT_EQ(internal_env->node_env(), env);

test/cctest/test_node_api.cc

+1-1
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ TEST_F(NodeApiTest, CreateNodeApiEnv) {
3535
Local<Object> module_obj = Object::New(isolate_);
3636
Local<Object> exports_obj = Object::New(isolate_);
3737
napi_module_register_by_symbol(
38-
exports_obj, module_obj, env->context(), init, nullptr);
38+
exports_obj, module_obj, env->context(), init, 0);
3939
ASSERT_NE(addon_env, nullptr);
4040
node_napi_env internal_env = reinterpret_cast<node_napi_env>(addon_env);
4141
EXPECT_EQ(internal_env->node_env(), env);
+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
'targets': [
3+
{
4+
'target_name': 'test_null_init',
5+
'sources': [ 'test_null_init.c' ]
6+
}
7+
]
8+
}

test/node-api/test_null_init/test.js

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
'use strict';
2+
const common = require('../../common');
3+
const assert = require('assert');
4+
5+
assert.throws(
6+
() => require(`./build/${common.buildType}/test_null_init`),
7+
/Module has no declared entry point[.]/);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
#include <node_api.h>
2+
3+
NAPI_MODULE(NODE_GYP_MODULE_NAME, NULL)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{
2+
"targets": [
3+
{
4+
"target_name": "test_reference_all_types",
5+
"sources": [ "test_reference_all_types.c" ],
6+
"defines": [ 'NAPI_EXPERIMENTAL' ]
7+
}
8+
]
9+
}

0 commit comments

Comments
 (0)