Skip to content
Closed
Show file tree
Hide file tree
Changes from 2 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
1 change: 1 addition & 0 deletions node.gyp
Original file line number Diff line number Diff line change
Expand Up @@ -1037,6 +1037,7 @@
'test/cctest/test_base64.cc',
'test/cctest/test_node_postmortem_metadata.cc',
'test/cctest/test_environment.cc',
'test/cctest/test_linked_binding.cc',
'test/cctest/test_platform.cc',
'test/cctest/test_report_util.cc',
'test/cctest/test_traced_value.cc',
Expand Down
12 changes: 12 additions & 0 deletions src/node.h
Original file line number Diff line number Diff line change
Expand Up @@ -445,6 +445,10 @@ typedef void (*addon_context_register_func)(
v8::Local<v8::Context> context,
void* priv);

enum ModuleFlags {
kLinked = 0x02
};

struct node_module {
int nm_version;
unsigned int nm_flags;
Expand Down Expand Up @@ -532,6 +536,14 @@ extern "C" NODE_EXTERN void node_module_register(void* mod);
/* NOLINTNEXTLINE (readability/null_usage) */ \
NODE_MODULE_CONTEXT_AWARE_X(modname, regfunc, NULL, 0)

// Embedders can use this type of binding for statically linked native bindings.
// It is used the same way addon bindings are used, except that linked bindings
// can be accessed through `process._linkedBinding(modname)`.
#define NODE_MODULE_LINKED(modname, regfunc) \
/* NOLINTNEXTLINE (readability/null_usage) */ \
NODE_MODULE_CONTEXT_AWARE_X(modname, regfunc, NULL, \
node::ModuleFlags::kLinked)

/*
* For backward compatibility in add-on modules.
*/
Expand Down
4 changes: 4 additions & 0 deletions src/node_binding.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@ enum {
NM_F_DELETEME = 1 << 3,
};

// 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));
Comment thread
addaleax marked this conversation as resolved.
Outdated

#define NODE_MODULE_CONTEXT_AWARE_CPP(modname, regfunc, priv, flags) \
static node::node_module _module = { \
NODE_MODULE_VERSION, \
Expand Down
1 change: 1 addition & 0 deletions test/cctest/node_test_fixture.cc
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@ ArrayBufferUniquePtr NodeTestFixture::allocator{nullptr, nullptr};
uv_loop_t NodeTestFixture::current_loop;
NodePlatformUniquePtr NodeTestFixture::platform;
TracingAgentUniquePtr NodeTestFixture::tracing_agent;
bool NodeTestFixture::node_initialized = false;
14 changes: 14 additions & 0 deletions test/cctest/node_test_fixture.h
Original file line number Diff line number Diff line change
Expand Up @@ -64,9 +64,19 @@ class NodeTestFixture : public ::testing::Test {
static TracingAgentUniquePtr tracing_agent;
static NodePlatformUniquePtr platform;
static uv_loop_t current_loop;
static bool node_initialized;
v8::Isolate* isolate_;

static void SetUpTestCase() {
if (!node_initialized) {
node_initialized = true;
int argc = 1;
const char* argv0 = "cctest";
int exec_argc;
const char** exec_argv;
node::Init(&argc, &argv0, &exec_argc, &exec_argv);
}

tracing_agent.reset(new node::tracing::Agent());
node::tracing::TraceEventHelper::SetAgent(tracing_agent.get());
CHECK_EQ(0, uv_loop_init(&current_loop));
Expand All @@ -89,9 +99,11 @@ class NodeTestFixture : public ::testing::Test {
&node::FreeArrayBufferAllocator);
isolate_ = NewIsolate(allocator.get(), &current_loop);
CHECK_NE(isolate_, nullptr);
isolate_->Enter();
}

void TearDown() override {
isolate_->Exit();
isolate_->Dispose();
platform->UnregisterIsolate(isolate_);
isolate_ = nullptr;
Expand All @@ -118,6 +130,8 @@ class EnvironmentTestFixture : public NodeTestFixture {
1, *argv,
argv.nr_args(), *argv);
CHECK_NE(nullptr, environment_);
// TODO(addaleax): Make this a public API.
CHECK(!RunBootstrapping(environment_).IsEmpty());
}

~Env() {
Expand Down
42 changes: 42 additions & 0 deletions test/cctest/test_linked_binding.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
#include "node_test_fixture.h"
#include "node_internals.h" // RunBootstrapping()

void InitializeBinding(v8::Local<v8::Object> exports,
v8::Local<v8::Value> module,
v8::Local<v8::Context> context) {
v8::Isolate* isolate = context->GetIsolate();
exports->Set(
context,
v8::String::NewFromOneByte(isolate,
reinterpret_cast<const uint8_t*>("key"),
v8::NewStringType::kNormal).ToLocalChecked(),
v8::String::NewFromOneByte(isolate,
reinterpret_cast<const uint8_t*>("value"),
v8::NewStringType::kNormal).ToLocalChecked())
.FromJust();
}

NODE_MODULE_LINKED(cctest_linkedbinding, InitializeBinding);

class LinkedBindingTest : public EnvironmentTestFixture {};

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

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

const char* run_script =
"process._linkedBinding('cctest_linkedbinding').key";
v8::Local<v8::Script> script = v8::Script::Compile(
context,
v8::String::NewFromOneByte(isolate_,
reinterpret_cast<const uint8_t*>(run_script),
v8::NewStringType::kNormal).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, "value"), 0);
}