| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent b07ad39 commit f13589f
9 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -318,7 +318,7 @@ class ModuleLoader { | |||
| 318 | 318 | * @param {object} importAttributes import attributes from the import statement. | |
| 319 | 319 | * @returns {ModuleJobBase} | |
| 320 | 320 | */ | |
| 321 | - getModuleWrapForRequire(specifier, parentURL, importAttributes) { | ||
| 321 | + getModuleJobForRequire(specifier, parentURL, importAttributes) { | ||
| 322 | 322 | assert(getOptionValue('--experimental-require-module')); | |
| 323 | 323 | ||
| 324 | 324 | if (canParse(specifier)) { | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -1,8 +1,8 @@ | |||
| 1 | 1 | 'use strict'; | |
| 2 | 2 | ||
| 3 | 3 | const { | |
| 4 | + Array, | ||
| 4 | 5 | ArrayPrototypeJoin, | |
| 5 | - ArrayPrototypePush, | ||
| 6 | 6 | ArrayPrototypeSome, | |
| 7 | 7 | FunctionPrototype, | |
| 8 | 8 | ObjectSetPrototypeOf, | |
@@ -82,31 +82,8 @@ class ModuleJob extends ModuleJobBase { | |||
| 82 | 82 | this.modulePromise = PromiseResolve(this.modulePromise); | |
| 83 | 83 | } | |
| 84 | 84 | ||
| 85 | - // 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 | - }; | ||
| 108 | 85 | // Promise for the list of all dependencyJobs. | |
| 109 | - this.linked = link(); | ||
| 86 | + this.linked = this._link(); | ||
| 110 | 87 | // This promise is awaited later anyway, so silence | |
| 111 | 88 | // 'unhandled rejection' warnings. | |
| 112 | 89 | PromisePrototypeThen(this.linked, undefined, noop); | |
@@ -116,6 +93,49 @@ class ModuleJob extends ModuleJobBase { | |||
| 116 | 93 | this.instantiated = undefined; | |
| 117 | 94 | } | |
| 118 | 95 | ||
| 96 | + /** | ||
| 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 | + | ||
| 119 | 139 | instantiate() { | |
| 120 | 140 | if (this.instantiated === undefined) { | |
| 121 | 141 | this.instantiated = this._instantiate(); | |
@@ -269,18 +289,20 @@ class ModuleJobSync extends ModuleJobBase { | |||
| 269 | 289 | super(url, importAttributes, moduleWrap, isMain, inspectBrk, true); | |
| 270 | 290 | assert(this.module instanceof ModuleWrap); | |
| 271 | 291 | this.#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); | ||
| 274 | 297 | for (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; | ||
| 282 | 303 | } | |
| 283 | - this.linked = linked; | ||
| 304 | + this.module.link(specifiers, modules); | ||
| 305 | + this.linked = jobs; | ||
| 284 | 306 | } | |
| 285 | 307 | ||
| 286 | 308 | get modulePromise() { | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -2,16 +2,20 @@ | |||
| 2 | 2 | ||
| 3 | 3 | const assert = require('internal/assert'); | |
| 4 | 4 | const { | |
| 5 | + Array, | ||
| 5 | 6 | ArrayIsArray, | |
| 6 | 7 | ArrayPrototypeForEach, | |
| 7 | 8 | ArrayPrototypeIndexOf, | |
| 9 | + ArrayPrototypeMap, | ||
| 8 | 10 | ArrayPrototypeSome, | |
| 9 | 11 | ObjectDefineProperty, | |
| 10 | 12 | ObjectGetPrototypeOf, | |
| 11 | 13 | ObjectPrototypeHasOwnProperty, | |
| 12 | 14 | ObjectSetPrototypeOf, | |
| 15 | + PromiseResolve, | ||
| 16 | + PromisePrototypeThen, | ||
| 13 | 17 | ReflectApply, | |
| 14 | - SafePromiseAllReturnVoid, | ||
| 18 | + SafePromiseAllReturnArrayLike, | ||
| 15 | 19 | Symbol, | |
| 16 | 20 | SymbolToStringTag, | |
| 17 | 21 | TypeError, | |
@@ -293,44 +297,61 @@ class SourceTextModule extends Module { | |||
| 293 | 297 | importModuleDynamically, | |
| 294 | 298 | }); | |
| 295 | 299 | ||
| 296 | - this[kLink] = async (linker) => { | ||
| 297 | - this.#statusOverride = 'linking'; | ||
| 300 | + this[kDependencySpecifiers] = undefined; | ||
| 301 | + } | ||
| 298 | 302 | ||
| 299 | - const promises = this[kWrap].link(async (identifier, attributes) => { | ||
| 300 | - const module = await linker(identifier, this, { attributes, assert: attributes }); | ||
| 301 | - if (!isModule(module)) { | ||
| 302 | - throw new ERR_VM_MODULE_NOT_MODULE(); | ||
| 303 | - } | ||
| 304 | - if (module.context !== this.context) { | ||
| 305 | - throw new ERR_VM_MODULE_DIFFERENT_CONTEXT(); | ||
| 306 | - } | ||
| 307 | - if (module.status === 'errored') { | ||
| 308 | - throw new ERR_VM_MODULE_LINK_FAILURE(`request for '${identifier}' resolved to an errored module`, module.error); | ||
| 309 | - } | ||
| 310 | - if (module.status === 'unlinked') { | ||
| 311 | - await module[kLink](linker); | ||
| 312 | - } | ||
| 313 | - return module[kWrap]; | ||
| 303 | + async [kLink](linker) { | ||
| 304 | + this.#statusOverride = 'linking'; | ||
| 305 | + | ||
| 306 | + const moduleRequests = this[kWrap].getModuleRequests(); | ||
| 307 | + // Iterates the module requests and links with the linker. | ||
| 308 | + // Specifiers should be aligned with the moduleRequests array in order. | ||
| 309 | + const specifiers = Array(moduleRequests.length); | ||
| 310 | + const modulePromises = Array(moduleRequests.length); | ||
| 311 | + // Iterates with index to avoid calling into userspace with `Symbol.iterator`. | ||
| 312 | + for (let idx = 0; idx < moduleRequests.length; idx++) { | ||
| 313 | + const { specifier, attributes } = moduleRequests[idx]; | ||
| 314 | + | ||
| 315 | + const linkerResult = linker(specifier, this, { | ||
| 316 | + attributes, | ||
| 317 | + assert: attributes, | ||
| 314 | 318 | }); | |
| 319 | + const modulePromise = PromisePrototypeThen( | ||
| 320 | + PromiseResolve(linkerResult), async (module) => { | ||
| 321 | + if (!isModule(module)) { | ||
| 322 | + throw new ERR_VM_MODULE_NOT_MODULE(); | ||
| 323 | + } | ||
| 324 | + if (module.context !== this.context) { | ||
| 325 | + throw new ERR_VM_MODULE_DIFFERENT_CONTEXT(); | ||
| 326 | + } | ||
| 327 | + if (module.status === 'errored') { | ||
| 328 | + throw new ERR_VM_MODULE_LINK_FAILURE(`request for '${specifier}' resolved to an errored module`, module.error); | ||
| 329 | + } | ||
| 330 | + if (module.status === 'unlinked') { | ||
| 331 | + await module[kLink](linker); | ||
| 332 | + } | ||
| 333 | + return module[kWrap]; | ||
| 334 | + }); | ||
| 335 | + modulePromises[idx] = modulePromise; | ||
| 336 | + specifiers[idx] = specifier; | ||
| 337 | + } | ||
| 315 | 338 | ||
| 316 | - try { | ||
| 317 | - if (promises !== undefined) { | ||
| 318 | - await SafePromiseAllReturnVoid(promises); | ||
| 319 | - } | ||
| 320 | - } catch (e) { | ||
| 321 | - this.#error = e; | ||
| 322 | - throw e; | ||
| 323 | - } finally { | ||
| 324 | - this.#statusOverride = undefined; | ||
| 325 | - } | ||
| 326 | - }; | ||
| 327 | - | ||
| 328 | - this[kDependencySpecifiers] = undefined; | ||
| 339 | + try { | ||
| 340 | + const modules = await SafePromiseAllReturnArrayLike(modulePromises); | ||
| 341 | + this[kWrap].link(specifiers, modules); | ||
| 342 | + } catch (e) { | ||
| 343 | + this.#error = e; | ||
| 344 | + throw e; | ||
| 345 | + } finally { | ||
| 346 | + this.#statusOverride = undefined; | ||
| 347 | + } | ||
| 329 | 348 | } | |
| 330 | 349 | ||
| 331 | 350 | get dependencySpecifiers() { | |
| 332 | 351 | validateInternalField(this, kDependencySpecifiers, 'SourceTextModule'); | |
| 333 | - this[kDependencySpecifiers] ??= this[kWrap].getStaticDependencySpecifiers(); | ||
| 352 | + // TODO(legendecas): add a new getter to expose the import attributes as the value type | ||
| 353 | + // of [[RequestedModules]] is changed in https://tc39.es/proposal-import-attributes/#table-cyclic-module-fields. | ||
| 354 | + this[kDependencySpecifiers] ??= ArrayPrototypeMap(this[kWrap].getModuleRequests(), (request) => request.specifier); | ||
| 334 | 355 | return this[kDependencySpecifiers]; | |
| 335 | 356 | } | |
| 336 | 357 | ||
@@ -392,10 +413,10 @@ class SyntheticModule extends Module { | |||
| 392 | 413 | context, | |
| 393 | 414 | identifier, | |
| 394 | 415 | }); | |
| 416 | + } | ||
| 395 | 417 | ||
| 396 | - this[kLink] = () => this[kWrap].link(() => { | ||
| 397 | - assert.fail('link callback should not be called'); | ||
| 398 | - }); | ||
| 418 | + [kLink]() { | ||
| 419 | + /** nothing to do for synthetic modules */ | ||
| 399 | 420 | } | |
| 400 | 421 | ||
| 401 | 422 | setExport(name, value) { | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -71,6 +71,7 @@ | |||
| 71 | 71 | V(args_string, "args") \ | |
| 72 | 72 | V(asn1curve_string, "asn1Curve") \ | |
| 73 | 73 | V(async_ids_stack_string, "async_ids_stack") \ | |
| 74 | + V(attributes_string, "attributes") \ | ||
| 74 | 75 | V(base_string, "base") \ | |
| 75 | 76 | V(bits_string, "bits") \ | |
| 76 | 77 | V(block_list_string, "blockList") \ | |
@@ -303,6 +304,7 @@ | |||
| 303 | 304 | V(sni_context_string, "sni_context") \ | |
| 304 | 305 | V(source_string, "source") \ | |
| 305 | 306 | V(source_map_url_string, "sourceMapURL") \ | |
| 307 | + V(specifier_string, "specifier") \ | ||
| 306 | 308 | V(stack_string, "stack") \ | |
| 307 | 309 | V(standard_name_string, "standardName") \ | |
| 308 | 310 | V(start_time_string, "startTime") \ | |
@@ -377,6 +379,7 @@ | |||
| 377 | 379 | V(intervalhistogram_constructor_template, v8::FunctionTemplate) \ | |
| 378 | 380 | V(libuv_stream_wrap_ctor_template, v8::FunctionTemplate) \ | |
| 379 | 381 | V(message_port_constructor_template, v8::FunctionTemplate) \ | |
| 382 | + V(module_wrap_constructor_template, v8::FunctionTemplate) \ | ||
| 380 | 383 | V(microtask_queue_ctor_template, v8::FunctionTemplate) \ | |
| 381 | 384 | V(pipe_constructor_template, v8::FunctionTemplate) \ | |
| 382 | 385 | V(promise_wrap_template, v8::ObjectTemplate) \ | |
| Back | FazBrowse Home | New Git URL |
0 commit comments