Skip to content

Commit

Permalink
modules: move callbacks and conditions into modules/esm/utils.js
Browse files Browse the repository at this point in the history
This moves the following utils into modules/esm/utils.js:

- Code related to default conditions
- The callbackMap (which is now created in the module instead of
  hanging off the module_wrap binding, since the C++ land
  does not need it).
- Per-isolate module callbacks

These are self-contained code that can be included into the
built-in snapshot.

PR-URL: #45849
Reviewed-By: Geoffrey Booth <[email protected]>
Reviewed-By: Chengzhong Wu <[email protected]>
  • Loading branch information
joyeecheung authored and targos committed Jan 1, 2023
1 parent f6c6673 commit 0b3512f
Show file tree
Hide file tree
Showing 11 changed files with 130 additions and 91 deletions.
6 changes: 3 additions & 3 deletions lib/internal/modules/esm/create_dynamic_module.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ ${ArrayPrototypeJoin(ArrayPrototypeMap(imports, createImport), '\n')}
${ArrayPrototypeJoin(ArrayPrototypeMap(exports, createExport), '\n')}
import.meta.done();
`;
const { ModuleWrap, callbackMap } = internalBinding('module_wrap');
const { ModuleWrap } = internalBinding('module_wrap');
const m = new ModuleWrap(`${url}`, undefined, source, 0, 0);

const readyfns = new SafeSet();
Expand All @@ -46,8 +46,8 @@ import.meta.done();

if (imports.length)
reflect.imports = ObjectCreate(null);

callbackMap.set(m, {
const { setCallbackForWrap } = require('internal/modules/esm/utils');
setCallbackForWrap(m, {
initializeImportMeta: (meta, wrap) => {
meta.exports = reflect.exports;
if (reflect.imports)
Expand Down
12 changes: 8 additions & 4 deletions lib/internal/modules/esm/loader.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,12 @@ function newModuleMap() {

const {
defaultResolve,
DEFAULT_CONDITIONS,
} = require('internal/modules/esm/resolve');

const {
getDefaultConditions,
} = require('internal/modules/esm/utils');

function getTranslators() {
const { translators } = require('internal/modules/esm/translators');
return translators;
Expand Down Expand Up @@ -363,9 +366,10 @@ class ESMLoader {
url = pathToFileURL(`${process.cwd()}/[eval${++this.evalIndex}]`).href
) {
const evalInstance = (url) => {
const { ModuleWrap, callbackMap } = internalBinding('module_wrap');
const { ModuleWrap } = internalBinding('module_wrap');
const { setCallbackForWrap } = require('internal/modules/esm/utils');
const module = new ModuleWrap(url, undefined, source, 0, 0);
callbackMap.set(module, {
setCallbackForWrap(module, {
importModuleDynamically: (specifier, { url }, importAssertions) => {
return this.import(specifier, url, importAssertions);
}
Expand Down Expand Up @@ -798,7 +802,7 @@ class ESMLoader {
}
const chain = this.#hooks.resolve;
const context = {
conditions: DEFAULT_CONDITIONS,
conditions: getDefaultConditions(),
importAssertions,
parentURL,
};
Expand Down
32 changes: 1 addition & 31 deletions lib/internal/modules/esm/resolve.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ const {
ArrayPrototypeJoin,
ArrayPrototypeShift,
JSONStringify,
ObjectFreeze,
ObjectGetOwnPropertyNames,
ObjectPrototypeHasOwnProperty,
RegExp,
Expand Down Expand Up @@ -45,7 +44,6 @@ const typeFlag = getOptionValue('--input-type');
const { URL, pathToFileURL, fileURLToPath } = require('internal/url');
const {
ERR_INPUT_TYPE_NOT_ALLOWED,
ERR_INVALID_ARG_VALUE,
ERR_INVALID_MODULE_SPECIFIER,
ERR_INVALID_PACKAGE_CONFIG,
ERR_INVALID_PACKAGE_TARGET,
Expand All @@ -60,25 +58,13 @@ const {

const { Module: CJSModule } = require('internal/modules/cjs/loader');
const { getPackageConfig, getPackageScopeConfig } = require('internal/modules/esm/package_config');
const { getConditionsSet } = require('internal/modules/esm/utils');

/**
* @typedef {import('internal/modules/esm/package_config.js').PackageConfig} PackageConfig
*/


const userConditions = getOptionValue('--conditions');
const noAddons = getOptionValue('--no-addons');
const addonConditions = noAddons ? [] : ['node-addons'];

const DEFAULT_CONDITIONS = ObjectFreeze([
'node',
'import',
...addonConditions,
...userConditions,
]);

const DEFAULT_CONDITIONS_SET = new SafeSet(DEFAULT_CONDITIONS);

const emittedPackageWarnings = new SafeSet();

function emitTrailingSlashPatternDeprecation(match, pjsonUrl, base) {
Expand Down Expand Up @@ -147,21 +133,6 @@ function emitLegacyIndexDeprecation(url, packageJSONUrl, base, main) {
);
}

/**
* @param {string[]} [conditions]
* @returns {Set<string>}
*/
function getConditionsSet(conditions) {
if (conditions !== undefined && conditions !== DEFAULT_CONDITIONS) {
if (!ArrayIsArray(conditions)) {
throw new ERR_INVALID_ARG_VALUE('conditions', conditions,
'expected an array');
}
return new SafeSet(conditions);
}
return DEFAULT_CONDITIONS_SET;
}

const realpathCache = new SafeMap();

/**
Expand Down Expand Up @@ -1125,7 +1096,6 @@ async function defaultResolve(specifier, context = {}) {
}

module.exports = {
DEFAULT_CONDITIONS,
defaultResolve,
encodedSepRegEx,
getPackageScopeConfig,
Expand Down
3 changes: 2 additions & 1 deletion lib/internal/modules/esm/translators.js
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,8 @@ translators.set('module', async function moduleStrategy(url, source, isMain) {
maybeCacheSourceMap(url, source);
debug(`Translating StandardModule ${url}`);
const module = new ModuleWrap(url, undefined, source, 0, 0);
moduleWrap.callbackMap.set(module, {
const { setCallbackForWrap } = require('internal/modules/esm/utils');
setCallbackForWrap(module, {
initializeImportMeta: (meta, wrap) => this.importMetaInitialize(meta, { url }),
importModuleDynamically,
});
Expand Down
105 changes: 105 additions & 0 deletions lib/internal/modules/esm/utils.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
'use strict';
const {
ArrayIsArray,
SafeSet,
SafeWeakMap,
ObjectFreeze,
} = primordials;

const {
ERR_VM_DYNAMIC_IMPORT_CALLBACK_MISSING,
ERR_INVALID_ARG_VALUE,
} = require('internal/errors').codes;

const { getOptionValue } = require('internal/options');

const {
setImportModuleDynamicallyCallback,
setInitializeImportMetaObjectCallback
} = internalBinding('module_wrap');
const {
getModuleFromWrap,
} = require('internal/vm/module');
const assert = require('internal/assert');

const callbackMap = new SafeWeakMap();
function setCallbackForWrap(wrap, data) {
callbackMap.set(wrap, data);
}

let defaultConditions;
function getDefaultConditions() {
assert(defaultConditions !== undefined);
return defaultConditions;
}

let defaultConditionsSet;
function getDefaultConditionsSet() {
assert(defaultConditionsSet !== undefined);
return defaultConditionsSet;
}

// This function is called during pre-execution, before any user code is run.
function initializeDefaultConditions() {
const userConditions = getOptionValue('--conditions');
const noAddons = getOptionValue('--no-addons');
const addonConditions = noAddons ? [] : ['node-addons'];

defaultConditions = ObjectFreeze([
'node',
'import',
...addonConditions,
...userConditions,
]);
defaultConditionsSet = new SafeSet(defaultConditions);
}

/**
* @param {string[]} [conditions]
* @returns {Set<string>}
*/
function getConditionsSet(conditions) {
if (conditions !== undefined && conditions !== getDefaultConditions()) {
if (!ArrayIsArray(conditions)) {
throw new ERR_INVALID_ARG_VALUE('conditions', conditions,
'expected an array');
}
return new SafeSet(conditions);
}
return getDefaultConditionsSet();
}

function initializeImportMetaObject(wrap, meta) {
if (callbackMap.has(wrap)) {
const { initializeImportMeta } = callbackMap.get(wrap);
if (initializeImportMeta !== undefined) {
initializeImportMeta(meta, getModuleFromWrap(wrap) || wrap);
}
}
}

async function importModuleDynamicallyCallback(wrap, specifier, assertions) {
if (callbackMap.has(wrap)) {
const { importModuleDynamically } = callbackMap.get(wrap);
if (importModuleDynamically !== undefined) {
return importModuleDynamically(
specifier, getModuleFromWrap(wrap) || wrap, assertions);
}
}
throw new ERR_VM_DYNAMIC_IMPORT_CALLBACK_MISSING();
}

function initializeESM() {
initializeDefaultConditions();
// Setup per-isolate callbacks that locate data or callbacks that we keep
// track of for different ESM modules.
setInitializeImportMetaObjectCallback(initializeImportMetaObject);
setImportModuleDynamicallyCallback(importModuleDynamicallyCallback);
}

module.exports = {
setCallbackForWrap,
initializeESM,
getDefaultConditions,
getConditionsSet,
};
29 changes: 0 additions & 29 deletions lib/internal/process/esm_loader.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,40 +5,11 @@ const {
ObjectCreate,
} = primordials;

const {
ERR_VM_DYNAMIC_IMPORT_CALLBACK_MISSING,
} = require('internal/errors').codes;
const { ESMLoader } = require('internal/modules/esm/loader');
const {
hasUncaughtExceptionCaptureCallback,
} = require('internal/process/execution');
const { pathToFileURL } = require('internal/url');
const {
getModuleFromWrap,
} = require('internal/vm/module');

exports.initializeImportMetaObject = function(wrap, meta) {
const { callbackMap } = internalBinding('module_wrap');
if (callbackMap.has(wrap)) {
const { initializeImportMeta } = callbackMap.get(wrap);
if (initializeImportMeta !== undefined) {
initializeImportMeta(meta, getModuleFromWrap(wrap) || wrap);
}
}
};

exports.importModuleDynamicallyCallback =
async function importModuleDynamicallyCallback(wrap, specifier, assertions) {
const { callbackMap } = internalBinding('module_wrap');
if (callbackMap.has(wrap)) {
const { importModuleDynamically } = callbackMap.get(wrap);
if (importModuleDynamically !== undefined) {
return importModuleDynamically(
specifier, getModuleFromWrap(wrap) || wrap, assertions);
}
}
throw new ERR_VM_DYNAMIC_IMPORT_CALLBACK_MISSING();
};

const esmLoader = new ESMLoader();
exports.esmLoader = esmLoader;
Expand Down
15 changes: 2 additions & 13 deletions lib/internal/process/pre_execution.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ const {
ObjectDefineProperty,
ObjectGetOwnPropertyDescriptor,
SafeMap,
SafeWeakMap,
StringPrototypeStartsWith,
globalThis,
} = primordials;
Expand Down Expand Up @@ -571,20 +570,10 @@ function initializeCJSLoader() {
}

function initializeESMLoader() {
// Create this WeakMap in js-land because V8 has no C++ API for WeakMap.
internalBinding('module_wrap').callbackMap = new SafeWeakMap();

if (getEmbedderOptions().shouldNotRegisterESMLoader) return;

const {
setImportModuleDynamicallyCallback,
setInitializeImportMetaObjectCallback
} = internalBinding('module_wrap');
const esm = require('internal/process/esm_loader');
// Setup per-isolate callbacks that locate data or callbacks that we keep
// track of for different ESM modules.
setInitializeImportMetaObjectCallback(esm.initializeImportMetaObject);
setImportModuleDynamicallyCallback(esm.importModuleDynamicallyCallback);
const { initializeESM } = require('internal/modules/esm/utils');
initializeESM();

// Patch the vm module when --experimental-vm-modules is on.
// Please update the comments in vm.js when this block changes.
Expand Down
7 changes: 3 additions & 4 deletions lib/internal/vm.js
Original file line number Diff line number Diff line change
Expand Up @@ -94,12 +94,11 @@ function internalCompileFunction(code, params, options) {
if (importModuleDynamically !== undefined) {
validateFunction(importModuleDynamically,
'options.importModuleDynamically');
const { importModuleDynamicallyWrap } =
require('internal/vm/module');
const { callbackMap } = internalBinding('module_wrap');
const { importModuleDynamicallyWrap } = require('internal/vm/module');
const wrapped = importModuleDynamicallyWrap(importModuleDynamically);
const func = result.function;
callbackMap.set(result.cacheKey, {
const { setCallbackForWrap } = require('internal/modules/esm/utils');
setCallbackForWrap(result.cacheKey, {
importModuleDynamically: (s, _k, i) => wrapped(s, func, i),
});
}
Expand Down
4 changes: 2 additions & 2 deletions lib/internal/vm/module.js
Original file line number Diff line number Diff line change
Expand Up @@ -125,8 +125,8 @@ class Module {
this[kWrap] = new ModuleWrap(identifier, context, sourceText,
options.lineOffset, options.columnOffset,
options.cachedData);

binding.callbackMap.set(this[kWrap], {
const { setCallbackForWrap } = require('internal/modules/esm/utils');
setCallbackForWrap(this[kWrap], {
initializeImportMeta: options.initializeImportMeta,
importModuleDynamically: options.importModuleDynamically ?
importModuleDynamicallyWrap(options.importModuleDynamically) :
Expand Down
7 changes: 3 additions & 4 deletions lib/vm.js
Original file line number Diff line number Diff line change
Expand Up @@ -111,10 +111,9 @@ class Script extends ContextifyScript {
if (importModuleDynamically !== undefined) {
validateFunction(importModuleDynamically,
'options.importModuleDynamically');
const { importModuleDynamicallyWrap } =
require('internal/vm/module');
const { callbackMap } = internalBinding('module_wrap');
callbackMap.set(this, {
const { importModuleDynamicallyWrap } = require('internal/vm/module');
const { setCallbackForWrap } = require('internal/modules/esm/utils');
setCallbackForWrap(this, {
importModuleDynamically:
importModuleDynamicallyWrap(importModuleDynamically),
});
Expand Down
1 change: 1 addition & 0 deletions test/parallel/test-bootstrap-modules.js
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ const expectedModules = new Set([
'NativeModule internal/modules/esm/package_config',
'NativeModule internal/modules/esm/resolve',
'NativeModule internal/modules/esm/translators',
'NativeModule internal/modules/esm/utils',
'NativeModule internal/modules/package_json_reader',
'NativeModule internal/modules/run_main',
'NativeModule internal/net',
Expand Down

0 comments on commit 0b3512f

Please sign in to comment.