src: add public API for linked bindings

(Re-?)add a public API for creating linked bindings (access to
`NM_F_LINKED` as a constant was previously removed in
d6ac8a4db0), and add a test for
the functionality.

PR-URL: https://github.com/nodejs/node/pull/26457
Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
Reviewed-By: Joyee Cheung <joyeec9h3@gmail.com>
Reviewed-By: Shelley Vohr <codebytere@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
This commit is contained in:
Anna Henningsen 2019-03-05 20:09:43 +01:00 committed by Ruben Bridgewater
parent 58b00f4cca
commit db2a5b05df
No known key found for this signature in database
GPG Key ID: F07496B3EB3C1762
4 changed files with 60 additions and 0 deletions

View File

@ -1038,6 +1038,7 @@
'test/cctest/test_base64.cc', 'test/cctest/test_base64.cc',
'test/cctest/test_node_postmortem_metadata.cc', 'test/cctest/test_node_postmortem_metadata.cc',
'test/cctest/test_environment.cc', 'test/cctest/test_environment.cc',
'test/cctest/test_linked_binding.cc',
'test/cctest/test_platform.cc', 'test/cctest/test_platform.cc',
'test/cctest/test_report_util.cc', 'test/cctest/test_report_util.cc',
'test/cctest/test_traced_value.cc', 'test/cctest/test_traced_value.cc',

View File

@ -445,6 +445,10 @@ typedef void (*addon_context_register_func)(
v8::Local<v8::Context> context, v8::Local<v8::Context> context,
void* priv); void* priv);
enum ModuleFlags {
kLinked = 0x02
};
struct node_module { struct node_module {
int nm_version; int nm_version;
unsigned int nm_flags; unsigned int nm_flags;
@ -532,6 +536,14 @@ extern "C" NODE_EXTERN void node_module_register(void* mod);
/* NOLINTNEXTLINE (readability/null_usage) */ \ /* NOLINTNEXTLINE (readability/null_usage) */ \
NODE_MODULE_CONTEXT_AWARE_X(modname, regfunc, NULL, 0) 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. * For backward compatibility in add-on modules.
*/ */

View File

@ -21,6 +21,11 @@ enum {
NM_F_DELETEME = 1 << 3, 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),
"NM_F_LINKED != node::ModuleFlags::kLinked");
#define NODE_MODULE_CONTEXT_AWARE_CPP(modname, regfunc, priv, flags) \ #define NODE_MODULE_CONTEXT_AWARE_CPP(modname, regfunc, priv, flags) \
static node::node_module _module = { \ static node::node_module _module = { \
NODE_MODULE_VERSION, \ NODE_MODULE_VERSION, \

View File

@ -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);
}