Closed Bug 1761590 Opened 3 years ago Closed 3 years ago

Code evaluated inside browser console has microtask level == 0 and results in unexpected evaluation order

Categories

(DevTools :: Console, defect)

defect

Tracking

(firefox101 fixed)

RESOLVED FIXED
101 Branch
Tracking Status
firefox101 --- fixed

People

(Reporter: arai, Assigned: arai)

References

(Blocks 1 open bug)

Details

Attachments

(1 file)

separated from bug 1760791.

Steps to reproduce:

  1. run Nightly 100.0a1 (2022-03-24) (64-bit) on macOS
  2. Evaluate the following code in browser console:
queueMicrotask(() => console.log(2));
document.createXULElement("browser");
console.log(1);

Expected result:

1
2

Microtask checkpoint is performed after evaluating the whole code.

Actual result:

2
1

Microtask checkpoint is performed inside createXULElement.

This is because the code is evaluated with microtask level == 0, and CallSetup inside createXULElement enters/leaves microtask, that performs microtask checkpoint when leaving.

To make it work as expected (or, simply to avoid surprise), we should enter microtask before evaluating the browser console input.

Note this also happens in a privileged web console, like in about:config.
Or when putting the code in a watch expression in the debugger.

The evaluation of console input is done by executeInGlobalWithBindings:

https://searchfox.org/mozilla-central/rev/0e93b94f4c2045c6a5f5260ee48bbf7a94a993bc/devtools/server/actors/webconsole/eval-with-debugger.js#243

function getEvalResult(
  dbg,
  string,
  evalOptions,
  bindings,
  frame,
  dbgGlobal,
  noSideEffectDebugger
) {
...
    result = dbgGlobal.executeInGlobalWithBindings(
      string,
      bindings,
      evalOptions
    );

and this is called from a runnable created by Services.tm.dispatchToMainThread.

https://searchfox.org/mozilla-central/rev/0e93b94f4c2045c6a5f5260ee48bbf7a94a993bc/devtools/server/actors/webconsole.js#1007

const WebConsoleActor = ActorClassWithSpec(webconsoleSpec, {
...
  evaluateJSAsync: async function(request) {
...
    DevToolsUtils.executeSoon(async () => {
      try {
        // Execute the script that may pause.
        let response = await this.evaluateJS(request);

https://searchfox.org/mozilla-central/rev/0e93b94f4c2045c6a5f5260ee48bbf7a94a993bc/devtools/shared/DevToolsUtils.js#62

exports.executeSoon = function(fn) {
...
    Services.tm.dispatchToMainThread({
      run: exports.makeInfallible(executor),

and I don't see any suitable place to put nsAutoMicroTask in between them.

Possible options are:

  • (a) Add native helper function that takes function and calls it in microtask
    and enclose some part of the code with it
  • (b) Add native helper function that enter/leave microtask,
    and enclose some part of the code with it
  • (c) extend Services.tm.dispatchToMainThread to allocate nsAutoMicroTask before calling the runnable

The attached patch takes (b).

Given the finally block isn't guaranteed to be executed on OOM, it would be better taking (a)

(c) doesn't fit here because the function is async function, and it's not guaranteed that the console input is evaluated before the first await.
the microtask should be entered/left just before/after evaluating the console input.

Attachment #9271665 - Attachment description: WIP: Bug 1761590 - WIP: Enter microtask when evaluating console/debugger input. → Bug 1761590 - Enter microtask when evaluating console/debugger input. r?nchevobbe!,smaug!

(In reply to Tooru Fujisawa [:arai] from comment #5)

(c) doesn't fit here because the function is async function, and it's not guaranteed that the console input is evaluated before the first await.
the microtask should be entered/left just before/after evaluating the console input.

(For later reference) this wasn't true.
If there's await before the console input, the remaining part of the function is evaluated inside PromiseJobRunnable that has CallSetup.
So this issue is specific to the current case that the console input is evaluated in the first runnable.
the patch is modified to wrap the runnable with nsAutoMicroTask.

Pushed by arai_a@mac.com: https://hg.mozilla.org/integration/autoland/rev/0ef8a6690db4 Enter microtask when evaluating console/debugger input. r=nchevobbe,smaug
Regressions: 1764682
Status: ASSIGNED → RESOLVED
Closed: 3 years ago
Resolution: --- → FIXED
Target Milestone: --- → 101 Branch
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Created:
Updated:
Size: