Test that resetting [[ModuleAsyncEvaluationCount]] is unobserbable

This commit is contained in:
Nicolò Ribaudo 2025-10-15 18:27:53 +02:00 committed by Ms2ger
parent 687cf880eb
commit d2940bdbb0
7 changed files with 117 additions and 0 deletions

View File

@ -0,0 +1,6 @@
// Copyright (C) 2025 Igalia, S.L. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
import { logs } from "./unobservable-global-async-evaluation-count-reset-setup_FIXTURE.js";
import "./unobservable-global-async-evaluation-count-reset-b_FIXTURE.js";
logs.push("A");

View File

@ -0,0 +1,6 @@
// Copyright (C) 2025 Igalia, S.L. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
import { pB, pB_start } from "./unobservable-global-async-evaluation-count-reset-setup_FIXTURE.js";
pB_start.resolve();
await pB.promise;

View File

@ -0,0 +1,4 @@
// Copyright (C) 2025 Igalia, S.L. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
await 1;

View File

@ -0,0 +1,7 @@
// Copyright (C) 2025 Igalia, S.L. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
import { logs } from "./unobservable-global-async-evaluation-count-reset-setup_FIXTURE.js";
import "./unobservable-global-async-evaluation-count-reset-e_FIXTURE.js";
import "./unobservable-global-async-evaluation-count-reset-b_FIXTURE.js";
logs.push("D");

View File

@ -0,0 +1,5 @@
// Copyright (C) 2025 Igalia, S.L. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
import { pE_start } from "./unobservable-global-async-evaluation-count-reset-setup_FIXTURE.js";
pE_start.resolve();

View File

@ -0,0 +1,7 @@
// Copyright (C) 2025 Igalia, S.L. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
export const logs = [];
export const pB = Promise.withResolvers();
export const pB_start = Promise.withResolvers();
export const pE_start = Promise.withResolvers();

View File

@ -0,0 +1,82 @@
// Copyright (C) 2025 Igalia, S.L. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
description: >
An implementation may unobservably reset [[ModuleAsyncEvaluationCount]] to 0
whenever there are no pending modules.
info: |
IncrementModuleAsyncEvaluationCount ( )
1. Let AR be the Agent Record of the surrounding agent.
2. Let count be AR.[[ModuleAsyncEvaluationCount]].
3. Set AR.[[ModuleAsyncEvaluationCount]] to count + 1.
4. Return count.
NOTE: This value is only used to keep track of the relative evaluation order
between pending modules. An implementation may unobservably reset
[[ModuleAsyncEvaluationCount]] to 0 whenever there are no pending modules.
InnerModuleEvaluation ( module, stack, index )
...
12. If module.[[PendingAsyncDependencies]] > 0 or module.[[HasTLA]] is true, then
a. Assert: module.[[AsyncEvaluationOrder]] is unset.
b. Set module.[[AsyncEvaluationOrder]] to IncrementModuleAsyncEvaluationCount().
...
AsyncModuleExecutionFulfilled ( module )
...
9. Perform GatherAvailableAncestors(module, execList).
10. ...
11. Let sortedExecList be a List whose elements are the elements of execList, sorted by their [[AsyncEvaluationOrder]] field in ascending order.
12. For each Cyclic Module Record m of sortedExecList, do
a. If m.[[Status]] is evaluated, then
i. Assert: m.[[EvaluationError]] is not empty.
b. Else if m.[[HasTLA]] is true, then
i. Perform ExecuteAsyncModule(m).
c. Else,
i. Let result be m.ExecuteModule().
...
Module graph (the order of dependencies in each module is important, and it's left-to-right):
A C D
E
B
Where B and C have top-level await. The test orchestrates the evaluation order such that:
- Import A first
- Once B starts evaluating, import C and immediately resolve its top-level await
- Once C finishes evaluating, import D
- Once E is evaluated, resolve B's await
esid: sec-IncrementModuleAsyncEvaluationCount
flags: [module, async]
features: [top-level-await, dynamic-import, promise-with-resolvers]
includes: [compareArray.js]
---*/
import { logs, pB, pB_start, pE_start } from "./unobservable-global-async-evaluation-count-reset-setup_FIXTURE.js";
const pA = import("./unobservable-global-async-evaluation-count-reset-a_FIXTURE.js");
let pD;
pB_start.promise.then(() => {
return import("./unobservable-global-async-evaluation-count-reset-c_FIXTURE.js");
}).then(() => {
pD = import("./unobservable-global-async-evaluation-count-reset-d_FIXTURE.js");
return pE_start.promise;
}).then(() => {
pB.resolve();
return Promise.all([pA, pD]);
}).then(() => {
assert.compareArray(logs, ["A", "D"], "A should evaluate before D");
}).then($DONE, $DONE);