summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/api/errors.md10
-rw-r--r--doc/api/vm.md103
-rw-r--r--lib/internal/errors.js2
-rw-r--r--lib/internal/modules/esm/loader.js4
-rw-r--r--lib/internal/vm/source_text_module.js284
-rw-r--r--lib/vm.js20
-rw-r--r--src/module_wrap.cc12
-rw-r--r--src/module_wrap.h2
-rw-r--r--test/parallel/test-internal-module-wrap.js2
-rw-r--r--test/parallel/test-util-inspect-namespace.js1
-rw-r--r--test/parallel/test-util-types.js1
-rw-r--r--test/parallel/test-vm-module-basic.js29
-rw-r--r--test/parallel/test-vm-module-dynamic-import.js4
-rw-r--r--test/parallel/test-vm-module-dynamic-namespace.js17
-rw-r--r--test/parallel/test-vm-module-errors.js75
-rw-r--r--test/parallel/test-vm-module-import-meta.js1
-rw-r--r--test/parallel/test-vm-module-link.js35
-rw-r--r--test/parallel/test-vm-module-reevaluate.js2
18 files changed, 269 insertions, 335 deletions
diff --git a/doc/api/errors.md b/doc/api/errors.md
index 34412648b3..4e76673723 100644
--- a/doc/api/errors.md
+++ b/doc/api/errors.md
@@ -1984,11 +1984,6 @@ than the parent module. Linked modules must share the same context.
The linker function returned a module for which linking has failed.
-<a id="ERR_VM_MODULE_NOT_LINKED"></a>
-### ERR_VM_MODULE_NOT_LINKED
-
-The module must be successfully linked before instantiation.
-
<a id="ERR_VM_MODULE_NOT_MODULE"></a>
### ERR_VM_MODULE_NOT_MODULE
@@ -2275,6 +2270,11 @@ removed: v10.0.0
Used when a given value is out of the accepted range.
+<a id="ERR_VM_MODULE_NOT_LINKED"></a>
+### ERR_VM_MODULE_NOT_LINKED
+
+The module must be successfully linked before instantiation.
+
<a id="ERR_ZLIB_BINDING_CLOSED"></a>
### ERR_ZLIB_BINDING_CLOSED
<!-- YAML
diff --git a/doc/api/vm.md b/doc/api/vm.md
index 18ebd10a63..601b8c3052 100644
--- a/doc/api/vm.md
+++ b/doc/api/vm.md
@@ -322,9 +322,9 @@ intrinsically asynchronous, in contrast with the synchronous nature of
`vm.Script` objects. With the help of async functions, however, manipulating
`vm.SourceTextModule` objects is fairly straightforward.
-Using a `vm.SourceTextModule` object requires four distinct steps:
-creation/parsing, linking, instantiation, and evaluation. These four steps are
-illustrated in the following example.
+Using a `vm.SourceTextModule` object requires three distinct steps:
+creation/parsing, linking, and evaluation. These three steps are illustrated in
+the following example.
This implementation lies at a lower level than the [ECMAScript Module
loader][]. There is also currently no way to interact with the Loader, though
@@ -391,15 +391,6 @@ const contextifiedSandbox = vm.createContext({ secret: 42 });
// Step 3
//
- // Instantiate the top-level Module.
- //
- // Only the top-level Module needs to be explicitly instantiated; its
- // dependencies will be recursively instantiated by instantiate().
-
- bar.instantiate();
-
- // Step 4
- //
// Evaluate the Module. The evaluate() method returns a Promise with a single
// property "result" that contains the result of the very last statement
// executed in the Module. In the case of `bar`, it is `s;`, which refers to
@@ -417,8 +408,9 @@ const contextifiedSandbox = vm.createContext({ secret: 42 });
* `code` {string} JavaScript Module code to parse
* `options`
- * `url` {string} URL used in module resolution and stack traces. **Default:**
- `'vm:module(i)'` where `i` is a context-specific ascending index.
+ * `identifier` {string} String used in stack traces.
+ **Default:** `'vm:module(i)'` where `i` is a context-specific ascending
+ index.
* `context` {Object} The [contextified][] object as returned by the
`vm.createContext()` method, to compile and evaluate this `Module` in.
* `lineOffset` {integer} Specifies the line number offset that is displayed
@@ -465,7 +457,6 @@ const contextifiedSandbox = vm.createContext({ secret: 42 });
});
// Since module has no dependencies, the linker function will never be called.
await module.link(() => {});
- module.instantiate();
await module.evaluate();
// Now, Object.prototype.secret will be equal to 42.
@@ -516,7 +507,7 @@ in the ECMAScript specification.
Evaluate the module.
-This must be called after the module has been instantiated; otherwise it will
+This must be called after the module has been linked; otherwise it will
throw an error. It could be called also when the module has already been
evaluated, in which case it will do one of the following two things:
@@ -531,23 +522,6 @@ This method cannot be called while the module is being evaluated
Corresponds to the [Evaluate() concrete method][] field of [Source Text Module
Record][]s in the ECMAScript specification.
-### module.instantiate()
-
-Instantiate the module. This must be called after linking has completed
-(`linkingStatus` is `'linked'`); otherwise it will throw an error. It may also
-throw an exception if one of the dependencies does not provide an export the
-parent module requires.
-
-However, if this function succeeded, further calls to this function after the
-initial instantiation will be no-ops, to be consistent with the ECMAScript
-specification.
-
-Unlike other methods operating on `Module`, this function completes
-synchronously and returns nothing.
-
-Corresponds to the [Instantiate() concrete method][] field of [Source Text
-Module Record][]s in the ECMAScript specification.
-
### module.link(linker)
* `linker` {Function}
@@ -563,7 +537,7 @@ Module Record][]s in the ECMAScript specification.
* Returns: {vm.SourceTextModule|Promise}
* Returns: {Promise}
-Link module dependencies. This method must be called before instantiation, and
+Link module dependencies. This method must be called before evaluation, and
can only be called once per module.
The function is expected to return a `Module` object or a `Promise` that
@@ -571,9 +545,9 @@ eventually resolves to a `Module` object. The returned `Module` must satisfy the
following two invariants:
* It must belong to the same context as the parent `Module`.
-* Its `linkingStatus` must not be `'errored'`.
+* Its `status` must not be `'errored'`.
-If the returned `Module`'s `linkingStatus` is `'unlinked'`, this method will be
+If the returned `Module`'s `status` is `'unlinked'`, this method will be
recursively called on the returned `Module` with the same provided `linker`
function.
@@ -587,37 +561,22 @@ specification, with a few key differences:
* The linker function is allowed to be asynchronous while
[HostResolveImportedModule][] is synchronous.
-* The linker function is executed during linking, a Node.js-specific stage
- before instantiation, while [HostResolveImportedModule][] is called during
- instantiation.
The actual [HostResolveImportedModule][] implementation used during module
-instantiation is one that returns the modules linked during linking. Since at
+linking is one that returns the modules linked during linking. Since at
that point all modules would have been fully linked already, the
[HostResolveImportedModule][] implementation is fully synchronous per
specification.
-### module.linkingStatus
-
-* {string}
-
-The current linking status of `module`. It will be one of the following values:
-
-* `'unlinked'`: `module.link()` has not yet been called.
-* `'linking'`: `module.link()` has been called, but not all Promises returned by
- the linker function have been resolved yet.
-* `'linked'`: `module.link()` has been called, and all its dependencies have
- been successfully linked.
-* `'errored'`: `module.link()` has been called, but at least one of its
- dependencies failed to link, either because the callback returned a `Promise`
- that is rejected, or because the `Module` the callback returned is invalid.
+Corresponds to the [Link() concrete method][] field of [Source Text Module
+Record][]s in the ECMAScript specification.
### module.namespace
* {Object}
-The namespace object of the module. This is only available after instantiation
-(`module.instantiate()`) has completed.
+The namespace object of the module. This is only available after linking
+(`module.link()`) has completed.
Corresponds to the [GetModuleNamespace][] abstract operation in the ECMAScript
specification.
@@ -628,21 +587,13 @@ specification.
The current status of the module. Will be one of:
-* `'uninstantiated'`: The module is not instantiated. It may because of any of
- the following reasons:
-
- * The module was just created.
- * `module.instantiate()` has been called on this module, but it failed for
- some reason.
-
- This status does not convey any information regarding if `module.link()` has
- been called. See `module.linkingStatus` for that.
+* `'unlinked'`: `module.link()` has not yet been called.
-* `'instantiating'`: The module is currently being instantiated through a
- `module.instantiate()` call on itself or a parent module.
+* `'linking'`: `module.link()` has been called, but not all Promises returned
+ by the linker function have been resolved yet.
-* `'instantiated'`: The module has been instantiated successfully, but
- `module.evaluate()` has not yet been called.
+* `'linked'`: The module has been linked successfully, and all of its
+ dependencies are linked, but `module.evaluate()` has not yet been called.
* `'evaluating'`: The module is being evaluated through a `module.evaluate()` on
itself or a parent module.
@@ -656,11 +607,11 @@ Other than `'errored'`, this status string corresponds to the specification's
`'evaluated'` in the specification, but with `[[EvaluationError]]` set to a
value that is not `undefined`.
-### module.url
+### module.identifier
* {string}
-The URL of the current module, as set in the constructor.
+The identifier of the current module, as set in the constructor.
## vm.compileFunction(code[, params[, options]])
<!-- YAML
@@ -1127,11 +1078,11 @@ queues.
[`vm.runInContext()`]: #vm_vm_runincontext_code_contextifiedsandbox_options
[`vm.runInThisContext()`]: #vm_vm_runinthiscontext_code_options
[ECMAScript Module Loader]: esm.html#esm_ecmascript_modules
-[Evaluate() concrete method]: https://tc39.github.io/ecma262/#sec-moduleevaluation
-[GetModuleNamespace]: https://tc39.github.io/ecma262/#sec-getmodulenamespace
-[HostResolveImportedModule]: https://tc39.github.io/ecma262/#sec-hostresolveimportedmodule
-[Instantiate() concrete method]: https://tc39.github.io/ecma262/#sec-moduledeclarationinstantiation
-[Source Text Module Record]: https://tc39.github.io/ecma262/#sec-source-text-module-records
+[Evaluate() concrete method]: https://tc39.es/ecma262/#sec-moduleevaluation
+[GetModuleNamespace]: https://tc39.es/ecma262/#sec-getmodulenamespace
+[HostResolveImportedModule]: https://tc39.es/ecma262/#sec-hostresolveimportedmodule
+[Link() concrete method]: https://tc39.es/ecma262/#sec-moduledeclarationlinking
+[Source Text Module Record]: https://tc39.es/ecma262/#sec-source-text-module-records
[V8 Embedder's Guide]: https://v8.dev/docs/embed#contexts
[contextified]: #vm_what_does_it_mean_to_contextify_an_object
[global object]: https://es5.github.io/#x15.1
diff --git a/lib/internal/errors.js b/lib/internal/errors.js
index 53f448cf2f..ab874cd533 100644
--- a/lib/internal/errors.js
+++ b/lib/internal/errors.js
@@ -1211,8 +1211,6 @@ E('ERR_VM_MODULE_DIFFERENT_CONTEXT',
'Linked modules must use the same context', Error);
E('ERR_VM_MODULE_LINKING_ERRORED',
'Linking has already failed for the provided module', Error);
-E('ERR_VM_MODULE_NOT_LINKED',
- 'Module must be linked before it can be instantiated', Error);
E('ERR_VM_MODULE_NOT_MODULE',
'Provided module is not an instance of Module', Error);
E('ERR_VM_MODULE_STATUS', 'Module status %s', Error);
diff --git a/lib/internal/modules/esm/loader.js b/lib/internal/modules/esm/loader.js
index 09109d3c71..9800e8a550 100644
--- a/lib/internal/modules/esm/loader.js
+++ b/lib/internal/modules/esm/loader.js
@@ -127,7 +127,7 @@ class Loader {
this.moduleMap.set(url, job);
const { module, result } = await job.run();
return {
- namespace: module.namespace(),
+ namespace: module.getNamespace(),
result
};
}
@@ -135,7 +135,7 @@ class Loader {
async import(specifier, parent) {
const job = await this.getModuleJob(specifier, parent);
const { module } = await job.run();
- return module.namespace();
+ return module.getNamespace();
}
hook({ resolve, dynamicInstantiate }) {
diff --git a/lib/internal/vm/source_text_module.js b/lib/internal/vm/source_text_module.js
index 881c298ce5..61af2e7a29 100644
--- a/lib/internal/vm/source_text_module.js
+++ b/lib/internal/vm/source_text_module.js
@@ -3,14 +3,12 @@
const { Object, SafePromise } = primordials;
const { isModuleNamespaceObject } = require('internal/util/types');
-const { URL } = require('internal/url');
const { isContext } = internalBinding('contextify');
const {
ERR_INVALID_ARG_TYPE,
ERR_VM_MODULE_ALREADY_LINKED,
ERR_VM_MODULE_DIFFERENT_CONTEXT,
ERR_VM_MODULE_LINKING_ERRORED,
- ERR_VM_MODULE_NOT_LINKED,
ERR_VM_MODULE_NOT_MODULE,
ERR_VM_MODULE_STATUS,
} = require('internal/errors').codes;
@@ -22,7 +20,7 @@ const {
const {
validateInt32,
validateUint32,
- validateString
+ validateString,
} = require('internal/validators');
const binding = internalBinding('module_wrap');
@@ -37,29 +35,33 @@ const {
} = binding;
const STATUS_MAP = {
- [kUninstantiated]: 'uninstantiated',
- [kInstantiating]: 'instantiating',
- [kInstantiated]: 'instantiated',
+ [kUninstantiated]: 'unlinked',
+ [kInstantiating]: 'linking',
+ [kInstantiated]: 'linked',
[kEvaluating]: 'evaluating',
[kEvaluated]: 'evaluated',
[kErrored]: 'errored',
};
let globalModuleId = 0;
+const defaultModuleName = 'vm:module';
const perContextModuleId = new WeakMap();
-const wrapMap = new WeakMap();
-const dependencyCacheMap = new WeakMap();
-const linkingStatusMap = new WeakMap();
-// ModuleWrap -> vm.SourceTextModule
const wrapToModuleMap = new WeakMap();
-const defaultModuleName = 'vm:module';
-// TODO(devsnek): figure out AbstractModule class or protocol
+const kNoError = Symbol('kNoError');
+
class SourceTextModule {
- constructor(src, options = {}) {
+ #wrap;
+ #identifier;
+ #context;
+ #dependencySpecifiers;
+ #statusOverride;
+ #error = kNoError;
+
+ constructor(source, options = {}) {
emitExperimentalWarning('vm.SourceTextModule');
- validateString(src, 'src');
+ validateString(source, 'source');
if (typeof options !== 'object' || options === null)
throw new ERR_INVALID_ARG_TYPE('options', 'Object', options);
@@ -81,21 +83,6 @@ class SourceTextModule {
}
}
- let { url } = options;
- if (url !== undefined) {
- validateString(url, 'options.url');
- url = new URL(url).href;
- } else if (context === undefined) {
- url = `${defaultModuleName}(${globalModuleId++})`;
- } else if (perContextModuleId.has(context)) {
- const curId = perContextModuleId.get(context);
- url = `${defaultModuleName}(${curId})`;
- perContextModuleId.set(context, curId + 1);
- } else {
- url = `${defaultModuleName}(0)`;
- perContextModuleId.set(context, 1);
- }
-
validateInt32(lineOffset, 'options.lineOffset');
validateInt32(columnOffset, 'options.columnOffset');
@@ -111,114 +98,167 @@ class SourceTextModule {
'options.importModuleDynamically', 'function', importModuleDynamically);
}
- const wrap = new ModuleWrap(src, url, context, lineOffset, columnOffset);
- wrapMap.set(this, wrap);
- linkingStatusMap.set(this, 'unlinked');
- wrapToModuleMap.set(wrap, this);
+ let { identifier } = options;
+ if (identifier !== undefined) {
+ validateString(identifier, 'options.identifier');
+ } else if (context === undefined) {
+ identifier = `${defaultModuleName}(${globalModuleId++})`;
+ } else if (perContextModuleId.has(context)) {
+ const curId = perContextModuleId.get(context);
+ identifier = `${defaultModuleName}(${curId})`;
+ perContextModuleId.set(context, curId + 1);
+ } else {
+ identifier = `${defaultModuleName}(0)`;
+ perContextModuleId.set(context, 1);
+ }
- binding.callbackMap.set(wrap, {
+ this.#wrap = new ModuleWrap(
+ source, identifier, context,
+ lineOffset, columnOffset,
+ );
+ wrapToModuleMap.set(this.#wrap, this);
+ this.#identifier = identifier;
+ this.#context = context;
+
+ binding.callbackMap.set(this.#wrap, {
initializeImportMeta,
- importModuleDynamically: importModuleDynamically ? async (...args) => {
- const m = await importModuleDynamically(...args);
- if (isModuleNamespaceObject(m)) {
- return m;
- }
- if (!m || !wrapMap.has(m))
- throw new ERR_VM_MODULE_NOT_MODULE();
- const childLinkingStatus = linkingStatusMap.get(m);
- if (childLinkingStatus === 'errored')
- throw m.error;
- return m.namespace;
- } : undefined,
+ importModuleDynamically: importModuleDynamically ?
+ importModuleDynamicallyWrap(importModuleDynamically) :
+ undefined,
});
+ }
- Object.defineProperties(this, {
- url: { value: url, enumerable: true },
- context: { value: context, enumerable: true },
- });
+ get status() {
+ try {
+ this.#error;
+ } catch {
+ throw new ERR_VM_MODULE_NOT_MODULE();
+ }
+ if (this.#error !== kNoError) {
+ return 'errored';
+ }
+ if (this.#statusOverride) {
+ return this.#statusOverride;
+ }
+ return STATUS_MAP[this.#wrap.getStatus()];
}
- get linkingStatus() {
- return linkingStatusMap.get(this);
+ get identifier() {
+ try {
+ return this.#identifier;
+ } catch {
+ throw new ERR_VM_MODULE_NOT_MODULE();
+ }
}
- get status() {
- return STATUS_MAP[wrapMap.get(this).getStatus()];
+ get context() {
+ try {
+ return this.#context;
+ } catch {
+ throw new ERR_VM_MODULE_NOT_MODULE();
+ }
}
get namespace() {
- const wrap = wrapMap.get(this);
- if (wrap.getStatus() < kInstantiated)
- throw new ERR_VM_MODULE_STATUS(
- 'must not be uninstantiated or instantiating'
- );
- return wrap.namespace();
+ try {
+ this.#wrap;
+ } catch {
+ throw new ERR_VM_MODULE_NOT_MODULE();
+ }
+ if (this.#wrap.getStatus() < kInstantiated) {
+ throw new ERR_VM_MODULE_STATUS('must not be unlinked or linking');
+ }
+ return this.#wrap.getNamespace();
}
get dependencySpecifiers() {
- let deps = dependencyCacheMap.get(this);
- if (deps !== undefined)
- return deps;
-
- deps = wrapMap.get(this).getStaticDependencySpecifiers();
- Object.freeze(deps);
- dependencyCacheMap.set(this, deps);
- return deps;
+ try {
+ this.#dependencySpecifiers;
+ } catch {
+ throw new ERR_VM_MODULE_NOT_MODULE();
+ }
+ if (this.#dependencySpecifiers === undefined) {
+ this.#dependencySpecifiers = this.#wrap.getStaticDependencySpecifiers();
+ }
+ return this.#dependencySpecifiers;
}
get error() {
- const wrap = wrapMap.get(this);
- if (wrap.getStatus() !== kErrored)
+ try {
+ this.#error;
+ } catch {
+ throw new ERR_VM_MODULE_NOT_MODULE();
+ }
+ if (this.#error !== kNoError) {
+ return this.#error;
+ }
+ if (this.#wrap.getStatus() !== kErrored) {
throw new ERR_VM_MODULE_STATUS('must be errored');
- return wrap.getError();
+ }
+ return this.#wrap.getError();
}
async link(linker) {
- if (typeof linker !== 'function')
+ try {
+ this.#link;
+ } catch {
+ throw new ERR_VM_MODULE_NOT_MODULE();
+ }
+
+ if (typeof linker !== 'function') {
throw new ERR_INVALID_ARG_TYPE('linker', 'function', linker);
- if (linkingStatusMap.get(this) !== 'unlinked')
+ }
+ if (this.status !== 'unlinked') {
throw new ERR_VM_MODULE_ALREADY_LINKED();
- const wrap = wrapMap.get(this);
- if (wrap.getStatus() !== kUninstantiated)
- throw new ERR_VM_MODULE_STATUS('must be uninstantiated');
+ }
- linkingStatusMap.set(this, 'linking');
+ await this.#link(linker);
- const promises = wrap.link(async (specifier) => {
- const m = await linker(specifier, this);
- if (!m || !wrapMap.has(m))
+ this.#wrap.instantiate();
+ }
+
+ #link = async function(linker) {
+ this.#statusOverride = 'linking';
+
+ const promises = this.#wrap.link(async (identifier) => {
+ const module = await linker(identifier, this);
+ try {
+ module.#wrap;
+ } catch {
throw new ERR_VM_MODULE_NOT_MODULE();
- if (m.context !== this.context)
+ }
+ if (module.context !== this.context) {
throw new ERR_VM_MODULE_DIFFERENT_CONTEXT();
- const childLinkingStatus = linkingStatusMap.get(m);
- if (childLinkingStatus === 'errored')
+ }
+ if (module.status === 'errored') {
throw new ERR_VM_MODULE_LINKING_ERRORED();
- if (childLinkingStatus === 'unlinked')
- await m.link(linker);
- return wrapMap.get(m);
+ }
+ if (module.status === 'unlinked') {
+ await module.#link(linker);
+ }
+ return module.#wrap;
});
try {
- if (promises !== undefined)
+ if (promises !== undefined) {
await SafePromise.all(promises);
- linkingStatusMap.set(this, 'linked');
- } catch (err) {
- linkingStatusMap.set(this, 'errored');
- throw err;
+ }
+ } catch (e) {
+ this.#error = e;
+ throw e;
+ } finally {
+ this.#statusOverride = undefined;
}
- }
+ };
- instantiate() {
- const wrap = wrapMap.get(this);
- const status = wrap.getStatus();
- if (status === kInstantiating || status === kEvaluating)
- throw new ERR_VM_MODULE_STATUS('must not be instantiating or evaluating');
- if (linkingStatusMap.get(this) !== 'linked')
- throw new ERR_VM_MODULE_NOT_LINKED();
- wrap.instantiate();
- }
async evaluate(options = {}) {
+ try {
+ this.#wrap;
+ } catch {
+ throw new ERR_VM_MODULE_NOT_MODULE();
+ }
+
if (typeof options !== 'object' || options === null) {
throw new ERR_INVALID_ARG_TYPE('options', 'Object', options);
}
@@ -229,24 +269,41 @@ class SourceTextModule {
} else {
validateUint32(timeout, 'options.timeout', true);
}
-
const { breakOnSigint = false } = options;
if (typeof breakOnSigint !== 'boolean') {
throw new ERR_INVALID_ARG_TYPE('options.breakOnSigint', 'boolean',
breakOnSigint);
}
-
- const wrap = wrapMap.get(this);
- const status = wrap.getStatus();
+ const status = this.#wrap.getStatus();
if (status !== kInstantiated &&
status !== kEvaluated &&
status !== kErrored) {
throw new ERR_VM_MODULE_STATUS(
- 'must be one of instantiated, evaluated, and errored'
+ 'must be one of linked, evaluated, or errored'
);
}
- const result = wrap.evaluate(timeout, breakOnSigint);
- return { result, __proto__: null };
+ const result = this.#wrap.evaluate(timeout, breakOnSigint);
+ return { __proto__: null, result };
+ }
+
+ static importModuleDynamicallyWrap(importModuleDynamically) {
+ // Named declaration for function name
+ const importModuleDynamicallyWrapper = async (...args) => {
+ const m = await importModuleDynamically(...args);
+ if (isModuleNamespaceObject(m)) {
+ return m;
+ }
+ try {
+ m.#wrap;
+ } catch {
+ throw new ERR_VM_MODULE_NOT_MODULE();
+ }
+ if (m.status === 'errored') {
+ throw m.error;
+ }
+ return m.namespace;
+ };
+ return importModuleDynamicallyWrapper;
}
[customInspectSymbol](depth, options) {
@@ -258,16 +315,19 @@ class SourceTextModule {
const o = Object.create({ constructor: ctor });
o.status = this.status;
- o.linkingStatus = this.linkingStatus;
- o.url = this.url;
+ o.identifier = this.identifier;
o.context = this.context;
return require('internal/util/inspect').inspect(o, options);
}
}
+// Declared as static to allow access to #wrap
+const importModuleDynamicallyWrap =
+ SourceTextModule.importModuleDynamicallyWrap;
+delete SourceTextModule.importModuleDynamicallyWrap;
+
module.exports = {
SourceTextModule,
wrapToModuleMap,
- wrapMap,
- linkingStatusMap,
+ importModuleDynamicallyWrap,
};
diff --git a/lib/vm.js b/lib/vm.js
index ec6614e661..90f332c775 100644
--- a/lib/vm.js
+++ b/lib/vm.js
@@ -31,10 +31,8 @@ const {
} = internalBinding('contextify');
const {
ERR_INVALID_ARG_TYPE,
- ERR_VM_MODULE_NOT_MODULE,
} = require('internal/errors').codes;
const {
- isModuleNamespaceObject,
isArrayBufferView,
} = require('internal/util/types');
const {
@@ -100,21 +98,13 @@ class Script extends ContextifyScript {
'function',
importModuleDynamically);
}
- const { wrapMap, linkingStatusMap } =
+ const { importModuleDynamicallyWrap } =
require('internal/vm/source_text_module');
const { callbackMap } = internalBinding('module_wrap');
- callbackMap.set(this, { importModuleDynamically: async (...args) => {
- const m = await importModuleDynamically(...args);
- if (isModuleNamespaceObject(m)) {
- return m;
- }
- if (!m || !wrapMap.has(m))
- throw new ERR_VM_MODULE_NOT_MODULE();
- const childLinkingStatus = linkingStatusMap.get(m);
- if (childLinkingStatus === 'errored')
- throw m.error;
- return m.namespace;
- } });
+ callbackMap.set(this, {
+ importModuleDynamically:
+ importModuleDynamicallyWrap(importModuleDynamically),
+ });
}
}
diff --git a/src/module_wrap.cc b/src/module_wrap.cc
index aeb44675f6..4a572c00e1 100644
--- a/src/module_wrap.cc
+++ b/src/module_wrap.cc
@@ -331,7 +331,7 @@ void ModuleWrap::Evaluate(const FunctionCallbackInfo<Value>& args) {
args.GetReturnValue().Set(result.ToLocalChecked());
}
-void ModuleWrap::Namespace(const FunctionCallbackInfo<Value>& args) {
+void ModuleWrap::GetNamespace(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args);
Isolate* isolate = args.GetIsolate();
ModuleWrap* obj;
@@ -1328,8 +1328,12 @@ void ModuleWrap::HostInitializeImportMetaObjectCallback(
Local<Function> callback =
env->host_initialize_import_meta_object_callback();
Local<Value> args[] = { wrap, meta };
- callback->Call(context, Undefined(env->isolate()), arraysize(args), args)
- .ToLocalChecked();
+ TryCatchScope try_catch(env);
+ USE(callback->Call(
+ context, Undefined(env->isolate()), arraysize(args), args));
+ if (try_catch.HasCaught() && !try_catch.HasTerminated()) {
+ try_catch.ReThrow();
+ }
}
void ModuleWrap::SetInitializeImportMetaObjectCallback(
@@ -1360,7 +1364,7 @@ void ModuleWrap::Initialize(Local<Object> target,
env->SetProtoMethod(tpl, "link", Link);
env->SetProtoMethod(tpl, "instantiate", Instantiate);
env->SetProtoMethod(tpl, "evaluate", Evaluate);
- env->SetProtoMethodNoSideEffect(tpl, "namespace", Namespace);
+ env->SetProtoMethodNoSideEffect(tpl, "getNamespace", GetNamespace);
env->SetProtoMethodNoSideEffect(tpl, "getStatus", GetStatus);
env->SetProtoMethodNoSideEffect(tpl, "getError", GetError);
env->SetProtoMethodNoSideEffect(tpl, "getStaticDependencySpecifiers",
diff --git a/src/module_wrap.h b/src/module_wrap.h
index 6c79781a9d..9e2aa3b948 100644
--- a/src/module_wrap.h
+++ b/src/module_wrap.h
@@ -57,7 +57,7 @@ class ModuleWrap : public BaseObject {
static void Link(const v8::FunctionCallbackInfo<v8::Value>& args);
static void Instantiate(const v8::FunctionCallbackInfo<v8::Value>& args);
static void Evaluate(const v8::FunctionCallbackInfo<v8::Value>& args);
- static void Namespace(const v8::FunctionCallbackInfo<v8::Value>& args);
+ static void GetNamespace(const v8::FunctionCallbackInfo<v8::Value>& args);
static void GetStatus(const v8::FunctionCallbackInfo<v8::Value>& args);
static void GetError(const v8::FunctionCallbackInfo<v8::Value>& args);
static void GetStaticDependencySpecifiers(
diff --git a/test/parallel/test-internal-module-wrap.js b/test/parallel/test-internal-module-wrap.js
index ee0b722d45..116a300543 100644
--- a/test/parallel/test-internal-module-wrap.js
+++ b/test/parallel/test-internal-module-wrap.js
@@ -25,5 +25,5 @@ const bar = new ModuleWrap('export const five = 5', 'bar');
foo.instantiate();
assert.strictEqual(await foo.evaluate(-1, false), 6);
- assert.strictEqual(foo.namespace().five, 5);
+ assert.strictEqual(foo.getNamespace().five, 5);
})();
diff --git a/test/parallel/test-util-inspect-namespace.js b/test/parallel/test-util-inspect-namespace.js
index f2b6e57178..89b26fcdbc 100644
--- a/test/parallel/test-util-inspect-namespace.js
+++ b/test/parallel/test-util-inspect-namespace.js
@@ -11,7 +11,6 @@ const { inspect } = require('util');
(async () => {
const m = new SourceTextModule('export const a = 1; export var b = 2');
await m.link(() => 0);
- m.instantiate();
assert.strictEqual(
inspect(m.namespace),
'[Module] { a: <uninitialized>, b: undefined }');
diff --git a/test/parallel/test-util-types.js b/test/parallel/test-util-types.js
index 69ebaaba12..6a9bad0169 100644
--- a/test/parallel/test-util-types.js
+++ b/test/parallel/test-util-types.js
@@ -281,7 +281,6 @@ for (const [ value, _method ] of [
(async () => {
const m = new vm.SourceTextModule('');
await m.link(() => 0);
- m.instantiate();
await m.evaluate();
assert.ok(types.isModuleNamespaceObject(m.namespace));
})();
diff --git a/test/parallel/test-vm-module-basic.js b/test/parallel/test-vm-module-basic.js
index 76a8e8a3d2..cbe5e29d3c 100644
--- a/test/parallel/test-vm-module-basic.js
+++ b/test/parallel/test-vm-module-basic.js
@@ -17,10 +17,9 @@ const util = require('util');
'baz = foo; typeofProcess = typeof process; typeof Object;',
{ context }
);
- assert.strictEqual(m.status, 'uninstantiated');
+ assert.strictEqual(m.status, 'unlinked');
await m.link(common.mustNotCall());
- m.instantiate();
- assert.strictEqual(m.status, 'instantiated');
+ assert.strictEqual(m.status, 'linked');
const result = await m.evaluate();
assert.strictEqual(m.status, 'evaluated');
assert.strictEqual(Object.getPrototypeOf(result), null);
@@ -37,7 +36,6 @@ const util = require('util');
'global.vmResult = "foo"; Object.prototype.toString.call(process);'
);
await m.link(common.mustNotCall());
- m.instantiate();
const { result } = await m.evaluate();
assert.strictEqual(global.vmResult, 'foo');
assert.strictEqual(result, '[object process]');
@@ -47,22 +45,21 @@ const util = require('util');
(async () => {
const m = new SourceTextModule('while (true) {}');
await m.link(common.mustNotCall());
- m.instantiate();
await m.evaluate({ timeout: 500 })
.then(() => assert(false), () => {});
})();
-// Check the generated url for each module
+// Check the generated identifier for each module
(async () => {
const context1 = createContext({ });
const context2 = createContext({ });
const m1 = new SourceTextModule('1', { context: context1 });
- assert.strictEqual(m1.url, 'vm:module(0)');
+ assert.strictEqual(m1.identifier, 'vm:module(0)');
const m2 = new SourceTextModule('2', { context: context1 });
- assert.strictEqual(m2.url, 'vm:module(1)');
+ assert.strictEqual(m2.identifier, 'vm:module(1)');
const m3 = new SourceTextModule('3', { context: context2 });
- assert.strictEqual(m3.url, 'vm:module(0)');
+ assert.strictEqual(m3.identifier, 'vm:module(0)');
})();
// Check inspection of the instance
@@ -72,13 +69,19 @@ const util = require('util');
assert.strictEqual(
util.inspect(m),
- "SourceTextModule {\n status: 'uninstantiated',\n linkingStatus:" +
- " 'unlinked',\n url: 'vm:module(0)',\n context: { foo: 'bar' }\n}"
+ `SourceTextModule {
+ status: 'unlinked',
+ identifier: 'vm:module(0)',
+ context: { foo: 'bar' }
+}`
);
assert.strictEqual(
m[util.inspect.custom].call(Object.create(null)),
- 'SourceTextModule {\n status: undefined,\n linkingStatus: undefined,' +
- '\n url: undefined,\n context: undefined\n}'
+ `SourceTextModule {
+ status: undefined,
+ identifier: undefined,
+ context: undefined
+}`,
);
assert.strictEqual(util.inspect(m, { depth: -1 }), '[SourceTextModule]');
}
diff --git a/test/parallel/test-vm-module-dynamic-import.js b/test/parallel/test-vm-module-dynamic-import.js
index 600f455e93..897d9f27d7 100644
--- a/test/parallel/test-vm-module-dynamic-import.js
+++ b/test/parallel/test-vm-module-dynamic-import.js
@@ -10,7 +10,6 @@ const { Script, SourceTextModule, createContext } = require('vm');
async function testNoCallback() {
const m = new SourceTextModule('import("foo")', { context: createContext() });
await m.link(common.mustNotCall());
- m.instantiate();
const { result } = await m.evaluate();
let threw = false;
try {
@@ -25,7 +24,6 @@ async function testNoCallback() {
async function test() {
const foo = new SourceTextModule('export const a = 1;');
await foo.link(common.mustNotCall());
- foo.instantiate();
await foo.evaluate();
{
@@ -50,7 +48,6 @@ async function test() {
}),
});
await m.link(common.mustNotCall());
- m.instantiate();
const { result } = await m.evaluate();
assert.strictEqual(foo.namespace, await result);
}
@@ -63,7 +60,6 @@ async function testInvalid() {
}),
});
await m.link(common.mustNotCall());
- m.instantiate();
const { result } = await m.evaluate();
await result.catch(common.mustCall((e) => {
assert.strictEqual(e.code, 'ERR_VM_MODULE_NOT_MODULE');
diff --git a/test/parallel/test-vm-module-dynamic-namespace.js b/test/parallel/test-vm-module-dynamic-namespace.js
index bcd91daebd..987b21f2ec 100644
--- a/test/parallel/test-vm-module-dynamic-namespace.js
+++ b/test/parallel/test-vm-module-dynamic-namespace.js
@@ -1,35 +1,30 @@
'use strict';
-// Flags: --experimental-vm-modules --expose-internals
-//
+// Flags: --experimental-vm-modules
+
const common = require('../common');
const assert = require('assert');
const { types } = require('util');
-const { SourceTextModule, wrapMap } = require('internal/vm/source_text_module');
-
-const { importModuleDynamicallyCallback } =
- require('internal/process/esm_loader');
+const { SourceTextModule } = require('vm');
async function getNamespace() {
const m = new SourceTextModule('');
await m.link(() => 0);
- m.instantiate();
await m.evaluate();
return m.namespace;
}
(async () => {
const namespace = await getNamespace();
- const m = new SourceTextModule('export const A = "A";', {
+ const m = new SourceTextModule('export const A = "A"; import("");', {
importModuleDynamically: common.mustCall((specifier, wrap) => {
return namespace;
})
});
await m.link(() => 0);
- m.instantiate();
- await m.evaluate();
- const ns = await importModuleDynamicallyCallback(wrapMap.get(m));
+ const { result } = await m.evaluate();
+ const ns = await result;
assert.ok(types.isModuleNamespaceObject(ns));
})().then(common.mustCall());
diff --git a/test/parallel/test-vm-module-errors.js b/test/parallel/test-vm-module-errors.js
index a92863b125..e76bbbb0e1 100644
--- a/test/parallel/test-vm-module-errors.js
+++ b/test/parallel/test-vm-module-errors.js
@@ -23,7 +23,7 @@ async function checkArgType() {
});
for (const invalidOptions of [
- 0, 1, null, true, 'str', () => {}, { url: 0 }, Symbol.iterator,
+ 0, 1, null, true, 'str', () => {}, { identifier: 0 }, Symbol.iterator,
{ context: null }, { context: 'hucairz' }, { context: {} }
]) {
common.expectsError(() => {
@@ -52,7 +52,7 @@ async function checkModuleState() {
await assert.rejects(async () => {
const m = new SourceTextModule('');
await m.link(common.mustNotCall());
- assert.strictEqual(m.linkingStatus, 'linked');
+ assert.strictEqual(m.status, 'linked');
await m.link(common.mustNotCall());
}, {
code: 'ERR_VM_MODULE_ALREADY_LINKED'
@@ -61,54 +61,18 @@ async function checkModuleState() {
await assert.rejects(async () => {
const m = new SourceTextModule('');
m.link(common.mustNotCall());
- assert.strictEqual(m.linkingStatus, 'linking');
+ assert.strictEqual(m.status, 'linking');
await m.link(common.mustNotCall());
}, {
code: 'ERR_VM_MODULE_ALREADY_LINKED'
});
- common.expectsError(() => {
- const m = new SourceTextModule('');
- m.instantiate();
- }, {
- code: 'ERR_VM_MODULE_NOT_LINKED'
- });
-
- await assert.rejects(async () => {
- const m = new SourceTextModule('import "foo";');
- try {
- await m.link(common.mustCall(() => ({})));
- } catch {
- assert.strictEqual(m.linkingStatus, 'errored');
- m.instantiate();
- }
- }, {
- code: 'ERR_VM_MODULE_NOT_LINKED'
- });
-
- {
- const m = new SourceTextModule('import "foo";');
- await m.link(common.mustCall(async (specifier, module) => {
- assert.strictEqual(module, m);
- assert.strictEqual(specifier, 'foo');
- assert.strictEqual(m.linkingStatus, 'linking');
- common.expectsError(() => {
- m.instantiate();
- }, {
- code: 'ERR_VM_MODULE_NOT_LINKED'
- });
- return new SourceTextModule('');
- }));
- m.instantiate();
- await m.evaluate();
- }
-
await assert.rejects(async () => {
const m = new SourceTextModule('');
await m.evaluate();
}, {
code: 'ERR_VM_MODULE_STATUS',
- message: 'Module status must be one of instantiated, evaluated, and errored'
+ message: 'Module status must be one of linked, evaluated, or errored'
});
await assert.rejects(async () => {
@@ -120,14 +84,6 @@ async function checkModuleState() {
'Received type boolean'
});
- await assert.rejects(async () => {
- const m = await createEmptyLinkedModule();
- await m.evaluate();
- }, {
- code: 'ERR_VM_MODULE_STATUS',
- message: 'Module status must be one of instantiated, evaluated, and errored'
- });
-
common.expectsError(() => {
const m = new SourceTextModule('');
m.error;
@@ -138,7 +94,6 @@ async function checkModuleState() {
await assert.rejects(async () => {
const m = await createEmptyLinkedModule();
- m.instantiate();
await m.evaluate();
m.error;
}, {
@@ -151,15 +106,7 @@ async function checkModuleState() {
m.namespace;
}, {
code: 'ERR_VM_MODULE_STATUS',
- message: 'Module status must not be uninstantiated or instantiating'
- });
-
- await assert.rejects(async () => {
- const m = await createEmptyLinkedModule();
- m.namespace;
- }, {
- code: 'ERR_VM_MODULE_STATUS',
- message: 'Module status must not be uninstantiated or instantiating'
+ message: 'Module status must not be unlinked or linking'
});
}
@@ -170,7 +117,7 @@ async function checkLinking() {
try {
await m.link(common.mustCall(() => ({})));
} catch (err) {
- assert.strictEqual(m.linkingStatus, 'errored');
+ assert.strictEqual(m.status, 'errored');
throw err;
}
}, {
@@ -185,7 +132,7 @@ async function checkLinking() {
try {
await bar.link(common.mustCall(() => foo));
} catch (err) {
- assert.strictEqual(bar.linkingStatus, 'errored');
+ assert.strictEqual(bar.status, 'errored');
throw err;
}
}, {
@@ -199,7 +146,7 @@ async function checkLinking() {
} catch {
// ignored
} finally {
- assert.strictEqual(erroredModule.linkingStatus, 'errored');
+ assert.strictEqual(erroredModule.status, 'errored');
}
const rootModule = new SourceTextModule('import "errored";');
@@ -224,19 +171,17 @@ common.expectsError(() => {
async function checkExecution() {
await (async () => {
const m = new SourceTextModule('import { nonexistent } from "module";');
- await m.link(common.mustCall(() => new SourceTextModule('')));
// There is no code for this exception since it is thrown by the JavaScript
// engine.
- assert.throws(() => {
- m.instantiate();
+ await assert.rejects(() => {
+ return m.link(common.mustCall(() => new SourceTextModule('')));
}, SyntaxError);
})();
await (async () => {
const m = new SourceTextModule('throw new Error();');
await m.link(common.mustNotCall());
- m.instantiate();
const evaluatePromise = m.evaluate();
await evaluatePromise.catch(() => {});
assert.strictEqual(m.status, 'errored');
diff --git a/test/parallel/test-vm-module-import-meta.js b/test/parallel/test-vm-module-import-meta.js
index 4886464f34..1db4467b08 100644
--- a/test/parallel/test-vm-module-import-meta.js
+++ b/test/parallel/test-vm-module-import-meta.js
@@ -14,7 +14,6 @@ async function testBasic() {
})
});
await m.link(common.mustNotCall());
- m.instantiate();
const { result } = await m.evaluate();
assert.strictEqual(typeof result, 'object');
assert.strictEqual(Object.getPrototypeOf(result), null);
diff --git a/test/parallel/test-vm-module-link.js b/test/parallel/test-vm-module-link.js
index 20518c4054..9678d13737 100644
--- a/test/parallel/test-vm-module-link.js
+++ b/test/parallel/test-vm-module-link.js
@@ -23,8 +23,6 @@ async function simple() {
return foo;
}));
- bar.instantiate();
-
assert.strictEqual((await bar.evaluate()).result, 5);
}
@@ -49,7 +47,6 @@ async function depth() {
const baz = await getProxy('bar', bar);
const barz = await getProxy('baz', baz);
- barz.instantiate();
await barz.evaluate();
assert.strictEqual(barz.namespace.default, 5);
@@ -67,20 +64,19 @@ async function circular() {
return foo;
}
`);
- await foo.link(common.mustCall(async (fooSpecifier, fooModule) => {
- assert.strictEqual(fooModule, foo);
- assert.strictEqual(fooSpecifier, 'bar');
- await bar.link(common.mustCall((barSpecifier, barModule) => {
- assert.strictEqual(barModule, bar);
- assert.strictEqual(barSpecifier, 'foo');
- assert.strictEqual(foo.linkingStatus, 'linking');
- return foo;
- }));
- assert.strictEqual(bar.linkingStatus, 'linked');
- return bar;
- }));
+ await foo.link(common.mustCall(async (specifier, module) => {
+ if (specifier === 'bar') {
+ assert.strictEqual(module, foo);
+ return bar;
+ }
+ assert.strictEqual(specifier, 'foo');
+ assert.strictEqual(module, bar);
+ assert.strictEqual(foo.status, 'linking');
+ return foo;
+ }, 2));
+
+ assert.strictEqual(bar.status, 'linked');
- foo.instantiate();
await foo.evaluate();
assert.strictEqual(foo.namespace.default, 42);
}
@@ -109,19 +105,20 @@ async function circular2() {
`
};
const moduleMap = new Map();
- const rootModule = new SourceTextModule(sourceMap.root, { url: 'vm:root' });
+ const rootModule = new SourceTextModule(sourceMap.root, {
+ identifier: 'vm:root',
+ });
async function link(specifier, referencingModule) {
if (moduleMap.has(specifier)) {
return moduleMap.get(specifier);
}
const mod = new SourceTextModule(sourceMap[specifier], {
- url: new URL(specifier, 'file:///').href,
+ identifier: new URL(specifier, 'file:///').href,
});
moduleMap.set(specifier, mod);
return mod;
}
await rootModule.link(link);
- rootModule.instantiate();
await rootModule.evaluate();
}
diff --git a/test/parallel/test-vm-module-reevaluate.js b/test/parallel/test-vm-module-reevaluate.js
index c3914f362f..4767541dd2 100644
--- a/test/parallel/test-vm-module-reevaluate.js
+++ b/test/parallel/test-vm-module-reevaluate.js
@@ -14,7 +14,6 @@ const finished = common.mustCall();
{
const m = new SourceTextModule('1');
await m.link(common.mustNotCall());
- m.instantiate();
assert.strictEqual((await m.evaluate()).result, 1);
assert.strictEqual((await m.evaluate()).result, undefined);
assert.strictEqual((await m.evaluate()).result, undefined);
@@ -23,7 +22,6 @@ const finished = common.mustCall();
{
const m = new SourceTextModule('throw new Error()');
await m.link(common.mustNotCall());
- m.instantiate();
let threw = false;
try {