tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

commit e02a390fa4b4abd0040e608ed06214c7b04d7eff
parent 577c80a38fcf58c95ef4fc652fa56a4cdcf82ea4
Author: Nicolò Ribaudo <nribaudo@igalia.com>
Date:   Fri,  3 Oct 2025 14:44:09 +0000

Bug 1992103 - Align async modules rejection order with fulfillment order r=jonco

This patch inverts the order in which we reject promises in
AsyncModuleExecutionRejected to match AsyncModuleExecutionFulfilled:
first the promise corresponding to the leaf module (the one that throws)
is rejected, and then its ancestors.

This change was discussed at the July 2025 TC39 meeting.

Spec PR: https://github.com/tc39/ecma262/pull/3695
test262: https://github.com/tc39/test262/pull/4591

Differential Revision: https://phabricator.services.mozilla.com/D267210

Diffstat:
Mjs/src/vm/Modules.cpp | 35++++++++++++++++++-----------------
1 file changed, 18 insertions(+), 17 deletions(-)

diff --git a/js/src/vm/Modules.cpp b/js/src/vm/Modules.cpp @@ -2507,10 +2507,10 @@ void js::AsyncModuleExecutionRejected(JSContext* cx, // Step 2. Assert: module.[[Status]] is evaluating-async. MOZ_ASSERT(module->status() == ModuleStatus::EvaluatingAsync); - // Step 3. Assert: module.[[AsyncEvaluation]] is true. + // Step 3. Assert: module.[[AsyncEvaluationOrder]] is an integer. MOZ_ASSERT(module->isAsyncEvaluating()); - // Step 4. 4. Assert: module.[[EvaluationError]] is empty. + // Step 4. Assert: module.[[EvaluationError]] is empty. MOZ_ASSERT(!module->hadEvaluationError()); ModuleObject::onTopLevelEvaluationFinished(module); @@ -2521,25 +2521,15 @@ void js::AsyncModuleExecutionRejected(JSContext* cx, // Step 6. Set module.[[Status]] to evaluated. MOZ_ASSERT(module->status() == ModuleStatus::Evaluated); + // Step 7. Set module.[[AsyncEvaluationOrder]] to done. module->clearAsyncEvaluatingPostOrder(); - // Step 7. For each Cyclic Module Record m of module.[[AsyncParentModules]], - // do: - Rooted<ListObject*> parents(cx, module->asyncParentModules()); - Rooted<ModuleObject*> parent(cx); - for (uint32_t i = 0; i < parents->length(); i++) { - parent = &parents->get(i).toObject().as<ModuleObject>(); - - // Step 7.a. Perform AsyncModuleExecutionRejected(m, error). - AsyncModuleExecutionRejected(cx, parent, error); - } - - // Step 8. If module.[[TopLevelCapability]] is not empty, then: + // Step 9. If module.[[TopLevelCapability]] is not empty, then: if (module->hasTopLevelCapability()) { - // Step 8.a. Assert: module.[[CycleRoot]] is module. + // Step 9.a. Assert: module.[[CycleRoot]] is module. MOZ_ASSERT(module->getCycleRoot() == module); - // Step 8.b. Perform ! Call(module.[[TopLevelCapability]].[[Reject]], + // Step 9.b. Perform ! Call(module.[[TopLevelCapability]].[[Reject]], // undefined, error). if (!ModuleObject::topLevelCapabilityReject(cx, module, error)) { // If Reject fails, there's nothing more we can do here. @@ -2547,7 +2537,18 @@ void js::AsyncModuleExecutionRejected(JSContext* cx, } } - // Step 9. Return unused. + // Step 10. For each Cyclic Module Record m of module.[[AsyncParentModules]], + // do: + Rooted<ListObject*> parents(cx, module->asyncParentModules()); + Rooted<ModuleObject*> parent(cx); + for (uint32_t i = 0; i < parents->length(); i++) { + parent = &parents->get(i).toObject().as<ModuleObject>(); + + // Step 10.a. Perform AsyncModuleExecutionRejected(m, error). + AsyncModuleExecutionRejected(cx, parent, error); + } + + // Step 11. Return unused. } // https://tc39.es/proposal-import-attributes/#sec-evaluate-import-call