mirror of
https://github.com/nodejs/node.git
synced 2024-11-21 10:59:27 +00:00
module: bootstrap module loaders in shadow realm
This bootstraps ESM loaders in the ShadowRealm with `ShadowRealm.prototype.importValue` as its entry point and enables loading ESM and CJS modules in the ShadowRealm. The module is imported without a parent URL and resolved with the current process's working directory. PR-URL: https://github.com/nodejs/node/pull/48655 Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com> Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Joyee Cheung <joyeec9h3@gmail.com>
This commit is contained in:
parent
6b7197cb2b
commit
fc2862b7f5
@ -50,6 +50,8 @@
|
|||||||
|
|
||||||
const {
|
const {
|
||||||
ArrayFrom,
|
ArrayFrom,
|
||||||
|
ArrayPrototypeFilter,
|
||||||
|
ArrayPrototypeIncludes,
|
||||||
ArrayPrototypeMap,
|
ArrayPrototypeMap,
|
||||||
ArrayPrototypePush,
|
ArrayPrototypePush,
|
||||||
ArrayPrototypeSlice,
|
ArrayPrototypeSlice,
|
||||||
@ -215,8 +217,8 @@ const internalBuiltinIds = builtinIds
|
|||||||
.filter((id) => StringPrototypeStartsWith(id, 'internal/') && id !== selfId);
|
.filter((id) => StringPrototypeStartsWith(id, 'internal/') && id !== selfId);
|
||||||
|
|
||||||
// When --expose-internals is on we'll add the internal builtin ids to these.
|
// When --expose-internals is on we'll add the internal builtin ids to these.
|
||||||
const canBeRequiredByUsersList = new SafeSet(publicBuiltinIds);
|
let canBeRequiredByUsersList = new SafeSet(publicBuiltinIds);
|
||||||
const canBeRequiredByUsersWithoutSchemeList =
|
let canBeRequiredByUsersWithoutSchemeList =
|
||||||
new SafeSet(publicBuiltinIds.filter((id) => !schemelessBlockList.has(id)));
|
new SafeSet(publicBuiltinIds.filter((id) => !schemelessBlockList.has(id)));
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -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.
|
// To be called during pre-execution when --expose-internals is on.
|
||||||
// Enables the user-land module loader to access internal modules.
|
// Enables the user-land module loader to access internal modules.
|
||||||
static exposeInternals() {
|
static exposeInternals() {
|
||||||
|
21
lib/internal/bootstrap/shadow_realm.js
Normal file
21
lib/internal/bootstrap/shadow_realm.js
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
// This script sets up the context for shadow realms.
|
||||||
|
|
||||||
|
const {
|
||||||
|
prepareShadowRealmExecution,
|
||||||
|
} = require('internal/process/pre_execution');
|
||||||
|
const {
|
||||||
|
BuiltinModule,
|
||||||
|
} = require('internal/bootstrap/realm');
|
||||||
|
|
||||||
|
BuiltinModule.setRealmAllowRequireByUsers([
|
||||||
|
/**
|
||||||
|
* The built-in modules exposed in the ShadowRealm must each be providing
|
||||||
|
* platform capabilities with no authority to cause side effects such as
|
||||||
|
* I/O or mutation of values that are shared across different realms within
|
||||||
|
* the same Node.js environment.
|
||||||
|
*/
|
||||||
|
]);
|
||||||
|
|
||||||
|
prepareShadowRealmExecution();
|
@ -136,6 +136,7 @@ port.on('message', (message) => {
|
|||||||
const isLoaderWorker =
|
const isLoaderWorker =
|
||||||
doEval === 'internal' &&
|
doEval === 'internal' &&
|
||||||
filename === require('internal/modules/esm/utils').loaderWorkerId;
|
filename === require('internal/modules/esm/utils').loaderWorkerId;
|
||||||
|
// Disable custom loaders in loader worker.
|
||||||
setupUserModules(isLoaderWorker);
|
setupUserModules(isLoaderWorker);
|
||||||
|
|
||||||
if (!hasStdin)
|
if (!hasStdin)
|
||||||
|
@ -528,9 +528,10 @@ let emittedLoaderFlagWarning = false;
|
|||||||
*/
|
*/
|
||||||
function createModuleLoader() {
|
function createModuleLoader() {
|
||||||
let customizations = null;
|
let customizations = null;
|
||||||
// Don't spawn a new worker if we're already in a worker thread created by instantiating CustomizedModuleLoader;
|
// Don't spawn a new worker if custom loaders are disabled. For instance, if
|
||||||
// doing so would cause an infinite loop.
|
// we're already in a worker thread created by instantiating
|
||||||
if (!require('internal/modules/esm/utils').isLoaderWorker()) {
|
// CustomizedModuleLoader; doing so would cause an infinite loop.
|
||||||
|
if (!require('internal/modules/esm/utils').forceDefaultLoader()) {
|
||||||
const userLoaderPaths = getOptionValue('--experimental-loader');
|
const userLoaderPaths = getOptionValue('--experimental-loader');
|
||||||
if (userLoaderPaths.length > 0) {
|
if (userLoaderPaths.length > 0) {
|
||||||
if (!emittedLoaderFlagWarning) {
|
if (!emittedLoaderFlagWarning) {
|
||||||
|
@ -4,6 +4,7 @@ const {
|
|||||||
ArrayIsArray,
|
ArrayIsArray,
|
||||||
SafeSet,
|
SafeSet,
|
||||||
SafeWeakMap,
|
SafeWeakMap,
|
||||||
|
Symbol,
|
||||||
ObjectFreeze,
|
ObjectFreeze,
|
||||||
} = primordials;
|
} = primordials;
|
||||||
|
|
||||||
@ -157,6 +158,26 @@ function registerModule(referrer, registry) {
|
|||||||
moduleRegistries.set(idSymbol, registry);
|
moduleRegistries.set(idSymbol, registry);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registers the ModuleRegistry for dynamic import() calls with a realm
|
||||||
|
* as the referrer. Similar to {@link registerModule}, but this function
|
||||||
|
* generates a new id symbol instead of using the one from the referrer
|
||||||
|
* object.
|
||||||
|
* @param {globalThis} globalThis The globalThis object of the realm.
|
||||||
|
* @param {ModuleRegistry} registry
|
||||||
|
*/
|
||||||
|
function registerRealm(globalThis, registry) {
|
||||||
|
let idSymbol = globalThis[host_defined_option_symbol];
|
||||||
|
// If the per-realm host-defined options is already registered, do nothing.
|
||||||
|
if (idSymbol) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Otherwise, register the per-realm host-defined options.
|
||||||
|
idSymbol = Symbol('Realm globalThis');
|
||||||
|
globalThis[host_defined_option_symbol] = idSymbol;
|
||||||
|
moduleRegistries.set(idSymbol, registry);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Defines the `import.meta` object for a given module.
|
* Defines the `import.meta` object for a given module.
|
||||||
* @param {symbol} symbol - Reference to the module.
|
* @param {symbol} symbol - Reference to the module.
|
||||||
@ -192,28 +213,29 @@ async function importModuleDynamicallyCallback(referrerSymbol, specifier, attrib
|
|||||||
throw new ERR_VM_DYNAMIC_IMPORT_CALLBACK_MISSING();
|
throw new ERR_VM_DYNAMIC_IMPORT_CALLBACK_MISSING();
|
||||||
}
|
}
|
||||||
|
|
||||||
let _isLoaderWorker = false;
|
let _forceDefaultLoader = false;
|
||||||
/**
|
/**
|
||||||
* Initializes handling of ES modules.
|
* Initializes handling of ES modules.
|
||||||
* This is configured during pre-execution. Specifically it's set to true for
|
* This is configured during pre-execution. Specifically it's set to true for
|
||||||
* the loader worker in internal/main/worker_thread.js.
|
* the loader worker in internal/main/worker_thread.js.
|
||||||
* @param {boolean} [isLoaderWorker=false] - A boolean indicating whether the loader is a worker or not.
|
* @param {boolean} [forceDefaultLoader=false] - A boolean indicating disabling custom loaders.
|
||||||
*/
|
*/
|
||||||
function initializeESM(isLoaderWorker = false) {
|
function initializeESM(forceDefaultLoader = false) {
|
||||||
_isLoaderWorker = isLoaderWorker;
|
_forceDefaultLoader = forceDefaultLoader;
|
||||||
initializeDefaultConditions();
|
initializeDefaultConditions();
|
||||||
// Setup per-isolate callbacks that locate data or callbacks that we keep
|
// Setup per-realm callbacks that locate data or callbacks that we keep
|
||||||
// track of for different ESM modules.
|
// track of for different ESM modules.
|
||||||
setInitializeImportMetaObjectCallback(initializeImportMetaObject);
|
setInitializeImportMetaObjectCallback(initializeImportMetaObject);
|
||||||
setImportModuleDynamicallyCallback(importModuleDynamicallyCallback);
|
setImportModuleDynamicallyCallback(importModuleDynamicallyCallback);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determine whether the current process is a loader worker.
|
* Determine whether custom loaders are disabled and it is forced to use the
|
||||||
* @returns {boolean} Whether the current process is a loader worker.
|
* default loader.
|
||||||
|
* @returns {boolean}
|
||||||
*/
|
*/
|
||||||
function isLoaderWorker() {
|
function forceDefaultLoader() {
|
||||||
return _isLoaderWorker;
|
return _forceDefaultLoader;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -251,10 +273,11 @@ async function initializeHooks() {
|
|||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
registerModule,
|
registerModule,
|
||||||
|
registerRealm,
|
||||||
initializeESM,
|
initializeESM,
|
||||||
initializeHooks,
|
initializeHooks,
|
||||||
getDefaultConditions,
|
getDefaultConditions,
|
||||||
getConditionsSet,
|
getConditionsSet,
|
||||||
loaderWorkerId: 'internal/modules/esm/worker',
|
loaderWorkerId: 'internal/modules/esm/worker',
|
||||||
isLoaderWorker,
|
forceDefaultLoader,
|
||||||
};
|
};
|
||||||
|
@ -67,6 +67,26 @@ function prepareWorkerThreadExecution() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function prepareShadowRealmExecution() {
|
||||||
|
const { registerRealm } = require('internal/modules/esm/utils');
|
||||||
|
// Patch the process object with legacy properties and normalizations.
|
||||||
|
// Do not expand argv1 as it is not available in ShadowRealm.
|
||||||
|
patchProcessObject(false);
|
||||||
|
setupDebugEnv();
|
||||||
|
|
||||||
|
// Disable custom loaders in ShadowRealm.
|
||||||
|
setupUserModules(true);
|
||||||
|
registerRealm(globalThis, {
|
||||||
|
__proto__: null,
|
||||||
|
importModuleDynamically: (specifier, _referrer, attributes) => {
|
||||||
|
// The handler for `ShadowRealm.prototype.importValue`.
|
||||||
|
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, attributes);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
function prepareExecution(options) {
|
function prepareExecution(options) {
|
||||||
const { expandArgv1, initializeModules, isMainThread } = options;
|
const { expandArgv1, initializeModules, isMainThread } = options;
|
||||||
|
|
||||||
@ -161,16 +181,17 @@ function setupSymbolDisposePolyfill() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function setupUserModules(isLoaderWorker = false) {
|
function setupUserModules(forceDefaultLoader = false) {
|
||||||
initializeCJSLoader();
|
initializeCJSLoader();
|
||||||
initializeESMLoader(isLoaderWorker);
|
initializeESMLoader(forceDefaultLoader);
|
||||||
const CJSLoader = require('internal/modules/cjs/loader');
|
const CJSLoader = require('internal/modules/cjs/loader');
|
||||||
assert(!CJSLoader.hasLoadedAnyUserCJSModule);
|
assert(!CJSLoader.hasLoadedAnyUserCJSModule);
|
||||||
// Loader workers are responsible for doing this themselves.
|
// Do not enable preload modules if custom loaders are disabled.
|
||||||
if (isLoaderWorker) {
|
// For example, loader workers are responsible for doing this themselves.
|
||||||
return;
|
// And preload modules are not supported in ShadowRealm as well.
|
||||||
|
if (!forceDefaultLoader) {
|
||||||
|
loadPreloadModules();
|
||||||
}
|
}
|
||||||
loadPreloadModules();
|
|
||||||
// Need to be done after --require setup.
|
// Need to be done after --require setup.
|
||||||
initializeFrozenIntrinsics();
|
initializeFrozenIntrinsics();
|
||||||
}
|
}
|
||||||
@ -701,9 +722,9 @@ function initializeCJSLoader() {
|
|||||||
initializeCJS();
|
initializeCJS();
|
||||||
}
|
}
|
||||||
|
|
||||||
function initializeESMLoader(isLoaderWorker) {
|
function initializeESMLoader(forceDefaultLoader) {
|
||||||
const { initializeESM } = require('internal/modules/esm/utils');
|
const { initializeESM } = require('internal/modules/esm/utils');
|
||||||
initializeESM(isLoaderWorker);
|
initializeESM(forceDefaultLoader);
|
||||||
|
|
||||||
// Patch the vm module when --experimental-vm-modules is on.
|
// Patch the vm module when --experimental-vm-modules is on.
|
||||||
// Please update the comments in vm.js when this block changes.
|
// Please update the comments in vm.js when this block changes.
|
||||||
@ -779,6 +800,7 @@ module.exports = {
|
|||||||
setupUserModules,
|
setupUserModules,
|
||||||
prepareMainThreadExecution,
|
prepareMainThreadExecution,
|
||||||
prepareWorkerThreadExecution,
|
prepareWorkerThreadExecution,
|
||||||
|
prepareShadowRealmExecution,
|
||||||
markBootstrapComplete,
|
markBootstrapComplete,
|
||||||
loadPreloadModules,
|
loadPreloadModules,
|
||||||
initializeFrozenIntrinsics,
|
initializeFrozenIntrinsics,
|
||||||
|
@ -372,8 +372,9 @@ void AsyncWrap::CreatePerContextProperties(Local<Object> target,
|
|||||||
Local<Value> unused,
|
Local<Value> unused,
|
||||||
Local<Context> context,
|
Local<Context> context,
|
||||||
void* priv) {
|
void* priv) {
|
||||||
Environment* env = Environment::GetCurrent(context);
|
Realm* realm = Realm::GetCurrent(context);
|
||||||
Isolate* isolate = env->isolate();
|
Environment* env = realm->env();
|
||||||
|
Isolate* isolate = realm->isolate();
|
||||||
HandleScope scope(isolate);
|
HandleScope scope(isolate);
|
||||||
|
|
||||||
PropertyAttribute ReadOnlyDontDelete =
|
PropertyAttribute ReadOnlyDontDelete =
|
||||||
@ -446,13 +447,16 @@ void AsyncWrap::CreatePerContextProperties(Local<Object> target,
|
|||||||
|
|
||||||
#undef FORCE_SET_TARGET_FIELD
|
#undef FORCE_SET_TARGET_FIELD
|
||||||
|
|
||||||
env->set_async_hooks_init_function(Local<Function>());
|
// TODO(legendecas): async hook functions are not realm-aware yet.
|
||||||
env->set_async_hooks_before_function(Local<Function>());
|
// This simply avoid overriding principal realm's functions when a
|
||||||
env->set_async_hooks_after_function(Local<Function>());
|
// ShadowRealm initializes the binding.
|
||||||
env->set_async_hooks_destroy_function(Local<Function>());
|
realm->set_async_hooks_init_function(Local<Function>());
|
||||||
env->set_async_hooks_promise_resolve_function(Local<Function>());
|
realm->set_async_hooks_before_function(Local<Function>());
|
||||||
env->set_async_hooks_callback_trampoline(Local<Function>());
|
realm->set_async_hooks_after_function(Local<Function>());
|
||||||
env->set_async_hooks_binding(target);
|
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(
|
void AsyncWrap::RegisterExternalReferences(
|
||||||
|
11
src/env.cc
11
src/env.cc
@ -1651,10 +1651,13 @@ void AsyncHooks::MemoryInfo(MemoryTracker* tracker) const {
|
|||||||
void AsyncHooks::grow_async_ids_stack() {
|
void AsyncHooks::grow_async_ids_stack() {
|
||||||
async_ids_stack_.reserve(async_ids_stack_.Length() * 3);
|
async_ids_stack_.reserve(async_ids_stack_.Length() * 3);
|
||||||
|
|
||||||
env()->async_hooks_binding()->Set(
|
env()
|
||||||
env()->context(),
|
->principal_realm()
|
||||||
env()->async_ids_stack_string(),
|
->async_hooks_binding()
|
||||||
async_ids_stack_.GetJSArray()).Check();
|
->Set(env()->context(),
|
||||||
|
env()->async_ids_stack_string(),
|
||||||
|
async_ids_stack_.GetJSArray())
|
||||||
|
.Check();
|
||||||
}
|
}
|
||||||
|
|
||||||
void AsyncHooks::FailWithCorruptedAsyncStack(double expected_async_id) {
|
void AsyncHooks::FailWithCorruptedAsyncStack(double expected_async_id) {
|
||||||
|
@ -39,6 +39,7 @@ using v8::MicrotaskQueue;
|
|||||||
using v8::Module;
|
using v8::Module;
|
||||||
using v8::ModuleRequest;
|
using v8::ModuleRequest;
|
||||||
using v8::Object;
|
using v8::Object;
|
||||||
|
using v8::ObjectTemplate;
|
||||||
using v8::PrimitiveArray;
|
using v8::PrimitiveArray;
|
||||||
using v8::Promise;
|
using v8::Promise;
|
||||||
using v8::ScriptCompiler;
|
using v8::ScriptCompiler;
|
||||||
@ -49,15 +50,17 @@ using v8::UnboundModuleScript;
|
|||||||
using v8::Undefined;
|
using v8::Undefined;
|
||||||
using v8::Value;
|
using v8::Value;
|
||||||
|
|
||||||
ModuleWrap::ModuleWrap(Environment* env,
|
ModuleWrap::ModuleWrap(Realm* realm,
|
||||||
Local<Object> object,
|
Local<Object> object,
|
||||||
Local<Module> module,
|
Local<Module> module,
|
||||||
Local<String> url,
|
Local<String> url,
|
||||||
Local<Object> context_object,
|
Local<Object> context_object,
|
||||||
Local<Value> synthetic_evaluation_step)
|
Local<Value> synthetic_evaluation_step)
|
||||||
: BaseObject(env, object),
|
: BaseObject(realm, object),
|
||||||
module_(env->isolate(), module),
|
module_(realm->isolate(), module),
|
||||||
module_hash_(module->GetIdentityHash()) {
|
module_hash_(module->GetIdentityHash()) {
|
||||||
|
realm->env()->hash_to_module_map.emplace(module_hash_, this);
|
||||||
|
|
||||||
object->SetInternalField(kModuleSlot, module);
|
object->SetInternalField(kModuleSlot, module);
|
||||||
object->SetInternalField(kURLSlot, url);
|
object->SetInternalField(kURLSlot, url);
|
||||||
object->SetInternalField(kSyntheticEvaluationStepsSlot,
|
object->SetInternalField(kSyntheticEvaluationStepsSlot,
|
||||||
@ -72,7 +75,6 @@ ModuleWrap::ModuleWrap(Environment* env,
|
|||||||
}
|
}
|
||||||
|
|
||||||
ModuleWrap::~ModuleWrap() {
|
ModuleWrap::~ModuleWrap() {
|
||||||
HandleScope scope(env()->isolate());
|
|
||||||
auto range = env()->hash_to_module_map.equal_range(module_hash_);
|
auto range = env()->hash_to_module_map.equal_range(module_hash_);
|
||||||
for (auto it = range.first; it != range.second; ++it) {
|
for (auto it = range.first; it != range.second; ++it) {
|
||||||
if (it->second == this) {
|
if (it->second == this) {
|
||||||
@ -107,8 +109,8 @@ void ModuleWrap::New(const FunctionCallbackInfo<Value>& args) {
|
|||||||
CHECK(args.IsConstructCall());
|
CHECK(args.IsConstructCall());
|
||||||
CHECK_GE(args.Length(), 3);
|
CHECK_GE(args.Length(), 3);
|
||||||
|
|
||||||
Environment* env = Environment::GetCurrent(args);
|
Realm* realm = Realm::GetCurrent(args);
|
||||||
Isolate* isolate = env->isolate();
|
Isolate* isolate = realm->isolate();
|
||||||
|
|
||||||
Local<Object> that = args.This();
|
Local<Object> that = args.This();
|
||||||
|
|
||||||
@ -122,7 +124,7 @@ void ModuleWrap::New(const FunctionCallbackInfo<Value>& args) {
|
|||||||
} else {
|
} else {
|
||||||
CHECK(args[1]->IsObject());
|
CHECK(args[1]->IsObject());
|
||||||
contextify_context = ContextifyContext::ContextFromContextifiedSandbox(
|
contextify_context = ContextifyContext::ContextFromContextifiedSandbox(
|
||||||
env, args[1].As<Object>());
|
realm->env(), args[1].As<Object>());
|
||||||
CHECK_NOT_NULL(contextify_context);
|
CHECK_NOT_NULL(contextify_context);
|
||||||
context = contextify_context->context();
|
context = contextify_context->context();
|
||||||
}
|
}
|
||||||
@ -148,8 +150,8 @@ void ModuleWrap::New(const FunctionCallbackInfo<Value>& args) {
|
|||||||
Local<Symbol> id_symbol = Symbol::New(isolate, url);
|
Local<Symbol> id_symbol = Symbol::New(isolate, url);
|
||||||
host_defined_options->Set(isolate, HostDefinedOptions::kID, id_symbol);
|
host_defined_options->Set(isolate, HostDefinedOptions::kID, id_symbol);
|
||||||
|
|
||||||
ShouldNotAbortOnUncaughtScope no_abort_scope(env);
|
ShouldNotAbortOnUncaughtScope no_abort_scope(realm->env());
|
||||||
TryCatchScope try_catch(env);
|
TryCatchScope try_catch(realm->env());
|
||||||
|
|
||||||
Local<Module> module;
|
Local<Module> module;
|
||||||
|
|
||||||
@ -206,7 +208,9 @@ void ModuleWrap::New(const FunctionCallbackInfo<Value>& args) {
|
|||||||
if (try_catch.HasCaught() && !try_catch.HasTerminated()) {
|
if (try_catch.HasCaught() && !try_catch.HasTerminated()) {
|
||||||
CHECK(!try_catch.Message().IsEmpty());
|
CHECK(!try_catch.Message().IsEmpty());
|
||||||
CHECK(!try_catch.Exception().IsEmpty());
|
CHECK(!try_catch.Exception().IsEmpty());
|
||||||
AppendExceptionLine(env, try_catch.Exception(), try_catch.Message(),
|
AppendExceptionLine(realm->env(),
|
||||||
|
try_catch.Exception(),
|
||||||
|
try_catch.Message(),
|
||||||
ErrorHandlingMode::MODULE_ERROR);
|
ErrorHandlingMode::MODULE_ERROR);
|
||||||
try_catch.ReThrow();
|
try_catch.ReThrow();
|
||||||
}
|
}
|
||||||
@ -215,18 +219,21 @@ void ModuleWrap::New(const FunctionCallbackInfo<Value>& args) {
|
|||||||
if (options == ScriptCompiler::kConsumeCodeCache &&
|
if (options == ScriptCompiler::kConsumeCodeCache &&
|
||||||
source.GetCachedData()->rejected) {
|
source.GetCachedData()->rejected) {
|
||||||
THROW_ERR_VM_MODULE_CACHED_DATA_REJECTED(
|
THROW_ERR_VM_MODULE_CACHED_DATA_REJECTED(
|
||||||
env, "cachedData buffer was rejected");
|
realm, "cachedData buffer was rejected");
|
||||||
try_catch.ReThrow();
|
try_catch.ReThrow();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!that->Set(context, env->url_string(), url).FromMaybe(false)) {
|
if (!that->Set(context, realm->isolate_data()->url_string(), url)
|
||||||
|
.FromMaybe(false)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (that->SetPrivate(context, env->host_defined_option_symbol(), id_symbol)
|
if (that->SetPrivate(context,
|
||||||
|
realm->isolate_data()->host_defined_option_symbol(),
|
||||||
|
id_symbol)
|
||||||
.IsNothing()) {
|
.IsNothing()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -236,28 +243,26 @@ void ModuleWrap::New(const FunctionCallbackInfo<Value>& args) {
|
|||||||
// be stored in an internal field.
|
// be stored in an internal field.
|
||||||
Local<Object> context_object = context->GetExtrasBindingObject();
|
Local<Object> context_object = context->GetExtrasBindingObject();
|
||||||
Local<Value> synthetic_evaluation_step =
|
Local<Value> synthetic_evaluation_step =
|
||||||
synthetic ? args[3] : Undefined(env->isolate()).As<v8::Value>();
|
synthetic ? args[3] : Undefined(realm->isolate()).As<v8::Value>();
|
||||||
|
|
||||||
ModuleWrap* obj = new ModuleWrap(
|
ModuleWrap* obj = new ModuleWrap(
|
||||||
env, that, module, url, context_object, synthetic_evaluation_step);
|
realm, that, module, url, context_object, synthetic_evaluation_step);
|
||||||
|
|
||||||
obj->contextify_context_ = contextify_context;
|
obj->contextify_context_ = contextify_context;
|
||||||
|
|
||||||
env->hash_to_module_map.emplace(module->GetIdentityHash(), obj);
|
|
||||||
|
|
||||||
that->SetIntegrityLevel(context, IntegrityLevel::kFrozen);
|
that->SetIntegrityLevel(context, IntegrityLevel::kFrozen);
|
||||||
args.GetReturnValue().Set(that);
|
args.GetReturnValue().Set(that);
|
||||||
}
|
}
|
||||||
|
|
||||||
static Local<Object> createImportAttributesContainer(
|
static Local<Object> createImportAttributesContainer(
|
||||||
Environment* env, Isolate* isolate, Local<FixedArray> raw_attributes) {
|
Realm* realm, Isolate* isolate, Local<FixedArray> raw_attributes) {
|
||||||
Local<Object> attributes =
|
Local<Object> attributes =
|
||||||
Object::New(isolate, v8::Null(env->isolate()), nullptr, nullptr, 0);
|
Object::New(isolate, v8::Null(isolate), nullptr, nullptr, 0);
|
||||||
for (int i = 0; i < raw_attributes->Length(); i += 3) {
|
for (int i = 0; i < raw_attributes->Length(); i += 3) {
|
||||||
attributes
|
attributes
|
||||||
->Set(env->context(),
|
->Set(realm->context(),
|
||||||
raw_attributes->Get(env->context(), i).As<String>(),
|
raw_attributes->Get(realm->context(), i).As<String>(),
|
||||||
raw_attributes->Get(env->context(), i + 1).As<Value>())
|
raw_attributes->Get(realm->context(), i + 1).As<Value>())
|
||||||
.ToChecked();
|
.ToChecked();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -265,7 +270,7 @@ static Local<Object> createImportAttributesContainer(
|
|||||||
}
|
}
|
||||||
|
|
||||||
void ModuleWrap::Link(const FunctionCallbackInfo<Value>& args) {
|
void ModuleWrap::Link(const FunctionCallbackInfo<Value>& args) {
|
||||||
Environment* env = Environment::GetCurrent(args);
|
Realm* realm = Realm::GetCurrent(args);
|
||||||
Isolate* isolate = args.GetIsolate();
|
Isolate* isolate = args.GetIsolate();
|
||||||
|
|
||||||
CHECK_EQ(args.Length(), 1);
|
CHECK_EQ(args.Length(), 1);
|
||||||
@ -292,14 +297,14 @@ void ModuleWrap::Link(const FunctionCallbackInfo<Value>& args) {
|
|||||||
// call the dependency resolve callbacks
|
// call the dependency resolve callbacks
|
||||||
for (int i = 0; i < module_requests_length; i++) {
|
for (int i = 0; i < module_requests_length; i++) {
|
||||||
Local<ModuleRequest> module_request =
|
Local<ModuleRequest> module_request =
|
||||||
module_requests->Get(env->context(), i).As<ModuleRequest>();
|
module_requests->Get(realm->context(), i).As<ModuleRequest>();
|
||||||
Local<String> specifier = module_request->GetSpecifier();
|
Local<String> specifier = module_request->GetSpecifier();
|
||||||
Utf8Value specifier_utf8(env->isolate(), specifier);
|
Utf8Value specifier_utf8(realm->isolate(), specifier);
|
||||||
std::string specifier_std(*specifier_utf8, specifier_utf8.length());
|
std::string specifier_std(*specifier_utf8, specifier_utf8.length());
|
||||||
|
|
||||||
Local<FixedArray> raw_attributes = module_request->GetImportAssertions();
|
Local<FixedArray> raw_attributes = module_request->GetImportAssertions();
|
||||||
Local<Object> attributes =
|
Local<Object> attributes =
|
||||||
createImportAttributesContainer(env, isolate, raw_attributes);
|
createImportAttributesContainer(realm, isolate, raw_attributes);
|
||||||
|
|
||||||
Local<Value> argv[] = {
|
Local<Value> argv[] = {
|
||||||
specifier,
|
specifier,
|
||||||
@ -315,11 +320,11 @@ void ModuleWrap::Link(const FunctionCallbackInfo<Value>& args) {
|
|||||||
maybe_resolve_return_value.ToLocalChecked();
|
maybe_resolve_return_value.ToLocalChecked();
|
||||||
if (!resolve_return_value->IsPromise()) {
|
if (!resolve_return_value->IsPromise()) {
|
||||||
THROW_ERR_VM_MODULE_LINK_FAILURE(
|
THROW_ERR_VM_MODULE_LINK_FAILURE(
|
||||||
env, "request for '%s' did not return promise", specifier_std);
|
realm, "request for '%s' did not return promise", specifier_std);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Local<Promise> resolve_promise = resolve_return_value.As<Promise>();
|
Local<Promise> resolve_promise = resolve_return_value.As<Promise>();
|
||||||
obj->resolve_cache_[specifier_std].Reset(env->isolate(), resolve_promise);
|
obj->resolve_cache_[specifier_std].Reset(isolate, resolve_promise);
|
||||||
|
|
||||||
promises[i] = resolve_promise;
|
promises[i] = resolve_promise;
|
||||||
}
|
}
|
||||||
@ -329,13 +334,13 @@ void ModuleWrap::Link(const FunctionCallbackInfo<Value>& args) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void ModuleWrap::Instantiate(const FunctionCallbackInfo<Value>& args) {
|
void ModuleWrap::Instantiate(const FunctionCallbackInfo<Value>& args) {
|
||||||
Environment* env = Environment::GetCurrent(args);
|
Realm* realm = Realm::GetCurrent(args);
|
||||||
Isolate* isolate = args.GetIsolate();
|
Isolate* isolate = args.GetIsolate();
|
||||||
ModuleWrap* obj;
|
ModuleWrap* obj;
|
||||||
ASSIGN_OR_RETURN_UNWRAP(&obj, args.This());
|
ASSIGN_OR_RETURN_UNWRAP(&obj, args.This());
|
||||||
Local<Context> context = obj->context();
|
Local<Context> context = obj->context();
|
||||||
Local<Module> module = obj->module_.Get(isolate);
|
Local<Module> module = obj->module_.Get(isolate);
|
||||||
TryCatchScope try_catch(env);
|
TryCatchScope try_catch(realm->env());
|
||||||
USE(module->InstantiateModule(context, ResolveModuleCallback));
|
USE(module->InstantiateModule(context, ResolveModuleCallback));
|
||||||
|
|
||||||
// clear resolve cache on instantiate
|
// clear resolve cache on instantiate
|
||||||
@ -344,7 +349,9 @@ void ModuleWrap::Instantiate(const FunctionCallbackInfo<Value>& args) {
|
|||||||
if (try_catch.HasCaught() && !try_catch.HasTerminated()) {
|
if (try_catch.HasCaught() && !try_catch.HasTerminated()) {
|
||||||
CHECK(!try_catch.Message().IsEmpty());
|
CHECK(!try_catch.Message().IsEmpty());
|
||||||
CHECK(!try_catch.Exception().IsEmpty());
|
CHECK(!try_catch.Exception().IsEmpty());
|
||||||
AppendExceptionLine(env, try_catch.Exception(), try_catch.Message(),
|
AppendExceptionLine(realm->env(),
|
||||||
|
try_catch.Exception(),
|
||||||
|
try_catch.Message(),
|
||||||
ErrorHandlingMode::MODULE_ERROR);
|
ErrorHandlingMode::MODULE_ERROR);
|
||||||
try_catch.ReThrow();
|
try_catch.ReThrow();
|
||||||
return;
|
return;
|
||||||
@ -352,8 +359,8 @@ void ModuleWrap::Instantiate(const FunctionCallbackInfo<Value>& args) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void ModuleWrap::Evaluate(const FunctionCallbackInfo<Value>& args) {
|
void ModuleWrap::Evaluate(const FunctionCallbackInfo<Value>& args) {
|
||||||
Environment* env = Environment::GetCurrent(args);
|
Realm* realm = Realm::GetCurrent(args);
|
||||||
Isolate* isolate = env->isolate();
|
Isolate* isolate = realm->isolate();
|
||||||
ModuleWrap* obj;
|
ModuleWrap* obj;
|
||||||
ASSIGN_OR_RETURN_UNWRAP(&obj, args.This());
|
ASSIGN_OR_RETURN_UNWRAP(&obj, args.This());
|
||||||
Local<Context> context = obj->context();
|
Local<Context> context = obj->context();
|
||||||
@ -368,14 +375,14 @@ void ModuleWrap::Evaluate(const FunctionCallbackInfo<Value>& args) {
|
|||||||
CHECK_EQ(args.Length(), 2);
|
CHECK_EQ(args.Length(), 2);
|
||||||
|
|
||||||
CHECK(args[0]->IsNumber());
|
CHECK(args[0]->IsNumber());
|
||||||
int64_t timeout = args[0]->IntegerValue(env->context()).FromJust();
|
int64_t timeout = args[0]->IntegerValue(realm->context()).FromJust();
|
||||||
|
|
||||||
CHECK(args[1]->IsBoolean());
|
CHECK(args[1]->IsBoolean());
|
||||||
bool break_on_sigint = args[1]->IsTrue();
|
bool break_on_sigint = args[1]->IsTrue();
|
||||||
|
|
||||||
ShouldNotAbortOnUncaughtScope no_abort_scope(env);
|
ShouldNotAbortOnUncaughtScope no_abort_scope(realm->env());
|
||||||
TryCatchScope try_catch(env);
|
TryCatchScope try_catch(realm->env());
|
||||||
Isolate::SafeForTerminationScope safe_for_termination(env->isolate());
|
Isolate::SafeForTerminationScope safe_for_termination(isolate);
|
||||||
|
|
||||||
bool timed_out = false;
|
bool timed_out = false;
|
||||||
bool received_signal = false;
|
bool received_signal = false;
|
||||||
@ -406,16 +413,15 @@ void ModuleWrap::Evaluate(const FunctionCallbackInfo<Value>& args) {
|
|||||||
|
|
||||||
// Convert the termination exception into a regular exception.
|
// Convert the termination exception into a regular exception.
|
||||||
if (timed_out || received_signal) {
|
if (timed_out || received_signal) {
|
||||||
if (!env->is_main_thread() && env->is_stopping())
|
if (!realm->env()->is_main_thread() && realm->env()->is_stopping()) return;
|
||||||
return;
|
isolate->CancelTerminateExecution();
|
||||||
env->isolate()->CancelTerminateExecution();
|
|
||||||
// It is possible that execution was terminated by another timeout in
|
// It is possible that execution was terminated by another timeout in
|
||||||
// which this timeout is nested, so check whether one of the watchdogs
|
// which this timeout is nested, so check whether one of the watchdogs
|
||||||
// from this invocation is responsible for termination.
|
// from this invocation is responsible for termination.
|
||||||
if (timed_out) {
|
if (timed_out) {
|
||||||
THROW_ERR_SCRIPT_EXECUTION_TIMEOUT(env, timeout);
|
THROW_ERR_SCRIPT_EXECUTION_TIMEOUT(realm->env(), timeout);
|
||||||
} else if (received_signal) {
|
} else if (received_signal) {
|
||||||
THROW_ERR_SCRIPT_EXECUTION_INTERRUPTED(env);
|
THROW_ERR_SCRIPT_EXECUTION_INTERRUPTED(realm->env());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -429,7 +435,7 @@ void ModuleWrap::Evaluate(const FunctionCallbackInfo<Value>& args) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void ModuleWrap::GetNamespace(const FunctionCallbackInfo<Value>& args) {
|
void ModuleWrap::GetNamespace(const FunctionCallbackInfo<Value>& args) {
|
||||||
Environment* env = Environment::GetCurrent(args);
|
Realm* realm = Realm::GetCurrent(args);
|
||||||
Isolate* isolate = args.GetIsolate();
|
Isolate* isolate = args.GetIsolate();
|
||||||
ModuleWrap* obj;
|
ModuleWrap* obj;
|
||||||
ASSIGN_OR_RETURN_UNWRAP(&obj, args.This());
|
ASSIGN_OR_RETURN_UNWRAP(&obj, args.This());
|
||||||
@ -439,7 +445,7 @@ void ModuleWrap::GetNamespace(const FunctionCallbackInfo<Value>& args) {
|
|||||||
switch (module->GetStatus()) {
|
switch (module->GetStatus()) {
|
||||||
case v8::Module::Status::kUninstantiated:
|
case v8::Module::Status::kUninstantiated:
|
||||||
case v8::Module::Status::kInstantiating:
|
case v8::Module::Status::kInstantiating:
|
||||||
return env->ThrowError(
|
return realm->env()->ThrowError(
|
||||||
"cannot get namespace, module has not been instantiated");
|
"cannot get namespace, module has not been instantiated");
|
||||||
case v8::Module::Status::kInstantiated:
|
case v8::Module::Status::kInstantiated:
|
||||||
case v8::Module::Status::kEvaluating:
|
case v8::Module::Status::kEvaluating:
|
||||||
@ -466,11 +472,11 @@ void ModuleWrap::GetStatus(const FunctionCallbackInfo<Value>& args) {
|
|||||||
|
|
||||||
void ModuleWrap::GetStaticDependencySpecifiers(
|
void ModuleWrap::GetStaticDependencySpecifiers(
|
||||||
const FunctionCallbackInfo<Value>& args) {
|
const FunctionCallbackInfo<Value>& args) {
|
||||||
Environment* env = Environment::GetCurrent(args);
|
Realm* realm = Realm::GetCurrent(args);
|
||||||
ModuleWrap* obj;
|
ModuleWrap* obj;
|
||||||
ASSIGN_OR_RETURN_UNWRAP(&obj, args.This());
|
ASSIGN_OR_RETURN_UNWRAP(&obj, args.This());
|
||||||
|
|
||||||
Local<Module> module = obj->module_.Get(env->isolate());
|
Local<Module> module = obj->module_.Get(realm->isolate());
|
||||||
|
|
||||||
Local<FixedArray> module_requests = module->GetModuleRequests();
|
Local<FixedArray> module_requests = module->GetModuleRequests();
|
||||||
int count = module_requests->Length();
|
int count = module_requests->Length();
|
||||||
@ -479,12 +485,12 @@ void ModuleWrap::GetStaticDependencySpecifiers(
|
|||||||
|
|
||||||
for (int i = 0; i < count; i++) {
|
for (int i = 0; i < count; i++) {
|
||||||
Local<ModuleRequest> module_request =
|
Local<ModuleRequest> module_request =
|
||||||
module_requests->Get(env->context(), i).As<ModuleRequest>();
|
module_requests->Get(realm->context(), i).As<ModuleRequest>();
|
||||||
specifiers[i] = module_request->GetSpecifier();
|
specifiers[i] = module_request->GetSpecifier();
|
||||||
}
|
}
|
||||||
|
|
||||||
args.GetReturnValue().Set(
|
args.GetReturnValue().Set(
|
||||||
Array::New(env->isolate(), specifiers.out(), count));
|
Array::New(realm->isolate(), specifiers.out(), count));
|
||||||
}
|
}
|
||||||
|
|
||||||
void ModuleWrap::GetError(const FunctionCallbackInfo<Value>& args) {
|
void ModuleWrap::GetError(const FunctionCallbackInfo<Value>& args) {
|
||||||
@ -501,15 +507,13 @@ MaybeLocal<Module> ModuleWrap::ResolveModuleCallback(
|
|||||||
Local<String> specifier,
|
Local<String> specifier,
|
||||||
Local<FixedArray> import_attributes,
|
Local<FixedArray> import_attributes,
|
||||||
Local<Module> referrer) {
|
Local<Module> referrer) {
|
||||||
|
Isolate* isolate = context->GetIsolate();
|
||||||
Environment* env = Environment::GetCurrent(context);
|
Environment* env = Environment::GetCurrent(context);
|
||||||
if (env == nullptr) {
|
if (env == nullptr) {
|
||||||
Isolate* isolate = context->GetIsolate();
|
|
||||||
THROW_ERR_EXECUTION_ENVIRONMENT_NOT_AVAILABLE(isolate);
|
THROW_ERR_EXECUTION_ENVIRONMENT_NOT_AVAILABLE(isolate);
|
||||||
return MaybeLocal<Module>();
|
return MaybeLocal<Module>();
|
||||||
}
|
}
|
||||||
|
|
||||||
Isolate* isolate = env->isolate();
|
|
||||||
|
|
||||||
Utf8Value specifier_utf8(isolate, specifier);
|
Utf8Value specifier_utf8(isolate, specifier);
|
||||||
std::string specifier_std(*specifier_utf8, specifier_utf8.length());
|
std::string specifier_std(*specifier_utf8, specifier_utf8.length());
|
||||||
|
|
||||||
@ -559,11 +563,16 @@ static MaybeLocal<Promise> ImportModuleDynamically(
|
|||||||
THROW_ERR_EXECUTION_ENVIRONMENT_NOT_AVAILABLE(isolate);
|
THROW_ERR_EXECUTION_ENVIRONMENT_NOT_AVAILABLE(isolate);
|
||||||
return MaybeLocal<Promise>();
|
return MaybeLocal<Promise>();
|
||||||
}
|
}
|
||||||
|
Realm* realm = Realm::GetCurrent(context);
|
||||||
|
if (realm == nullptr) {
|
||||||
|
// Fallback to the principal realm if it's in a vm context.
|
||||||
|
realm = env->principal_realm();
|
||||||
|
}
|
||||||
|
|
||||||
EscapableHandleScope handle_scope(isolate);
|
EscapableHandleScope handle_scope(isolate);
|
||||||
|
|
||||||
Local<Function> import_callback =
|
Local<Function> import_callback =
|
||||||
env->host_import_module_dynamically_callback();
|
realm->host_import_module_dynamically_callback();
|
||||||
Local<Value> id;
|
Local<Value> id;
|
||||||
|
|
||||||
Local<FixedArray> options = host_defined_options.As<FixedArray>();
|
Local<FixedArray> options = host_defined_options.As<FixedArray>();
|
||||||
@ -579,7 +588,7 @@ static MaybeLocal<Promise> ImportModuleDynamically(
|
|||||||
}
|
}
|
||||||
|
|
||||||
Local<Object> attributes =
|
Local<Object> attributes =
|
||||||
createImportAttributesContainer(env, isolate, import_attributes);
|
createImportAttributesContainer(realm, isolate, import_attributes);
|
||||||
|
|
||||||
Local<Value> import_args[] = {
|
Local<Value> import_args[] = {
|
||||||
id,
|
id,
|
||||||
@ -603,13 +612,13 @@ static MaybeLocal<Promise> ImportModuleDynamically(
|
|||||||
void ModuleWrap::SetImportModuleDynamicallyCallback(
|
void ModuleWrap::SetImportModuleDynamicallyCallback(
|
||||||
const FunctionCallbackInfo<Value>& args) {
|
const FunctionCallbackInfo<Value>& args) {
|
||||||
Isolate* isolate = args.GetIsolate();
|
Isolate* isolate = args.GetIsolate();
|
||||||
Environment* env = Environment::GetCurrent(args);
|
Realm* realm = Realm::GetCurrent(args);
|
||||||
HandleScope handle_scope(isolate);
|
HandleScope handle_scope(isolate);
|
||||||
|
|
||||||
CHECK_EQ(args.Length(), 1);
|
CHECK_EQ(args.Length(), 1);
|
||||||
CHECK(args[0]->IsFunction());
|
CHECK(args[0]->IsFunction());
|
||||||
Local<Function> import_callback = args[0].As<Function>();
|
Local<Function> import_callback = args[0].As<Function>();
|
||||||
env->set_host_import_module_dynamically_callback(import_callback);
|
realm->set_host_import_module_dynamically_callback(import_callback);
|
||||||
|
|
||||||
isolate->SetHostImportModuleDynamicallyCallback(ImportModuleDynamically);
|
isolate->SetHostImportModuleDynamicallyCallback(ImportModuleDynamically);
|
||||||
}
|
}
|
||||||
@ -624,10 +633,15 @@ void ModuleWrap::HostInitializeImportMetaObjectCallback(
|
|||||||
if (module_wrap == nullptr) {
|
if (module_wrap == nullptr) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
Realm* realm = Realm::GetCurrent(context);
|
||||||
|
if (realm == nullptr) {
|
||||||
|
// Fallback to the principal realm if it's in a vm context.
|
||||||
|
realm = env->principal_realm();
|
||||||
|
}
|
||||||
|
|
||||||
Local<Object> wrap = module_wrap->object();
|
Local<Object> wrap = module_wrap->object();
|
||||||
Local<Function> callback =
|
Local<Function> callback =
|
||||||
env->host_initialize_import_meta_object_callback();
|
realm->host_initialize_import_meta_object_callback();
|
||||||
Local<Value> id;
|
Local<Value> id;
|
||||||
if (!wrap->GetPrivate(context, env->host_defined_option_symbol())
|
if (!wrap->GetPrivate(context, env->host_defined_option_symbol())
|
||||||
.ToLocal(&id)) {
|
.ToLocal(&id)) {
|
||||||
@ -637,7 +651,7 @@ void ModuleWrap::HostInitializeImportMetaObjectCallback(
|
|||||||
Local<Value> args[] = {id, meta};
|
Local<Value> args[] = {id, meta};
|
||||||
TryCatchScope try_catch(env);
|
TryCatchScope try_catch(env);
|
||||||
USE(callback->Call(
|
USE(callback->Call(
|
||||||
context, Undefined(env->isolate()), arraysize(args), args));
|
context, Undefined(realm->isolate()), arraysize(args), args));
|
||||||
if (try_catch.HasCaught() && !try_catch.HasTerminated()) {
|
if (try_catch.HasCaught() && !try_catch.HasTerminated()) {
|
||||||
try_catch.ReThrow();
|
try_catch.ReThrow();
|
||||||
}
|
}
|
||||||
@ -645,13 +659,13 @@ void ModuleWrap::HostInitializeImportMetaObjectCallback(
|
|||||||
|
|
||||||
void ModuleWrap::SetInitializeImportMetaObjectCallback(
|
void ModuleWrap::SetInitializeImportMetaObjectCallback(
|
||||||
const FunctionCallbackInfo<Value>& args) {
|
const FunctionCallbackInfo<Value>& args) {
|
||||||
Environment* env = Environment::GetCurrent(args);
|
Realm* realm = Realm::GetCurrent(args);
|
||||||
Isolate* isolate = env->isolate();
|
Isolate* isolate = realm->isolate();
|
||||||
|
|
||||||
CHECK_EQ(args.Length(), 1);
|
CHECK_EQ(args.Length(), 1);
|
||||||
CHECK(args[0]->IsFunction());
|
CHECK(args[0]->IsFunction());
|
||||||
Local<Function> import_meta_callback = args[0].As<Function>();
|
Local<Function> import_meta_callback = args[0].As<Function>();
|
||||||
env->set_host_initialize_import_meta_object_callback(import_meta_callback);
|
realm->set_host_initialize_import_meta_object_callback(import_meta_callback);
|
||||||
|
|
||||||
isolate->SetHostInitializeImportMetaObjectCallback(
|
isolate->SetHostInitializeImportMetaObjectCallback(
|
||||||
HostInitializeImportMetaObjectCallback);
|
HostInitializeImportMetaObjectCallback);
|
||||||
@ -742,12 +756,9 @@ void ModuleWrap::CreateCachedData(const FunctionCallbackInfo<Value>& args) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ModuleWrap::Initialize(Local<Object> target,
|
void ModuleWrap::CreatePerIsolateProperties(IsolateData* isolate_data,
|
||||||
Local<Value> unused,
|
Local<ObjectTemplate> target) {
|
||||||
Local<Context> context,
|
Isolate* isolate = isolate_data->isolate();
|
||||||
void* priv) {
|
|
||||||
Environment* env = Environment::GetCurrent(context);
|
|
||||||
Isolate* isolate = env->isolate();
|
|
||||||
|
|
||||||
Local<FunctionTemplate> tpl = NewFunctionTemplate(isolate, New);
|
Local<FunctionTemplate> tpl = NewFunctionTemplate(isolate, New);
|
||||||
tpl->InstanceTemplate()->SetInternalFieldCount(
|
tpl->InstanceTemplate()->SetInternalFieldCount(
|
||||||
@ -767,28 +778,36 @@ void ModuleWrap::Initialize(Local<Object> target,
|
|||||||
"getStaticDependencySpecifiers",
|
"getStaticDependencySpecifiers",
|
||||||
GetStaticDependencySpecifiers);
|
GetStaticDependencySpecifiers);
|
||||||
|
|
||||||
SetConstructorFunction(context, target, "ModuleWrap", tpl);
|
SetConstructorFunction(isolate, target, "ModuleWrap", tpl);
|
||||||
|
|
||||||
SetMethod(context,
|
SetMethod(isolate,
|
||||||
target,
|
target,
|
||||||
"setImportModuleDynamicallyCallback",
|
"setImportModuleDynamicallyCallback",
|
||||||
SetImportModuleDynamicallyCallback);
|
SetImportModuleDynamicallyCallback);
|
||||||
SetMethod(context,
|
SetMethod(isolate,
|
||||||
target,
|
target,
|
||||||
"setInitializeImportMetaObjectCallback",
|
"setInitializeImportMetaObjectCallback",
|
||||||
SetInitializeImportMetaObjectCallback);
|
SetInitializeImportMetaObjectCallback);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ModuleWrap::CreatePerContextProperties(Local<Object> target,
|
||||||
|
Local<Value> unused,
|
||||||
|
Local<Context> context,
|
||||||
|
void* priv) {
|
||||||
|
Realm* realm = Realm::GetCurrent(context);
|
||||||
|
Isolate* isolate = realm->isolate();
|
||||||
#define V(name) \
|
#define V(name) \
|
||||||
target->Set(context, \
|
target \
|
||||||
FIXED_ONE_BYTE_STRING(env->isolate(), #name), \
|
->Set(context, \
|
||||||
Integer::New(env->isolate(), Module::Status::name)) \
|
FIXED_ONE_BYTE_STRING(isolate, #name), \
|
||||||
.FromJust()
|
Integer::New(isolate, Module::Status::name)) \
|
||||||
V(kUninstantiated);
|
.FromJust()
|
||||||
V(kInstantiating);
|
V(kUninstantiated);
|
||||||
V(kInstantiated);
|
V(kInstantiating);
|
||||||
V(kEvaluating);
|
V(kInstantiated);
|
||||||
V(kEvaluated);
|
V(kEvaluating);
|
||||||
V(kErrored);
|
V(kEvaluated);
|
||||||
|
V(kErrored);
|
||||||
#undef V
|
#undef V
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -812,7 +831,9 @@ void ModuleWrap::RegisterExternalReferences(
|
|||||||
} // namespace loader
|
} // namespace loader
|
||||||
} // namespace node
|
} // namespace node
|
||||||
|
|
||||||
NODE_BINDING_CONTEXT_AWARE_INTERNAL(module_wrap,
|
NODE_BINDING_CONTEXT_AWARE_INTERNAL(
|
||||||
node::loader::ModuleWrap::Initialize)
|
module_wrap, node::loader::ModuleWrap::CreatePerContextProperties)
|
||||||
|
NODE_BINDING_PER_ISOLATE_INIT(
|
||||||
|
module_wrap, node::loader::ModuleWrap::CreatePerIsolateProperties)
|
||||||
NODE_BINDING_EXTERNAL_REFERENCE(
|
NODE_BINDING_EXTERNAL_REFERENCE(
|
||||||
module_wrap, node::loader::ModuleWrap::RegisterExternalReferences)
|
module_wrap, node::loader::ModuleWrap::RegisterExternalReferences)
|
||||||
|
@ -10,6 +10,7 @@
|
|||||||
|
|
||||||
namespace node {
|
namespace node {
|
||||||
|
|
||||||
|
class IsolateData;
|
||||||
class Environment;
|
class Environment;
|
||||||
class ExternalReferenceRegistry;
|
class ExternalReferenceRegistry;
|
||||||
|
|
||||||
@ -40,10 +41,12 @@ class ModuleWrap : public BaseObject {
|
|||||||
kInternalFieldCount
|
kInternalFieldCount
|
||||||
};
|
};
|
||||||
|
|
||||||
static void Initialize(v8::Local<v8::Object> target,
|
static void CreatePerIsolateProperties(IsolateData* isolate_data,
|
||||||
v8::Local<v8::Value> unused,
|
v8::Local<v8::ObjectTemplate> target);
|
||||||
v8::Local<v8::Context> context,
|
static void CreatePerContextProperties(v8::Local<v8::Object> target,
|
||||||
void* priv);
|
v8::Local<v8::Value> unused,
|
||||||
|
v8::Local<v8::Context> context,
|
||||||
|
void* priv);
|
||||||
static void RegisterExternalReferences(ExternalReferenceRegistry* registry);
|
static void RegisterExternalReferences(ExternalReferenceRegistry* registry);
|
||||||
static void HostInitializeImportMetaObjectCallback(
|
static void HostInitializeImportMetaObjectCallback(
|
||||||
v8::Local<v8::Context> context,
|
v8::Local<v8::Context> context,
|
||||||
@ -66,7 +69,7 @@ class ModuleWrap : public BaseObject {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ModuleWrap(Environment* env,
|
ModuleWrap(Realm* realm,
|
||||||
v8::Local<v8::Object> object,
|
v8::Local<v8::Object> object,
|
||||||
v8::Local<v8::Module> module,
|
v8::Local<v8::Module> module,
|
||||||
v8::Local<v8::String> url,
|
v8::Local<v8::String> url,
|
||||||
|
@ -40,6 +40,7 @@ static_assert(static_cast<int>(NM_F_LINKED) ==
|
|||||||
V(fs_dir) \
|
V(fs_dir) \
|
||||||
V(messaging) \
|
V(messaging) \
|
||||||
V(mksnapshot) \
|
V(mksnapshot) \
|
||||||
|
V(module_wrap) \
|
||||||
V(performance) \
|
V(performance) \
|
||||||
V(process_methods) \
|
V(process_methods) \
|
||||||
V(timers) \
|
V(timers) \
|
||||||
|
@ -123,6 +123,10 @@ void AppendExceptionLine(Environment* env,
|
|||||||
inline void THROW_##code( \
|
inline void THROW_##code( \
|
||||||
Environment* env, const char* format, Args&&... args) { \
|
Environment* env, const char* format, Args&&... args) { \
|
||||||
THROW_##code(env->isolate(), format, std::forward<Args>(args)...); \
|
THROW_##code(env->isolate(), format, std::forward<Args>(args)...); \
|
||||||
|
} \
|
||||||
|
template <typename... Args> \
|
||||||
|
inline void THROW_##code(Realm* realm, const char* format, Args&&... args) { \
|
||||||
|
THROW_##code(realm->isolate(), format, std::forward<Args>(args)...); \
|
||||||
}
|
}
|
||||||
ERRORS_WITH_CODE(V)
|
ERRORS_WITH_CODE(V)
|
||||||
#undef V
|
#undef V
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#include "node_shadow_realm.h"
|
#include "node_shadow_realm.h"
|
||||||
#include "env-inl.h"
|
#include "env-inl.h"
|
||||||
#include "node_errors.h"
|
#include "node_errors.h"
|
||||||
|
#include "node_process.h"
|
||||||
|
|
||||||
namespace node {
|
namespace node {
|
||||||
namespace shadow_realm {
|
namespace shadow_realm {
|
||||||
@ -9,6 +10,8 @@ using v8::EscapableHandleScope;
|
|||||||
using v8::HandleScope;
|
using v8::HandleScope;
|
||||||
using v8::Local;
|
using v8::Local;
|
||||||
using v8::MaybeLocal;
|
using v8::MaybeLocal;
|
||||||
|
using v8::Object;
|
||||||
|
using v8::String;
|
||||||
using v8::Value;
|
using v8::Value;
|
||||||
|
|
||||||
using TryCatchScope = node::errors::TryCatchScope;
|
using TryCatchScope = node::errors::TryCatchScope;
|
||||||
@ -16,6 +19,11 @@ using TryCatchScope = node::errors::TryCatchScope;
|
|||||||
// static
|
// static
|
||||||
ShadowRealm* ShadowRealm::New(Environment* env) {
|
ShadowRealm* ShadowRealm::New(Environment* env) {
|
||||||
ShadowRealm* realm = new ShadowRealm(env);
|
ShadowRealm* realm = new ShadowRealm(env);
|
||||||
|
// TODO(legendecas): required by node::PromiseRejectCallback.
|
||||||
|
// Remove this once promise rejection doesn't need to be handled across
|
||||||
|
// realms.
|
||||||
|
realm->context()->SetSecurityToken(
|
||||||
|
env->principal_realm()->context()->GetSecurityToken());
|
||||||
|
|
||||||
// We do not expect the realm bootstrapping to throw any
|
// We do not expect the realm bootstrapping to throw any
|
||||||
// exceptions. If it does, exit the current Node.js instance.
|
// exceptions. If it does, exit the current Node.js instance.
|
||||||
@ -32,6 +40,10 @@ MaybeLocal<Context> HostCreateShadowRealmContextCallback(
|
|||||||
Local<Context> initiator_context) {
|
Local<Context> initiator_context) {
|
||||||
Environment* env = Environment::GetCurrent(initiator_context);
|
Environment* env = Environment::GetCurrent(initiator_context);
|
||||||
EscapableHandleScope scope(env->isolate());
|
EscapableHandleScope scope(env->isolate());
|
||||||
|
|
||||||
|
// We do not expect the realm bootstrapping to throw any
|
||||||
|
// exceptions. If it does, exit the current Node.js instance.
|
||||||
|
TryCatchScope try_catch(env, TryCatchScope::CatchMode::kFatal);
|
||||||
ShadowRealm* realm = ShadowRealm::New(env);
|
ShadowRealm* realm = ShadowRealm::New(env);
|
||||||
if (realm != nullptr) {
|
if (realm != nullptr) {
|
||||||
return scope.Escape(realm->context());
|
return scope.Escape(realm->context());
|
||||||
@ -137,6 +149,28 @@ v8::MaybeLocal<v8::Value> ShadowRealm::BootstrapRealm() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The process object is not exposed globally in ShadowRealm yet.
|
||||||
|
// However, the process properties need to be setup for built-in modules.
|
||||||
|
// Specifically, process.cwd() is needed by the ESM loader.
|
||||||
|
if (ExecuteBootstrapper(
|
||||||
|
"internal/bootstrap/switches/does_not_own_process_state")
|
||||||
|
.IsEmpty()) {
|
||||||
|
return MaybeLocal<Value>();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Setup process.env proxy.
|
||||||
|
Local<String> env_string = FIXED_ONE_BYTE_STRING(isolate_, "env");
|
||||||
|
Local<Object> env_proxy;
|
||||||
|
if (!isolate_data()->env_proxy_template()->NewInstance(context()).ToLocal(
|
||||||
|
&env_proxy) ||
|
||||||
|
process_object()->Set(context(), env_string, env_proxy).IsNothing()) {
|
||||||
|
return MaybeLocal<Value>();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ExecuteBootstrapper("internal/bootstrap/shadow_realm").IsEmpty()) {
|
||||||
|
return MaybeLocal<Value>();
|
||||||
|
}
|
||||||
|
|
||||||
return v8::True(isolate_);
|
return v8::True(isolate_);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
15
test/fixtures/es-module-shadow-realm/custom-loaders.js
vendored
Normal file
15
test/fixtures/es-module-shadow-realm/custom-loaders.js
vendored
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
// This fixture is used to test that custom loaders are not enabled in the ShadowRealm.
|
||||||
|
|
||||||
|
'use strict';
|
||||||
|
const assert = require('assert');
|
||||||
|
|
||||||
|
async function workInChildProcess() {
|
||||||
|
// Assert that the process is running with a custom loader.
|
||||||
|
const moduleNamespace = await import('file:///42.mjs');
|
||||||
|
assert.strictEqual(moduleNamespace.default, 42);
|
||||||
|
|
||||||
|
const realm = new ShadowRealm();
|
||||||
|
await assert.rejects(realm.importValue('file:///42.mjs', 'default'), TypeError);
|
||||||
|
}
|
||||||
|
|
||||||
|
workInChildProcess();
|
9
test/fixtures/es-module-shadow-realm/preload-main.js
vendored
Normal file
9
test/fixtures/es-module-shadow-realm/preload-main.js
vendored
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
// This fixture is used to test that --require preload modules are not enabled in the ShadowRealm.
|
||||||
|
|
||||||
|
'use strict';
|
||||||
|
const assert = require('assert');
|
||||||
|
|
||||||
|
assert.strictEqual(globalThis.preload, 42);
|
||||||
|
const realm = new ShadowRealm();
|
||||||
|
const value = realm.evaluate(`globalThis.preload`);
|
||||||
|
assert.strictEqual(value, undefined);
|
1
test/fixtures/es-module-shadow-realm/preload.js
vendored
Normal file
1
test/fixtures/es-module-shadow-realm/preload.js
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
globalThis.preload = 42;
|
3
test/fixtures/es-module-shadow-realm/re-export-state-counter.mjs
vendored
Normal file
3
test/fixtures/es-module-shadow-realm/re-export-state-counter.mjs
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
// This module verifies that the module specifier is resolved relative to the
|
||||||
|
// current module and not the current working directory in the ShadowRealm.
|
||||||
|
export { getCounter } from "./state-counter.mjs";
|
4
test/fixtures/es-module-shadow-realm/state-counter.mjs
vendored
Normal file
4
test/fixtures/es-module-shadow-realm/state-counter.mjs
vendored
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
let counter = 0;
|
||||||
|
export const getCounter = () => {
|
||||||
|
return counter++;
|
||||||
|
};
|
21
test/parallel/test-shadow-realm-allowed-builtin-modules.js
Normal file
21
test/parallel/test-shadow-realm-allowed-builtin-modules.js
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
// Flags: --experimental-shadow-realm
|
||||||
|
'use strict';
|
||||||
|
const common = require('../common');
|
||||||
|
const assert = require('assert');
|
||||||
|
|
||||||
|
async function main() {
|
||||||
|
// Verifies that builtin modules can not be imported in the ShadowRealm.
|
||||||
|
const realm = new ShadowRealm();
|
||||||
|
// The error object created inside the ShadowRealm with the error code
|
||||||
|
// property is not copied on the realm boundary. Only the error message
|
||||||
|
// is copied. Simply check the error message here.
|
||||||
|
await assert.rejects(realm.importValue('fs', 'readFileSync'), {
|
||||||
|
message: /Cannot find package 'fs'/,
|
||||||
|
});
|
||||||
|
// As above, we can only validate the error message, not the error code.
|
||||||
|
await assert.rejects(realm.importValue('node:fs', 'readFileSync'), {
|
||||||
|
message: /No such built-in module: node:fs/,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
main().then(common.mustCall());
|
26
test/parallel/test-shadow-realm-custom-loaders.js
Normal file
26
test/parallel/test-shadow-realm-custom-loaders.js
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
'use strict';
|
||||||
|
const common = require('../common');
|
||||||
|
const fixtures = require('../common/fixtures');
|
||||||
|
const assert = require('assert');
|
||||||
|
|
||||||
|
const commonArgs = [
|
||||||
|
'--experimental-shadow-realm',
|
||||||
|
'--no-warnings',
|
||||||
|
];
|
||||||
|
|
||||||
|
async function main() {
|
||||||
|
// Verifies that custom loaders are not enabled in the ShadowRealm.
|
||||||
|
const child = await common.spawnPromisified(process.execPath, [
|
||||||
|
...commonArgs,
|
||||||
|
'--experimental-loader',
|
||||||
|
fixtures.fileURL('es-module-loaders', 'loader-resolve-shortcircuit.mjs'),
|
||||||
|
'--experimental-loader',
|
||||||
|
fixtures.fileURL('es-module-loaders', 'loader-load-foo-or-42.mjs'),
|
||||||
|
fixtures.path('es-module-shadow-realm', 'custom-loaders.js'),
|
||||||
|
]);
|
||||||
|
|
||||||
|
assert.strictEqual(child.stderr, '');
|
||||||
|
assert.strictEqual(child.code, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
main().then(common.mustCall());
|
20
test/parallel/test-shadow-realm-gc-module.js
Normal file
20
test/parallel/test-shadow-realm-gc-module.js
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
// Flags: --experimental-shadow-realm --max-old-space-size=20
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verifying modules imported by ShadowRealm instances can be correctly
|
||||||
|
* garbage collected.
|
||||||
|
*/
|
||||||
|
|
||||||
|
const common = require('../common');
|
||||||
|
const fixtures = require('../common/fixtures');
|
||||||
|
|
||||||
|
async function main() {
|
||||||
|
const mod = fixtures.fileURL('es-module-shadow-realm', 'state-counter.mjs');
|
||||||
|
for (let i = 0; i < 100; i++) {
|
||||||
|
const realm = new ShadowRealm();
|
||||||
|
await realm.importValue(mod, 'getCounter');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
main().then(common.mustCall());
|
28
test/parallel/test-shadow-realm-import-value-resolve.js
Normal file
28
test/parallel/test-shadow-realm-import-value-resolve.js
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
// Flags: --experimental-shadow-realm
|
||||||
|
'use strict';
|
||||||
|
const common = require('../common');
|
||||||
|
const assert = require('assert');
|
||||||
|
const path = require('path');
|
||||||
|
|
||||||
|
common.skipIfWorker('process.chdir is not supported in workers.');
|
||||||
|
|
||||||
|
async function main() {
|
||||||
|
const realm = new ShadowRealm();
|
||||||
|
|
||||||
|
const dirname = __dirname;
|
||||||
|
// Set process cwd to the parent directory of __dirname.
|
||||||
|
const cwd = path.dirname(dirname);
|
||||||
|
process.chdir(cwd);
|
||||||
|
// Hardcode the relative path to ensure the string is still a valid relative
|
||||||
|
// URL string.
|
||||||
|
const relativePath = './fixtures/es-module-shadow-realm/re-export-state-counter.mjs';
|
||||||
|
|
||||||
|
// Make sure that the module can not be resolved relative to __filename.
|
||||||
|
assert.throws(() => require.resolve(relativePath), { code: 'MODULE_NOT_FOUND' });
|
||||||
|
|
||||||
|
// Resolve relative to the current working directory.
|
||||||
|
const getCounter = await realm.importValue(relativePath, 'getCounter');
|
||||||
|
assert.strictEqual(typeof getCounter, 'function');
|
||||||
|
}
|
||||||
|
|
||||||
|
main().then(common.mustCall());
|
29
test/parallel/test-shadow-realm-module.js
Normal file
29
test/parallel/test-shadow-realm-module.js
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
// Flags: --experimental-shadow-realm
|
||||||
|
'use strict';
|
||||||
|
const common = require('../common');
|
||||||
|
const fixtures = require('../common/fixtures');
|
||||||
|
const assert = require('assert');
|
||||||
|
|
||||||
|
async function main() {
|
||||||
|
const realm = new ShadowRealm();
|
||||||
|
const mod = fixtures.fileURL('es-module-shadow-realm', 'state-counter.mjs');
|
||||||
|
const getCounter = await realm.importValue(mod, 'getCounter');
|
||||||
|
assert.strictEqual(getCounter(), 0);
|
||||||
|
const getCounter1 = await realm.importValue(mod, 'getCounter');
|
||||||
|
// Returned value is a newly wrapped function.
|
||||||
|
assert.notStrictEqual(getCounter, getCounter1);
|
||||||
|
// Verify that the module state is shared between two `importValue` calls.
|
||||||
|
assert.strictEqual(getCounter1(), 1);
|
||||||
|
assert.strictEqual(getCounter(), 2);
|
||||||
|
|
||||||
|
const { getCounter: getCounterThisRealm } = await import(mod);
|
||||||
|
assert.notStrictEqual(getCounterThisRealm, getCounter);
|
||||||
|
// Verify that the module state is not shared between two realms.
|
||||||
|
assert.strictEqual(getCounterThisRealm(), 0);
|
||||||
|
assert.strictEqual(getCounter(), 3);
|
||||||
|
|
||||||
|
// Verify that shadow realm rejects to import a non-existing module.
|
||||||
|
await assert.rejects(realm.importValue('non-exists', 'exports'), TypeError);
|
||||||
|
}
|
||||||
|
|
||||||
|
main().then(common.mustCall());
|
20
test/parallel/test-shadow-realm-preload-module.js
Normal file
20
test/parallel/test-shadow-realm-preload-module.js
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
'use strict';
|
||||||
|
const common = require('../common');
|
||||||
|
const fixtures = require('../common/fixtures');
|
||||||
|
const { spawnSyncAndExitWithoutError } = require('../common/child_process');
|
||||||
|
|
||||||
|
const commonArgs = [
|
||||||
|
'--experimental-shadow-realm',
|
||||||
|
];
|
||||||
|
|
||||||
|
async function main() {
|
||||||
|
// Verifies that --require preload modules are not enabled in the ShadowRealm.
|
||||||
|
spawnSyncAndExitWithoutError(process.execPath, [
|
||||||
|
...commonArgs,
|
||||||
|
'--require',
|
||||||
|
fixtures.path('es-module-shadow-realm', 'preload.js'),
|
||||||
|
fixtures.path('es-module-shadow-realm', 'preload-main.js'),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
main().then(common.mustCall());
|
Loading…
Reference in New Issue
Block a user