Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

src: allow N-API addon in AddLinkedBinding() #35301

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions src/api/environment.cc
Original file line number Diff line number Diff line change
Expand Up @@ -677,6 +677,10 @@ void AddLinkedBinding(Environment* env, const node_module& mod) {
prev_head->nm_link = &env->extra_linked_bindings()->back();
}

void AddLinkedBinding(Environment* env, const napi_module& mod) {
AddLinkedBinding(env, napi_module_to_node_module(&mod));
}

void AddLinkedBinding(Environment* env,
const char* name,
addon_context_register_func fn,
Expand Down
4 changes: 4 additions & 0 deletions src/node.h
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,8 @@
// Forward-declare libuv loop
struct uv_loop_s;

struct napi_module;

// Forward-declare these functions now to stop MSVS from becoming
// terminally confused when it's done in node_internals.h
namespace node {
Expand Down Expand Up @@ -819,6 +821,8 @@ extern "C" NODE_EXTERN void node_module_register(void* mod);
// In each variant, the registration function needs to be usable at least for
// the time during which the Environment exists.
NODE_EXTERN void AddLinkedBinding(Environment* env, const node_module& mod);
NODE_EXTERN void AddLinkedBinding(Environment* env,
const struct napi_module& mod);
NODE_EXTERN void AddLinkedBinding(Environment* env,
const char* name,
addon_context_register_func fn,
Expand Down
17 changes: 12 additions & 5 deletions src/node_api.cc
Original file line number Diff line number Diff line change
Expand Up @@ -447,7 +447,7 @@ static void napi_module_register_cb(v8::Local<v8::Object> exports,
v8::Local<v8::Context> context,
void* priv) {
napi_module_register_by_symbol(exports, module, context,
static_cast<napi_module*>(priv)->nm_register_func);
static_cast<const napi_module*>(priv)->nm_register_func);
}

void napi_module_register_by_symbol(v8::Local<v8::Object> exports,
Expand Down Expand Up @@ -480,19 +480,26 @@ void napi_module_register_by_symbol(v8::Local<v8::Object> exports,
}
}

// Registers a NAPI module.
void napi_module_register(napi_module* mod) {
node::node_module* nm = new node::node_module {
namespace node {
node_module napi_module_to_node_module(const napi_module* mod) {
return {
-1,
mod->nm_flags | NM_F_DELETEME,
nullptr,
mod->nm_filename,
nullptr,
napi_module_register_cb,
mod->nm_modname,
mod, // priv
const_cast<napi_module*>(mod), // priv
nullptr,
};
}
} // namespace node

// Registers a NAPI module.
void napi_module_register(napi_module* mod) {
node::node_module* nm = new node::node_module(
node::napi_module_to_node_module(mod));
node::node_module_register(nm);
}

Expand Down
2 changes: 1 addition & 1 deletion 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_addon_register_func)(napi_env env,
napi_value exports);

typedef struct {
typedef struct napi_module {
int nm_version;
unsigned int nm_flags;
const char* nm_filename;
Expand Down
2 changes: 2 additions & 0 deletions src/node_internals.h
Original file line number Diff line number Diff line change
Expand Up @@ -398,6 +398,8 @@ namespace fs {
std::string Basename(const std::string& str, const std::string& extension);
} // namespace fs

node_module napi_module_to_node_module(const napi_module* mod);

} // namespace node

#endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
Expand Down
109 changes: 108 additions & 1 deletion test/cctest/test_linked_binding.cc
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#include "node_test_fixture.h"
#include "node_internals.h" // RunBootstrapping()
#include "node_api.h"

void InitializeBinding(v8::Local<v8::Object> exports,
v8::Local<v8::Value> module,
Expand Down Expand Up @@ -83,3 +83,110 @@ TEST_F(LinkedBindingTest, LocallyDefinedLinkedBindingTest) {
CHECK_EQ(strcmp(*utf8val, "value"), 0);
CHECK_EQ(calls, 1);
}

napi_value InitializeLocalNapiBinding(napi_env env, napi_value exports) {
napi_value key, value;
CHECK_EQ(
napi_create_string_utf8(env, "hello", NAPI_AUTO_LENGTH, &key), napi_ok);
CHECK_EQ(
napi_create_string_utf8(env, "world", NAPI_AUTO_LENGTH, &value), napi_ok);
CHECK_EQ(napi_set_property(env, exports, key, value), napi_ok);
return nullptr;
}

static napi_module local_linked_napi = {
NAPI_MODULE_VERSION,
node::ModuleFlags::kLinked,
nullptr,
InitializeLocalNapiBinding,
"local_linked_napi",
nullptr,
{0},
};

TEST_F(LinkedBindingTest, LocallyDefinedLinkedBindingNapiTest) {
const v8::HandleScope handle_scope(isolate_);
const Argv argv;
Env test_env {handle_scope, argv};

AddLinkedBinding(*test_env, local_linked_napi);

v8::Local<v8::Context> context = isolate_->GetCurrentContext();

const char* run_script =
"process._linkedBinding('local_linked_napi').hello";
v8::Local<v8::Script> script = v8::Script::Compile(
context,
v8::String::NewFromOneByte(isolate_,
reinterpret_cast<const uint8_t*>(run_script))
.ToLocalChecked())
.ToLocalChecked();
v8::Local<v8::Value> completion_value = script->Run(context).ToLocalChecked();
v8::String::Utf8Value utf8val(isolate_, completion_value);
CHECK_NOT_NULL(*utf8val);
CHECK_EQ(strcmp(*utf8val, "world"), 0);
}

napi_value NapiLinkedWithInstanceData(napi_env env, napi_value exports) {
int* instance_data = new int(0);
CHECK_EQ(
napi_set_instance_data(
env,
instance_data,
[](napi_env env, void* data, void* hint) {
++*static_cast<int*>(data);
}, nullptr),
napi_ok);

napi_value key, value;
CHECK_EQ(
napi_create_string_utf8(env, "hello", NAPI_AUTO_LENGTH, &key), napi_ok);
CHECK_EQ(
napi_create_external(env, instance_data, nullptr, nullptr, &value),
napi_ok);
CHECK_EQ(napi_set_property(env, exports, key, value), napi_ok);
return nullptr;
}

static napi_module local_linked_napi_id = {
NAPI_MODULE_VERSION,
node::ModuleFlags::kLinked,
nullptr,
NapiLinkedWithInstanceData,
"local_linked_napi_id",
nullptr,
{0},
};

TEST_F(LinkedBindingTest, LocallyDefinedLinkedBindingNapiInstanceDataTest) {
const v8::HandleScope handle_scope(isolate_);
int* instance_data = nullptr;

{
const Argv argv;
Env test_env {handle_scope, argv};

AddLinkedBinding(*test_env, local_linked_napi_id);

v8::Local<v8::Context> context = isolate_->GetCurrentContext();

const char* run_script =
"process._linkedBinding('local_linked_napi_id').hello";
v8::Local<v8::Script> script = v8::Script::Compile(
context,
v8::String::NewFromOneByte(isolate_,
reinterpret_cast<const uint8_t*>(run_script))
.ToLocalChecked())
.ToLocalChecked();
v8::Local<v8::Value> completion_value =
script->Run(context).ToLocalChecked();
CHECK(completion_value->IsExternal());
instance_data = static_cast<int*>(
completion_value.As<v8::External>()->Value());
CHECK_NE(instance_data, nullptr);
CHECK_EQ(*instance_data, 0);
}

CHECK_EQ(*instance_data, 1);
delete instance_data;
}