tor-browser

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

commit e123932d1854c445432f5b46532b369bab3e0264
parent bc8068f5592a3af1219015633aae1dfed07ba0cc
Author: Nicolò Ribaudo <nribaudo@igalia.com>
Date:   Fri, 17 Oct 2025 09:03:34 +0000

Bug 1992208 - Part 2: Only reset moduleAsyncEvaluatingPostOrder when there are no pending modules r=jonco

This patch fixes the bug by aligning our implementation with the spec
note: we cannot simply reset `moduleAsyncEvaluatingPostOrder` when the
last discovered module settles. Instead, we can only reset it when
*all* previously pending modules have settled.

test262 tests: https://github.com/tc39/test262/pull/4600

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

Diffstat:
Mjs/src/builtin/ModuleObject.cpp | 28+++++++++++++++-------------
Mjs/src/vm/Runtime.cpp | 3++-
Mjs/src/vm/Runtime.h | 15+++++++++------
3 files changed, 26 insertions(+), 20 deletions(-)

diff --git a/js/src/builtin/ModuleObject.cpp b/js/src/builtin/ModuleObject.cpp @@ -691,25 +691,26 @@ void ModuleNamespaceObject::ProxyHandler::finalize(JS::GCContext* gcx, } } +// https://tc39.es/ecma262/#sec-IncrementModuleAsyncEvaluationCount +// 9.6.3 IncrementModuleAsyncEvaluationCount() static uint32_t IncrementModuleAsyncEvaluationCount(JSRuntime* rt) { + if (rt->pendingAsyncModuleEvaluations == 0) { + // From the spec NOTE: + // An implementation may unobservably reset [[ModuleAsyncEvaluationCount]] + // to 0 whenever there are no pending modules. + rt->moduleAsyncEvaluatingPostOrder = 0; + } + uint32_t ordinal = rt->moduleAsyncEvaluatingPostOrder; MOZ_ASSERT(ordinal != ASYNC_EVALUATING_POST_ORDER_DONE); MOZ_ASSERT(ordinal != ASYNC_EVALUATING_POST_ORDER_UNSET); MOZ_ASSERT(ordinal < ASYNC_EVALUATING_POST_ORDER_MAX_VALUE); rt->moduleAsyncEvaluatingPostOrder++; - return ordinal; -} -// Reset the runtime's moduleAsyncEvaluatingPostOrder counter when the last -// module that was async evaluating is finished. -// -// The graph is not re-entrant and any future modules will be independent from -// this one. -static void MaybeResetPostOrderCounter(JSRuntime* rt, - uint32_t finishedPostOrder) { - if (rt->moduleAsyncEvaluatingPostOrder == finishedPostOrder + 1) { - rt->moduleAsyncEvaluatingPostOrder = 0; - } + MOZ_ASSERT(rt->pendingAsyncModuleEvaluations < MAX_UINT32); + rt->pendingAsyncModuleEvaluations++; + + return ordinal; } bool AsyncEvaluationOrder::isUnset() const { @@ -736,7 +737,8 @@ void AsyncEvaluationOrder::set(JSRuntime* rt) { void AsyncEvaluationOrder::setDone(JSRuntime* rt) { MOZ_ASSERT(isInteger()); - MaybeResetPostOrderCounter(rt, value); + MOZ_ASSERT(rt->pendingAsyncModuleEvaluations > 0); + rt->pendingAsyncModuleEvaluations--; value = ASYNC_EVALUATING_POST_ORDER_DONE; } diff --git a/js/src/vm/Runtime.cpp b/js/src/vm/Runtime.cpp @@ -150,7 +150,8 @@ JSRuntime::JSRuntime(JSRuntime* parentRuntime) stackFormat_(parentRuntime ? js::StackFormat::Default : js::StackFormat::SpiderMonkey), wasmInstances(mutexid::WasmRuntimeInstances), - moduleAsyncEvaluatingPostOrder(0) { + moduleAsyncEvaluatingPostOrder(0), + pendingAsyncModuleEvaluations(0) { JS_COUNT_CTOR(JSRuntime); liveRuntimesCount++; diff --git a/js/src/vm/Runtime.h b/js/src/vm/Runtime.h @@ -1074,15 +1074,18 @@ struct JSRuntime { // threads for purposes of wasm::InterruptRunningCode(). js::ExclusiveData<js::wasm::InstanceVector> wasmInstances; - // A counter used when recording the order in which modules had their - // AsyncEvaluation field set to true. This is used to order queued - // evaluations. This is reset when the last module that was async evaluating - // is finished. + // The [[ModuleAsyncEvaluationCount]] field of agent records // - // See https://tc39.es/ecma262/#sec-async-module-execution-fulfilled step 10 - // for use. + // See https://tc39.es/ecma262/#sec-agents. js::MainThreadData<uint32_t> moduleAsyncEvaluatingPostOrder; + // A counter used to detect when there are no pending async modules, so + // that we can reset [[ModuleAsyncEvaluationCount]] to 0. + // + // See the note in + // https://tc39.es/ecma262/#sec-IncrementModuleAsyncEvaluationCount for use. + js::MainThreadData<uint32_t> pendingAsyncModuleEvaluations; + // The implementation-defined abstract operation HostLoadImportedModule. js::MainThreadData<JS::ModuleLoadHook> moduleLoadHook;