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: implement constants and natives binding directly #48186

Closed
wants to merge 3 commits 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
15 changes: 9 additions & 6 deletions lib/internal/bootstrap/realm.js
Original file line number Diff line number Diff line change
Expand Up @@ -78,11 +78,13 @@ ObjectDefineProperty(process, 'moduleLoadList', {
});


// internalBindingAllowlist contains the name of internalBinding modules
// that are allowed for access via process.binding()... This is used
// to provide a transition path for modules that are being moved over to
// internalBinding.
const internalBindingAllowlist = new SafeSet([
// processBindingAllowList contains the name of bindings that are allowed
// for access via process.binding(). This is used to provide a transition
// path for modules that are being moved over to internalBinding.
// Certain bindings may not actually correspond to an internalBinding any
// more, we just implement them as legacy wrappers instead. See the
// legacyWrapperList.
const processBindingAllowList = new SafeSet([
'async_wrap',
'buffer',
'cares_wrap',
Expand Down Expand Up @@ -124,6 +126,7 @@ const runtimeDeprecatedList = new SafeSet([
]);

const legacyWrapperList = new SafeSet([
'natives',
'util',
]);

Expand All @@ -145,7 +148,7 @@ const experimentalModuleList = new SafeSet();
module = String(module);
// Deprecated specific process.binding() modules, but not all, allow
// selective fallback to internalBinding for the deprecated ones.
if (internalBindingAllowlist.has(module)) {
if (processBindingAllowList.has(module)) {
if (runtimeDeprecatedList.has(module)) {
runtimeDeprecatedList.delete(module);
process.emitWarning(
Expand Down
8 changes: 2 additions & 6 deletions lib/internal/debugger/inspect_repl.js
Original file line number Diff line number Diff line change
Expand Up @@ -118,16 +118,12 @@ function extractFunctionName(description) {
return fnNameMatch ? `: ${fnNameMatch[1]}` : '';
}

const {
builtinIds: PUBLIC_BUILTINS,
} = internalBinding('builtins');
const NATIVES = internalBinding('natives');
const { builtinIds } = internalBinding('builtins');
function isNativeUrl(url) {
url = SideEffectFreeRegExpPrototypeSymbolReplace(/\.js$/, url, '');

return StringPrototypeStartsWith(url, 'node:internal/') ||
ArrayPrototypeIncludes(PUBLIC_BUILTINS, url) ||
url in NATIVES || url === 'bootstrap_node';
Copy link
Member Author

@joyeecheung joyeecheung May 26, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The original condition was already redundant, builtinIds actually contains both public and internal IDs, so I just removed it (as well as bootstrap_node which no longer exists)

ArrayPrototypeIncludes(builtinIds, url);
}

function getRelativePath(filenameOrURL) {
Expand Down
8 changes: 8 additions & 0 deletions lib/internal/legacy/processbinding.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,4 +33,12 @@ module.exports = {
], key);
})));
},
natives() {
const { natives: result, configs } = internalBinding('builtins');
// Legacy feature: process.binding('natives').config contains stringified
// config.gypi. We do not use this object internally so it's fine to mutate
// it.
result.configs = configs;
return result;
joyeecheung marked this conversation as resolved.
Show resolved Hide resolved
},
};
2 changes: 1 addition & 1 deletion lib/internal/v8_prof_processor.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ const console = require('internal/console/global');
const vm = require('vm');
const { SourceTextModule } = require('internal/vm/module');

const natives = internalBinding('natives');
const { natives } = internalBinding('builtins');
anonrig marked this conversation as resolved.
Show resolved Hide resolved

async function linker(specifier, referencingModule) {
// Transform "./file.mjs" to "file"
Expand Down
15 changes: 1 addition & 14 deletions src/node_binding.cc
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
V(builtins) \
V(cares_wrap) \
V(config) \
V(constants) \
V(contextify) \
V(credentials) \
V(encoding_binding) \
Expand Down Expand Up @@ -619,7 +620,6 @@ void GetInternalBinding(const FunctionCallbackInfo<Value>& args) {
Realm* realm = Realm::GetCurrent(args);
Isolate* isolate = realm->isolate();
HandleScope scope(isolate);
Local<Context> context = realm->context();

CHECK(args[0]->IsString());

Expand All @@ -631,19 +631,6 @@ void GetInternalBinding(const FunctionCallbackInfo<Value>& args) {
if (mod != nullptr) {
exports = InitInternalBinding(realm, mod);
realm->internal_bindings.insert(mod);
} else if (!strcmp(*module_v, "constants")) {
exports = Object::New(isolate);
CHECK(exports->SetPrototype(context, Null(isolate)).FromJust());
DefineConstants(isolate, exports);
} else if (!strcmp(*module_v, "natives")) {
exports = realm->env()->builtin_loader()->GetSourceObject(context);
// Legacy feature: process.binding('natives').config contains stringified
// config.gypi
CHECK(exports
->Set(context,
realm->isolate_data()->config_string(),
realm->env()->builtin_loader()->GetConfigString(isolate))
.FromJust());
} else {
return THROW_ERR_INVALID_MODULE(isolate, "No such binding: %s", *module_v);
}
Expand Down
21 changes: 17 additions & 4 deletions src/node_builtins.cc
Original file line number Diff line number Diff line change
Expand Up @@ -63,15 +63,19 @@ bool BuiltinLoader::Add(const char* id, const UnionBytes& source) {
return result.second;
}

Local<Object> BuiltinLoader::GetSourceObject(Local<Context> context) {
Isolate* isolate = context->GetIsolate();
void BuiltinLoader::GetNatives(Local<Name> property,
const PropertyCallbackInfo<Value>& info) {
Environment* env = Environment::GetCurrent(info);
Isolate* isolate = env->isolate();
Local<Context> context = env->context();

Local<Object> out = Object::New(isolate);
auto source = source_.read();
auto source = env->builtin_loader()->source_.read();
for (auto const& x : *source) {
Local<String> key = OneByteString(isolate, x.first.c_str(), x.first.size());
out->Set(context, key, x.second.ToStringChecked(isolate)).FromJust();
}
return out;
info.GetReturnValue().Set(out);
}

Local<String> BuiltinLoader::GetConfigString(Isolate* isolate) {
Expand Down Expand Up @@ -689,6 +693,14 @@ void BuiltinLoader::CreatePerIsolateProperties(IsolateData* isolate_data,
None,
SideEffectType::kHasNoSideEffect);

target->SetAccessor(FIXED_ONE_BYTE_STRING(isolate, "natives"),
GetNatives,
nullptr,
Local<Value>(),
DEFAULT,
None,
SideEffectType::kHasNoSideEffect);

SetMethod(isolate, target, "getCacheUsage", BuiltinLoader::GetCacheUsage);
SetMethod(isolate, target, "compileFunction", BuiltinLoader::CompileFunction);
SetMethod(isolate, target, "hasCachedBuiltins", HasCachedBuiltins);
Expand All @@ -712,6 +724,7 @@ void BuiltinLoader::RegisterExternalReferences(
registry->Register(CompileFunction);
registry->Register(HasCachedBuiltins);
registry->Register(SetInternalLoaders);
registry->Register(GetNatives);

RegisterExternalReferencesForInternalizedBuiltinCode(registry);
}
Expand Down
4 changes: 3 additions & 1 deletion src/node_builtins.h
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,6 @@ class NODE_EXTERN_PRIVATE BuiltinLoader {
const char* id,
Realm* realm);

v8::Local<v8::Object> GetSourceObject(v8::Local<v8::Context> context);
// Returns config.gypi as a JSON string
v8::Local<v8::String> GetConfigString(v8::Isolate* isolate);
bool Exists(const char* id);
Expand Down Expand Up @@ -169,6 +168,9 @@ class NODE_EXTERN_PRIVATE BuiltinLoader {
static void CompileFunction(const v8::FunctionCallbackInfo<v8::Value>& args);
static void HasCachedBuiltins(
const v8::FunctionCallbackInfo<v8::Value>& args);
// For legacy process.binding('natives')
static void GetNatives(v8::Local<v8::Name> property,
const v8::PropertyCallbackInfo<v8::Value>& info);

void AddExternalizedBuiltin(const char* id, const char* filename);

Expand Down
20 changes: 16 additions & 4 deletions src/node_constants.cc
Original file line number Diff line number Diff line change
Expand Up @@ -63,10 +63,14 @@

namespace node {

using v8::Context;
using v8::Isolate;
using v8::Local;
using v8::Null;
using v8::Object;
using v8::Value;

namespace {
namespace constants {

void DefineErrnoConstants(Local<Object> target) {
#ifdef E2BIG
Expand Down Expand Up @@ -1270,10 +1274,14 @@ void DefineTraceConstants(Local<Object> target) {
NODE_DEFINE_CONSTANT(target, TRACE_EVENT_PHASE_LINK_IDS);
}

} // anonymous namespace
void CreatePerContextProperties(Local<Object> target,
Local<Value> unused,
Local<Context> context,
void* priv) {
Isolate* isolate = context->GetIsolate();
Environment* env = Environment::GetCurrent(context);

void DefineConstants(v8::Isolate* isolate, Local<Object> target) {
Environment* env = Environment::GetCurrent(isolate);
CHECK(target->SetPrototype(env->context(), Null(env->isolate())).FromJust());

Local<Object> os_constants = Object::New(isolate);
CHECK(os_constants->SetPrototype(env->context(),
Expand Down Expand Up @@ -1353,4 +1361,8 @@ void DefineConstants(v8::Isolate* isolate, Local<Object> target) {
trace_constants).Check();
}

} // namespace constants
} // namespace node

NODE_BINDING_CONTEXT_AWARE_INTERNAL(constants,
node::constants::CreatePerContextProperties)
5 changes: 0 additions & 5 deletions src/node_constants.h
Original file line number Diff line number Diff line change
Expand Up @@ -74,11 +74,6 @@
#endif // NODE_OPENSSL_DEFAULT_CIPHER_LIST
#endif // HAVE_OPENSSL

namespace node {

void DefineConstants(v8::Isolate* isolate, v8::Local<v8::Object> target);
} // namespace node

#endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS

#endif // SRC_NODE_CONSTANTS_H_
5 changes: 3 additions & 2 deletions test/es-module/test-loaders-hidden-from-users.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,9 @@ assert.throws(
assert.throws(
() => {
const source = 'module.exports = require("internal/bootstrap/realm")';
const { internalBinding } = require('internal/test/binding');
internalBinding('natives').owo = source;
// This needs to be process.binding() to mimic what's normally available
// in the user land.
process.binding('natives').owo = source;
require('owo');
}, {
code: 'MODULE_NOT_FOUND',
Expand Down