lib,src: iterate module requests of a module wrap in JS · nodejs/node@f13589f
11'use strict';
2233const {
4+ Array,
45 ArrayPrototypeJoin,
5- ArrayPrototypePush,
66 ArrayPrototypeSome,
77 FunctionPrototype,
88 ObjectSetPrototypeOf,
@@ -82,31 +82,8 @@ class ModuleJob extends ModuleJobBase {
8282this.modulePromise = PromiseResolve(this.modulePromise);
8383}
848485-// Wait for the ModuleWrap instance being linked with all dependencies.
86-const link = async () => {
87-this.module = await this.modulePromise;
88-assert(this.module instanceof ModuleWrap);
89-90-// Explicitly keeping track of dependency jobs is needed in order
91-// to flatten out the dependency graph below in `_instantiate()`,
92-// so that circular dependencies can't cause a deadlock by two of
93-// these `link` callbacks depending on each other.
94-const dependencyJobs = [];
95-const promises = this.module.link(async (specifier, attributes) => {
96-const job = await this.#loader.getModuleJob(specifier, url, attributes);
97-debug(`async link() ${this.url} -> ${specifier}`, job);
98-ArrayPrototypePush(dependencyJobs, job);
99-return job.modulePromise;
100-});
101-102-if (promises !== undefined) {
103-await SafePromiseAllReturnVoid(promises);
104-}
105-106-return SafePromiseAllReturnArrayLike(dependencyJobs);
107-};
10885// Promise for the list of all dependencyJobs.
109-this.linked = link();
86+this.linked = this._link();
11087// This promise is awaited later anyway, so silence
11188// 'unhandled rejection' warnings.
11289PromisePrototypeThen(this.linked, undefined, noop);
@@ -116,6 +93,49 @@ class ModuleJob extends ModuleJobBase {
11693this.instantiated = undefined;
11794}
1189596+/**
97+ * Iterates the module requests and links with the loader.
98+ * @returns {Promise<ModuleJob[]>} Dependency module jobs.
99+ */
100+async _link() {
101+this.module = await this.modulePromise;
102+assert(this.module instanceof ModuleWrap);
103+104+const moduleRequests = this.module.getModuleRequests();
105+// Explicitly keeping track of dependency jobs is needed in order
106+// to flatten out the dependency graph below in `_instantiate()`,
107+// so that circular dependencies can't cause a deadlock by two of
108+// these `link` callbacks depending on each other.
109+// Create an ArrayLike to avoid calling into userspace with `.then`
110+// when returned from the async function.
111+const dependencyJobs = Array(moduleRequests.length);
112+ObjectSetPrototypeOf(dependencyJobs, null);
113+114+// Specifiers should be aligned with the moduleRequests array in order.
115+const specifiers = Array(moduleRequests.length);
116+const modulePromises = Array(moduleRequests.length);
117+// Iterate with index to avoid calling into userspace with `Symbol.iterator`.
118+for (let idx = 0; idx < moduleRequests.length; idx++) {
119+const { specifier, attributes } = moduleRequests[idx];
120+121+const dependencyJobPromise = this.#loader.getModuleJob(
122+specifier, this.url, attributes,
123+);
124+const modulePromise = PromisePrototypeThen(dependencyJobPromise, (job) => {
125+debug(`async link() ${this.url} -> ${specifier}`, job);
126+dependencyJobs[idx] = job;
127+return job.modulePromise;
128+});
129+modulePromises[idx] = modulePromise;
130+specifiers[idx] = specifier;
131+}
132+133+const modules = await SafePromiseAllReturnArrayLike(modulePromises);
134+this.module.link(specifiers, modules);
135+136+return dependencyJobs;
137+}
138+119139instantiate() {
120140if (this.instantiated === undefined) {
121141this.instantiated = this._instantiate();
@@ -269,18 +289,20 @@ class ModuleJobSync extends ModuleJobBase {
269289super(url, importAttributes, moduleWrap, isMain, inspectBrk, true);
270290assert(this.module instanceof ModuleWrap);
271291this.#loader = loader;
272-const moduleRequests = this.module.getModuleRequestsSync();
273-const linked = [];
292+const moduleRequests = this.module.getModuleRequests();
293+// Specifiers should be aligned with the moduleRequests array in order.
294+const specifiers = Array(moduleRequests.length);
295+const modules = Array(moduleRequests.length);
296+const jobs = Array(moduleRequests.length);
274297for (let i = 0; i < moduleRequests.length; ++i) {
275-const { 0: specifier, 1: attributes } = moduleRequests[i];
276-const job = this.#loader.getModuleWrapForRequire(specifier, url, attributes);
277-const isLast = (i === moduleRequests.length - 1);
278-// TODO(joyeecheung): make the resolution callback deal with both promisified
279-// an raw module wraps, then we don't need to wrap it with a promise here.
280-this.module.cacheResolvedWrapsSync(specifier, PromiseResolve(job.module), isLast);
281-ArrayPrototypePush(linked, job);
298+const { specifier, attributes } = moduleRequests[i];
299+const job = this.#loader.getModuleJobForRequire(specifier, url, attributes);
300+specifiers[i] = specifier;
301+modules[i] = job.module;
302+jobs[i] = job;
282303}
283-this.linked = linked;
304+this.module.link(specifiers, modules);
305+this.linked = jobs;
284306}
285307286308get modulePromise() {