Status Update
Comments
bm...@chromium.org <bm...@chromium.org> #2
bm...@chromium.org <bm...@chromium.org> #3
at...@chromium.org <at...@chromium.org> #4
is...@google.com <is...@google.com> #5
[Auto-CCs applied]
[Monorail blocking:
[Monorail components added to Component Tags custom field.]
pe...@google.com <pe...@google.com>
ap...@google.com <ap...@google.com> #6
Branch: main
commit 1576bd328084f496150d84cb95ea0782c02064d2
Author: Eric Leese <leese@chromium.org>
Date: Fri Apr 05 17:39:48 2024
Scan for chained calls to .catch() for catch prediction
When doing catch prediction on a rejected promise assumed to be
propagating up the call stack, we check on each js frame if the
returned value is then used for chained promise methods like
.then, .finally, and .catch, and if any call in the chain is
.catch or a two-argument .then, we assume the rejection will be
caught.
Also overhauls how we scan through inlined frames and adds
tests for catch prediction in inlined call stacks.
Bug: b:40283993
Change-Id: I3b327c6823b2da3d160a237aefba3bdac96ae808
Reviewed-on:
Reviewed-by: Leszek Swirski <leszeks@chromium.org>
Commit-Queue: Eric Leese <leese@chromium.org>
Cr-Commit-Position: refs/heads/main@{#93227}
M src/execution/isolate.cc
M src/execution/isolate.h
M src/interpreter/bytecode-array-iterator.cc
M src/interpreter/bytecode-array-iterator.h
M test/cctest/test-debug.cc
M test/debugger/debug/es8/async-debug-caught-exception-cases.js
M test/inspector/debugger/break-on-exception-promise-catch-prediction-expected.txt
le...@google.com <le...@google.com>
le...@google.com <le...@google.com> #7
Looking through the examples given in the broader bug, I see a two samples that I expected to be fixed but are not:
let result = Promise.reject(null); // no action yet
result.catch(() => {}); // empty catch handler
var rjp = new Promise(function (rs, rj) {
rj(null);
//setTimeout(rj, 0)
});
rjp.catch(function (err) {});
Need to investigate if these are similar enough in bytecode that the heuristic should be expanded to cover them.
le...@google.com <le...@google.com> #8
In fact these two examples will pause if copied into the console but if you put them in a function they work. When evaluated at the top level the relevant interpreter bytecodes are:
21 E> 0x369c000401e9 @ 21 : 61 f7 f6 f5 04 CallProperty1 r2, r3, r4, [4]
13 E> 0x369c000401ee @ 26 : 25 02 StaCurrentContextSlot [2]
40 S> 0x369c000401f0 @ 28 : 17 02 LdaImmutableCurrentContextSlot [2]
0x369c000401f2 @ 30 : c7 Star3
47 E> 0x369c000401f3 @ 31 : 2f f6 04 06 GetNamedProperty r3, [4], [6]
The first CallProperty1
is the call to Promise.reject()
and the GetNamedProperty
is the lookup for .catch
. Normally we see call, star, GetNamedProperty in immediate sequence, but in the top-level case we save to the context first, then reload it and save to a register.
We could add support for this case, but I'm not convinced it is necessary. Code typed into the console isn't the case we need to optimize around. I can get the same behavior by capturing the promise in a closure, but it's not clear what the correct behavior should be in that case, as if the original promise (as opposed to the one returned from .catch) is saved, it might also be awaited or .thenned, and then the exception will be reported to the console as uncaught. So it's reasonable to be wary of this code pattern, though it wouldn't be hard to add support for it if it is the subject of user feedback.
I'm still considering this bug fixed.
bm...@google.com <bm...@google.com> #9
I suspect this has nothing to do with the REPL per se, but a similar thing would happen if you add a with
scope to your function, so I do believe this needs to be handled as well.
ap...@google.com <ap...@google.com> #10
Branch: main
commit e93e43d6471a9627c532ac3f0f5283720acf75a3
Author: Eric Leese <leese@chromium.org>
Date: Fri Apr 12 15:55:44 2024
Handle saving promise to context before calling .catch()
Bug: b:40283993
Change-Id: Iede31b0e96174d0e7c87fa30bf8fdabe926de490
Reviewed-on:
Commit-Queue: Eric Leese <leese@chromium.org>
Reviewed-by: Leszek Swirski <leszeks@chromium.org>
Cr-Commit-Position: refs/heads/main@{#93347}
M src/execution/isolate.cc
M test/cctest/test-debug.cc
ap...@google.com <ap...@google.com> #11
Branch: main
commit e329fc03dd453f1348c53bde7c7abe733dd03fd9
Author: Eric Leese <leese@chromium.org>
Date: Tue Apr 16 11:21:51 2024
Handle variables outside of with scope when scanning for .catch()
Bug: b:40283993
Change-Id: Ia8528b45d8aded71a6a798afaf04cc9dd6428648
Reviewed-on:
Reviewed-by: Benedikt Meurer <bmeurer@chromium.org>
Commit-Queue: Eric Leese <leese@chromium.org>
Cr-Commit-Position: refs/heads/main@{#93395}
M src/execution/isolate.cc
M test/cctest/test-debug.cc
ap...@google.com <ap...@google.com> #12
Branch: main
commit a14f46b1060a5d0d3d5f584b771d8171bf6a5c18
Author: Ilya Rezvov <irezvov@chromium.org>
Date: Wed Apr 17 13:58:39 2024
Revert "Handle saving promise to context before calling .catch()"
This reverts commit e93e43d6471a9627c532ac3f0f5283720acf75a3.
Reason for revert: Most likely the change caused a crash in Chromium
Original change's description:
> Handle saving promise to context before calling .catch()
>
> Bug: b:40283993
> Change-Id: Iede31b0e96174d0e7c87fa30bf8fdabe926de490
> Reviewed-on:
> Commit-Queue: Eric Leese <leese@chromium.org>
> Reviewed-by: Leszek Swirski <leszeks@chromium.org>
> Cr-Commit-Position: refs/heads/main@{#93347}
Bug: b:40283993
Change-Id: I8c9f64ee1281cc66be0dbaf9ab9e0f5f8ea6200c
Reviewed-on:
Owners-Override: Ilya Rezvov <irezvov@chromium.org>
Commit-Queue: Ilya Rezvov <irezvov@chromium.org>
Reviewed-by: Ilya Rezvov <irezvov@chromium.org>
Reviewed-by: Eric Leese <leese@chromium.org>
Cr-Commit-Position: refs/heads/main@{#93420}
M src/execution/isolate.cc
M test/cctest/test-debug.cc
ap...@google.com <ap...@google.com> #13
Branch: main
commit 5d3e376dfabbf5a3f8f0a3902a6f9b7fc8a69f36
Author: Eric Leese <leese@chromium.org>
Date: Mon Apr 22 12:55:49 2024
Reland "Handle saving promise to context before calling .catch()"
This reverts commit a14f46b1060a5d0d3d5f584b771d8171bf6a5c18.
Reason for revert: Beta (M125) shows no regression in spite of having this change, so most likely this was misattributed.
Bug: b:335398101
Original change's description:
> Revert "Handle saving promise to context before calling .catch()"
>
> This reverts commit e93e43d6471a9627c532ac3f0f5283720acf75a3.
>
> Reason for revert: Most likely the change caused a crash in Chromium
>
> Original change's description:
> > Handle saving promise to context before calling .catch()
> >
> > Bug: b:40283993
> > Change-Id: Iede31b0e96174d0e7c87fa30bf8fdabe926de490
> > Reviewed-on:
> > Commit-Queue: Eric Leese <leese@chromium.org>
> > Reviewed-by: Leszek Swirski <leszeks@chromium.org>
> > Cr-Commit-Position: refs/heads/main@{#93347}
>
> Bug: b:40283993
> Change-Id: I8c9f64ee1281cc66be0dbaf9ab9e0f5f8ea6200c
> Reviewed-on:
> Owners-Override: Ilya Rezvov <irezvov@chromium.org>
> Commit-Queue: Ilya Rezvov <irezvov@chromium.org>
> Reviewed-by: Ilya Rezvov <irezvov@chromium.org>
> Reviewed-by: Eric Leese <leese@chromium.org>
> Cr-Commit-Position: refs/heads/main@{#93420}
Bug: b:40283993
Change-Id: I889d243b419f1ff023bd376fcd7222cb4d9275c2
Reviewed-on:
Reviewed-by: Leszek Swirski <leszeks@chromium.org>
Commit-Queue: Eric Leese <leese@chromium.org>
Bot-Commit: Rubber Stamper <rubber-stamper@appspot.gserviceaccount.com>
Reviewed-by: Benedikt Meurer <bmeurer@chromium.org>
Cr-Commit-Position: refs/heads/main@{#93500}
M src/execution/isolate.cc
M test/cctest/test-debug.cc
Description
Can easily repro with:
Promise.reject(new Error('fail')).catch((e)=>console.log('caught'));
which will only pause if you have Pause on uncaught exceptions selected, because at the time reject is called, the catch handler hasn't been attached yet.
My proposal is to walk the stack, look at the currently evaluating expression, and see if it is immediately followed by .catch(). If so, assume a promise rejection will be caught there. It would also make sense to look for .this(,) with two arguments, and also a chain of .this() and .finally() followed by a .catch() or .this(,).
What I'm not proposing is scanning the whole function for a .catch(), just the current expression. So the following could appear to be uncaught:
function immediateFailure() { return Promise.reject(new Error()); }
function handleFailure() {
let promise = immediateFailure();
return promise.catch((e) => {});
}
I haven't begun looking into what is involved in implementing this, so maybe even this version is more trouble than it is worth.