Skip to content

Commit

Permalink
module: bootstrap module loaders in shadow realm
Browse files Browse the repository at this point in the history
  • Loading branch information
legendecas committed Aug 17, 2023
1 parent 966e3d3 commit f1f3986
Show file tree
Hide file tree
Showing 25 changed files with 487 additions and 190 deletions.
13 changes: 11 additions & 2 deletions lib/internal/bootstrap/realm.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@

const {
ArrayFrom,
ArrayPrototypeFilter,
ArrayPrototypeIncludes,
ArrayPrototypeMap,
ArrayPrototypePush,
ArrayPrototypeSlice,
Expand Down Expand Up @@ -215,8 +217,8 @@ const internalBuiltinIds = builtinIds
.filter((id) => StringPrototypeStartsWith(id, 'internal/') && id !== selfId);

// When --expose-internals is on we'll add the internal builtin ids to these.
const canBeRequiredByUsersList = new SafeSet(publicBuiltinIds);
const canBeRequiredByUsersWithoutSchemeList =
let canBeRequiredByUsersList = new SafeSet(publicBuiltinIds);
let canBeRequiredByUsersWithoutSchemeList =
new SafeSet(publicBuiltinIds.filter((id) => !schemelessBlockList.has(id)));

/**
Expand Down Expand Up @@ -269,6 +271,13 @@ class BuiltinModule {
}
}

static setRealmAllowRequireByUsers(ids) {
canBeRequiredByUsersList =
new SafeSet(ArrayPrototypeFilter(ids, (id) => ArrayPrototypeIncludes(publicBuiltinIds, id)));
canBeRequiredByUsersWithoutSchemeList =
new SafeSet(ArrayPrototypeFilter(ids, (id) => !schemelessBlockList.has(id)));
}

// To be called during pre-execution when --expose-internals is on.
// Enables the user-land module loader to access internal modules.
static exposeInternals() {
Expand Down
47 changes: 47 additions & 0 deletions lib/internal/bootstrap/shadow_realm.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
'use strict';

// In ShadowRealm.

const {
prepareShadowRealmExecution,
} = require('internal/process/pre_execution');
const {
BuiltinModule,
} = require('internal/bootstrap/realm');
const { setDefaultImportModuleDynamically } = require('internal/modules/esm/utils');

BuiltinModule.setRealmAllowRequireByUsers([
'assert',
'assert/strict',
'buffer',
'console',
'constants',
'cypto',
'diagnostics_channel',
'events',
'module',
'path',
'path/posix',
'path/win32',
'readline',
'readline/promises',
'repl',
'stream',
'stream/consumers',
'stream/promises',
'stream/web',
'string_decoder',
'url',
'util',
'util/types',
'zlib',
]);

prepareShadowRealmExecution();

// The handler for `ShadowRealm.prototype.importValue`.
setDefaultImportModuleDynamically((specifier, assertions) => {
const { esmLoader } = require('internal/process/esm_loader');
// `parentUrl` is not set in the case of a ShadowRealm top-level import.
return esmLoader.import(specifier, undefined, assertions);
});
5 changes: 4 additions & 1 deletion lib/internal/main/worker_thread.js
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,10 @@ port.on('message', (message) => {
const isLoaderWorker =
doEval === 'internal' &&
filename === require('internal/modules/esm/utils').loaderWorkerId;
setupUserModules(isLoaderWorker);
setupUserModules({
__proto__: null,
isLoaderWorker,
});

if (!hasStdin)
process.stdin.push(null);
Expand Down
9 changes: 9 additions & 0 deletions lib/internal/modules/esm/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,11 @@ function setCallbackForWrap(wrap, data) {
callbackMap.set(wrap, data);
}

let defaultImportModuleDynamically;
function setDefaultImportModuleDynamically(importModuleDynamically) {
defaultImportModuleDynamically = importModuleDynamically;
}

let defaultConditions;
function getDefaultConditions() {
assert(defaultConditions !== undefined);
Expand Down Expand Up @@ -90,6 +95,9 @@ async function importModuleDynamicallyCallback(wrap, specifier, assertions) {
specifier, getModuleFromWrap(wrap) || wrap, assertions);
}
}
if (defaultImportModuleDynamically) {
return defaultImportModuleDynamically(specifier, assertions);
}
throw new ERR_VM_DYNAMIC_IMPORT_CALLBACK_MISSING();
}

Expand Down Expand Up @@ -152,6 +160,7 @@ async function initializeHooks() {

module.exports = {
setCallbackForWrap,
setDefaultImportModuleDynamically,
initializeESM,
initializeHooks,
getDefaultConditions,
Expand Down
22 changes: 18 additions & 4 deletions lib/internal/process/pre_execution.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ const {
exposeLazyInterfaces,
defineReplaceableLazyAttribute,
setupCoverageHooks,
kEmptyObject,
} = require('internal/util');

const {
Expand Down Expand Up @@ -59,6 +60,18 @@ function prepareWorkerThreadExecution() {
});
}

function prepareShadowRealmExecution() {
// Patch the process object with legacy properties and normalizations.
// Do not expand argv1 as it is not available in ShadowRealm.
patchProcessObject(false);
setupDebugEnv();

setupUserModules({
__proto__: null,
noPreloadModules: true,
});
}

function prepareExecution(options) {
const { expandArgv1, initializeModules, isMainThread } = options;

Expand Down Expand Up @@ -150,16 +163,16 @@ function setupSymbolDisposePolyfill() {
}
}

function setupUserModules(isLoaderWorker = false) {
function setupUserModules(options = kEmptyObject) {
const { isLoaderWorker = false, noPreloadModules = false } = options;
initializeCJSLoader();
initializeESMLoader(isLoaderWorker);
const CJSLoader = require('internal/modules/cjs/loader');
assert(!CJSLoader.hasLoadedAnyUserCJSModule);
// Loader workers are responsible for doing this themselves.
if (isLoaderWorker) {
return;
if (!isLoaderWorker || noPreloadModules) {
loadPreloadModules();
}
loadPreloadModules();
// Need to be done after --require setup.
initializeFrozenIntrinsics();
}
Expand Down Expand Up @@ -687,6 +700,7 @@ module.exports = {
setupUserModules,
prepareMainThreadExecution,
prepareWorkerThreadExecution,
prepareShadowRealmExecution,
markBootstrapComplete,
loadPreloadModules,
initializeFrozenIntrinsics,
Expand Down
1 change: 1 addition & 0 deletions lib/internal/vm/module.js
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@ class Module {
options.cachedData);
const { setCallbackForWrap } = require('internal/modules/esm/utils');
setCallbackForWrap(this[kWrap], {
__proto__: null,
initializeImportMeta: options.initializeImportMeta,
importModuleDynamically: options.importModuleDynamically ?
importModuleDynamicallyWrap(options.importModuleDynamically) :
Expand Down
19 changes: 10 additions & 9 deletions src/async_wrap.cc
Original file line number Diff line number Diff line change
Expand Up @@ -372,8 +372,9 @@ void AsyncWrap::CreatePerContextProperties(Local<Object> target,
Local<Value> unused,
Local<Context> context,
void* priv) {
Environment* env = Environment::GetCurrent(context);
Isolate* isolate = env->isolate();
Realm* realm = Realm::GetCurrent(context);
Environment* env = realm->env();
Isolate* isolate = realm->isolate();
HandleScope scope(isolate);

PropertyAttribute ReadOnlyDontDelete =
Expand Down Expand Up @@ -446,13 +447,13 @@ void AsyncWrap::CreatePerContextProperties(Local<Object> target,

#undef FORCE_SET_TARGET_FIELD

env->set_async_hooks_init_function(Local<Function>());
env->set_async_hooks_before_function(Local<Function>());
env->set_async_hooks_after_function(Local<Function>());
env->set_async_hooks_destroy_function(Local<Function>());
env->set_async_hooks_promise_resolve_function(Local<Function>());
env->set_async_hooks_callback_trampoline(Local<Function>());
env->set_async_hooks_binding(target);
realm->set_async_hooks_init_function(Local<Function>());
realm->set_async_hooks_before_function(Local<Function>());
realm->set_async_hooks_after_function(Local<Function>());
realm->set_async_hooks_destroy_function(Local<Function>());
realm->set_async_hooks_promise_resolve_function(Local<Function>());
realm->set_async_hooks_callback_trampoline(Local<Function>());
realm->set_async_hooks_binding(target);
}

void AsyncWrap::RegisterExternalReferences(
Expand Down
12 changes: 8 additions & 4 deletions src/env.cc
Original file line number Diff line number Diff line change
Expand Up @@ -500,6 +500,7 @@ void IsolateData::CreateProperties() {
binding::CreateInternalBindingTemplates(this);

contextify::ContextifyContext::InitializeGlobalTemplates(this);
CreateEnvProxyTemplate(this);
}

constexpr uint16_t kDefaultCppGCEmebdderID = 0x90de;
Expand Down Expand Up @@ -1650,10 +1651,13 @@ void AsyncHooks::MemoryInfo(MemoryTracker* tracker) const {
void AsyncHooks::grow_async_ids_stack() {
async_ids_stack_.reserve(async_ids_stack_.Length() * 3);

env()->async_hooks_binding()->Set(
env()->context(),
env()->async_ids_stack_string(),
async_ids_stack_.GetJSArray()).Check();
env()
->principal_realm()
->async_hooks_binding()
->Set(env()->context(),
env()->async_ids_stack_string(),
async_ids_stack_.GetJSArray())
.Check();
}

void AsyncHooks::FailWithCorruptedAsyncStack(double expected_async_id) {
Expand Down
Loading

0 comments on commit f1f3986

Please sign in to comment.