src: implement natives binding without special casing

This patch removes special case in the internal binding loader
for natives, and implements it using the builtins internal
binding. Internally we do not actually need the natives binding,
so implement it as a legacy wrapper instead.

PR-URL: https://github.com/nodejs/node/pull/48186
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Chengzhong Wu <legendecas@gmail.com>
This commit is contained in:
Joyee Cheung 2023-05-06 16:51:51 +02:00
parent 6a3403cded
commit e1fa85133f
No known key found for this signature in database
GPG Key ID: 92B78A53C8303B8D
8 changed files with 43 additions and 29 deletions

View File

@ -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',
@ -124,6 +126,7 @@ const runtimeDeprecatedList = new SafeSet([
]);
const legacyWrapperList = new SafeSet([
'natives',
'util',
]);
@ -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(

View File

@ -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';
ArrayPrototypeIncludes(builtinIds, url);
}
function getRelativePath(filenameOrURL) {

View File

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

View File

@ -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');
async function linker(specifier, referencingModule) {
// Transform "./file.mjs" to "file"

View File

@ -635,15 +635,6 @@ void GetInternalBinding(const FunctionCallbackInfo<Value>& args) {
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);
}

View File

@ -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) {
@ -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);
@ -712,6 +724,7 @@ void BuiltinLoader::RegisterExternalReferences(
registry->Register(CompileFunction);
registry->Register(HasCachedBuiltins);
registry->Register(SetInternalLoaders);
registry->Register(GetNatives);
RegisterExternalReferencesForInternalizedBuiltinCode(registry);
}

View File

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

View File

@ -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',