Commit 4739535d authored by Benedikt Meurer's avatar Benedikt Meurer Committed by V8 LUCI CQ

[debug] Remove breakable location right before suspending.

This aligns the breakpoint behavior of YieldExpression and
AwaitExpression with the behavior of AssignmentExpression
in V8. It basically boils down to not reporting expression
positions on SuspendGenerator bytecodes as breakable
locations.

In particular the initial implicit yield of any generator
function is no longer a breakable position. In light of
this changes we also refine https://crrev.com/c/2949099
to not be able to step to the initial implicit yield
either, which would otherwise be really odd.

Before: https://imgur.com/KYy9F1S.png
After: https://imgur.com/gCnWU8J.png
Doc: https://goo.gle/devtools-reliable-await-breakpoints
Bug: chromium:901814, chromium:1319019, chromium:1246869
Fixed: chromium:1319019, chromium:1357501
Change-Id: I0c5f83e279918eb392d8f77a8a04c4c0285f938e
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3909688
Commit-Queue: Leszek Swirski <leszeks@chromium.org>
Reviewed-by: 's avatarKim-Anh Tran <kimanh@chromium.org>
Auto-Submit: Benedikt Meurer <bmeurer@chromium.org>
Reviewed-by: 's avatarLeszek Swirski <leszeks@chromium.org>
Cr-Commit-Position: refs/heads/main@{#83392}
parent 70de8dd1
...@@ -249,9 +249,11 @@ BreakIterator::BreakIterator(Handle<DebugInfo> debug_info) ...@@ -249,9 +249,11 @@ BreakIterator::BreakIterator(Handle<DebugInfo> debug_info)
int BreakIterator::BreakIndexFromPosition(int source_position) { int BreakIterator::BreakIndexFromPosition(int source_position) {
for (; !Done(); Next()) { for (; !Done(); Next()) {
if (GetDebugBreakType() == DEBUG_BREAK_SLOT_AT_SUSPEND) continue;
if (source_position <= position()) { if (source_position <= position()) {
int first_break = break_index(); int first_break = break_index();
for (; !Done(); Next()) { for (; !Done(); Next()) {
if (GetDebugBreakType() == DEBUG_BREAK_SLOT_AT_SUSPEND) continue;
if (source_position == position()) return break_index(); if (source_position == position()) return break_index();
} }
return first_break; return first_break;
...@@ -297,6 +299,10 @@ DebugBreakType BreakIterator::GetDebugBreakType() { ...@@ -297,6 +299,10 @@ DebugBreakType BreakIterator::GetDebugBreakType() {
} else if (bytecode == interpreter::Bytecode::kReturn) { } else if (bytecode == interpreter::Bytecode::kReturn) {
return DEBUG_BREAK_SLOT_AT_RETURN; return DEBUG_BREAK_SLOT_AT_RETURN;
} else if (bytecode == interpreter::Bytecode::kSuspendGenerator) { } else if (bytecode == interpreter::Bytecode::kSuspendGenerator) {
// SuspendGenerator should always only carry an expression position that
// is used in stack trace construction, but should never be a breakable
// position reported to the debugger front-end.
DCHECK(!source_position_iterator_.is_statement());
return DEBUG_BREAK_SLOT_AT_SUSPEND; return DEBUG_BREAK_SLOT_AT_SUSPEND;
} else if (interpreter::Bytecodes::IsCallOrConstruct(bytecode)) { } else if (interpreter::Bytecodes::IsCallOrConstruct(bytecode)) {
return DEBUG_BREAK_SLOT_AT_CALL; return DEBUG_BREAK_SLOT_AT_CALL;
...@@ -574,20 +580,21 @@ void Debug::Break(JavaScriptFrame* frame, Handle<JSFunction> break_target) { ...@@ -574,20 +580,21 @@ void Debug::Break(JavaScriptFrame* frame, Handle<JSFunction> break_target) {
if (current_frame_count > target_frame_count) return; if (current_frame_count > target_frame_count) return;
V8_FALLTHROUGH; V8_FALLTHROUGH;
case StepInto: { case StepInto: {
// Special case StepInto and StepOver for generators that are about to // StepInto and StepOver should enter "generator stepping" mode, except
// suspend, in which case we go into "generator stepping" mode. The // for the implicit initial yield in generators, where it should simply
// exception here is the initial implicit yield in generators (which // step out of the generator function.
// always has a suspend ID of 0), where we return to the caller first, if (location.IsSuspend()) {
// instead of triggering "generator stepping" mode straight away.
if (location.IsSuspend() && (!IsGeneratorFunction(shared->kind()) ||
location.generator_suspend_id() > 0)) {
DCHECK(!has_suspended_generator()); DCHECK(!has_suspended_generator());
thread_local_.suspended_generator_ =
location.GetGeneratorObjectForSuspendedFrame(frame);
ClearStepping(); ClearStepping();
if (!IsGeneratorFunction(shared->kind()) ||
location.generator_suspend_id() > 0) {
thread_local_.suspended_generator_ =
location.GetGeneratorObjectForSuspendedFrame(frame);
} else {
PrepareStep(StepOut);
}
return; return;
} }
FrameSummary summary = FrameSummary::GetTop(frame); FrameSummary summary = FrameSummary::GetTop(frame);
step_break = step_break || location.IsReturn() || step_break = step_break || location.IsReturn() ||
current_frame_count != last_frame_count || current_frame_count != last_frame_count ||
...@@ -1220,9 +1227,7 @@ void Debug::PrepareStep(StepAction step_action) { ...@@ -1220,9 +1227,7 @@ void Debug::PrepareStep(StepAction step_action) {
// Any step at a return is a step-out, and a step-out at a suspend behaves // Any step at a return is a step-out, and a step-out at a suspend behaves
// like a return. // like a return.
if (location.IsReturn() || if (location.IsReturn() ||
(location.IsSuspend() && (location.IsSuspend() && step_action == StepOut)) {
(step_action == StepOut || (IsGeneratorFunction(shared->kind()) &&
location.generator_suspend_id() == 0)))) {
// On StepOut we'll ignore our further calls to current function in // On StepOut we'll ignore our further calls to current function in
// PrepareStepIn callback. // PrepareStepIn callback.
if (last_step_action() == StepOut) { if (last_step_action() == StepOut) {
...@@ -1637,23 +1642,18 @@ void Debug::InstallDebugBreakTrampoline() { ...@@ -1637,23 +1642,18 @@ void Debug::InstallDebugBreakTrampoline() {
} }
namespace { namespace {
template <typename Iterator>
void GetBreakablePositions(Iterator* it, int start_position, int end_position,
std::vector<BreakLocation>* locations) {
while (!it->Done()) {
if (it->position() >= start_position && it->position() < end_position) {
locations->push_back(it->GetBreakLocation());
}
it->Next();
}
}
void FindBreakablePositions(Handle<DebugInfo> debug_info, int start_position, void FindBreakablePositions(Handle<DebugInfo> debug_info, int start_position,
int end_position, int end_position,
std::vector<BreakLocation>* locations) { std::vector<BreakLocation>* locations) {
DCHECK(debug_info->HasInstrumentedBytecodeArray()); DCHECK(debug_info->HasInstrumentedBytecodeArray());
BreakIterator it(debug_info); BreakIterator it(debug_info);
GetBreakablePositions(&it, start_position, end_position, locations); while (!it.Done()) {
if (it.GetDebugBreakType() != DEBUG_BREAK_SLOT_AT_SUSPEND &&
it.position() >= start_position && it.position() < end_position) {
locations->push_back(it.GetBreakLocation());
}
it.Next();
}
} }
bool CompileTopLevel(Isolate* isolate, Handle<Script> script) { bool CompileTopLevel(Isolate* isolate, Handle<Script> script) {
......
...@@ -148,13 +148,13 @@ class V8_EXPORT_PRIVATE BreakIterator { ...@@ -148,13 +148,13 @@ class V8_EXPORT_PRIVATE BreakIterator {
void ClearDebugBreak(); void ClearDebugBreak();
void SetDebugBreak(); void SetDebugBreak();
DebugBreakType GetDebugBreakType();
private: private:
int BreakIndexFromPosition(int position); int BreakIndexFromPosition(int position);
Isolate* isolate(); Isolate* isolate();
DebugBreakType GetDebugBreakType();
Handle<DebugInfo> debug_info_; Handle<DebugInfo> debug_info_;
int break_index_; int break_index_;
int position_; int position_;
......
...@@ -5,11 +5,11 @@ Running test: testBreakLocations ...@@ -5,11 +5,11 @@ Running test: testBreakLocations
function testFunction() { function testFunction() {
async function f1() { async function f1() {
for (let x = |_|0; x |_|< 1; ++|_|x) |_|await x; for (let x = |_|0; x |_|< 1; ++|_|x) |_|await x;
|_|return |_|await Promise.|C|resolve(2);|R| |_|return await Promise.|C|resolve(2);|R|
} }
async function f2() { async function f2() {
let r = |_|await |C|f1() + |_|await |C|f1(); let r = |_|await |C|f1() + await |C|f1();
|_|await |C|f1(); |_|await |C|f1();
|_|await |C|f1().|C|then(x => x |_|* 2|R|); |_|await |C|f1().|C|then(x => x |_|* 2|R|);
|_|await [1].|C|map(x => Promise.|C|resolve(x)|R|)[0]; |_|await [1].|C|map(x => Promise.|C|resolve(x)|R|)[0];
......
...@@ -99,7 +99,7 @@ let x = |R|class {} ...@@ -99,7 +99,7 @@ let x = |R|class {}
}|R| }|R|
|_|x = |R|class { |_|x = |R|class {
x = |_|function*|_|() { x = |_|function*() {
|_|yield 1; |_|yield 1;
|R|}; |R|};
}|R| }|R|
...@@ -190,7 +190,7 @@ let x = |R|class {} ...@@ -190,7 +190,7 @@ let x = |R|class {}
} }
|_|x = |R|class { |_|x = |R|class {
static x = |_|function*|_|() { static x = |_|function*() {
|_|yield 1; |_|yield 1;
|R|}|R|; |R|}|R|;
} }
...@@ -204,3 +204,4 @@ let x = |R|class {} ...@@ -204,3 +204,4 @@ let x = |R|class {}
[|C|bar()] = |_|6; [|C|bar()] = |_|6;
}|R| }|R|
|R| |R|
...@@ -152,7 +152,7 @@ function testSwitch() { ...@@ -152,7 +152,7 @@ function testSwitch() {
} }
|R|} |R|}
function* idMaker|_|() { function* idMaker() {
|_|yield 1; |_|yield 1;
|_|yield 2; |_|yield 2;
|_|yield 3; |_|yield 3;
...@@ -230,8 +230,8 @@ async function testPromiseAsyncWithCode() { ...@@ -230,8 +230,8 @@ async function testPromiseAsyncWithCode() {
|_|await p; |_|await p;
|R|} |R|}
|C|setTimeout(returnCall, 0); |C|setTimeout(returnCall, 0);
|_|await |C|foo(); await |C|foo();
|_|await |C|foo(); await |C|foo();
|C|nextTest(); |C|nextTest();
|R|} |R|}
|C|main(); |C|main();
...@@ -252,7 +252,7 @@ async function testPromiseComplex() { ...@@ -252,7 +252,7 @@ async function testPromiseComplex() {
} }
var x = |_|1; var x = |_|1;
var y = |_|2; var y = |_|2;
|C|returnFunction(|C|emptyFunction(), x++, --y, x => 2 |_|* x|R|, |C|returnCall())|C|().a = |_|await |C|foo((a => 2 |_|*a|R|)|C|(5)); |C|returnFunction(|C|emptyFunction(), x++, --y, x => 2 |_|* x|R|, |C|returnCall())|C|().a = await |C|foo((a => 2 |_|*a|R|)|C|(5));
|C|nextTest(); |C|nextTest();
|R|} |R|}
|C|main(); |C|main();
......
Line breakpoints for await
Running test: testAwaitInAsyncFunctionWithLeadingWhitespace
Setting breakpoint on `await this.foo()` in `obj.bar`
Calling `obj.bar()`
Hit breakpoint before calling into `this.foo`
Running test: testAwaitInAsyncFunctionWithoutLeadingWhitespace
Setting breakpoint on `await this.foo()` in `obj.baz`
Calling `obj.baz()`
Hit breakpoint before calling into `this.foo`
Running test: testAwaitInAsyncGeneratorWithLeadingWhitespace
Setting breakpoint on `await this.foo()` in `obj.barGenerator`
Calling `obj.barGenerator().next()`
Hit breakpoint before calling into `this.foo`
Running test: testAwaitInAsyncGeneratorWithoutLeadingWhitespace
Setting breakpoint on `await this.foo()` in `obj.bazGenerator`
Calling `obj.bazGenerator().next()`
Hit breakpoint before calling into `this.foo`
Running test: testAwaitInAsyncFunctionMinified
Setting breakpoint on `await this.foo()` in `obj.minified`
Calling `obj.minified()`
Hit breakpoint before calling into `this.foo`
// Copyright 2022 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
let {session, contextGroup, Protocol} =
InspectorTest.start('Line breakpoints for await');
// clang-format off
const url = 'line-breakpoint-await.js';
contextGroup.addScript(`
var obj = {
foo() {
debugger;
},
async bar() {
await this.foo();
},
async baz() {
await this.foo();
},
async* barGenerator() {
await this.foo();
},
async* bazGenerator() {
await this.foo();
},
async minified(){await this.foo();}
};
`, 0, 0, url);
// clang-format on
session.setupScriptMap();
InspectorTest.runAsyncTestSuite([
async function testAwaitInAsyncFunctionWithLeadingWhitespace() {
await Promise.all([
Protocol.Debugger.enable(),
Protocol.Runtime.enable(),
]);
InspectorTest.log('Setting breakpoint on `await this.foo()` in `obj.bar`');
const {result: {breakpointId}} =
await Protocol.Debugger.setBreakpointByUrl({
url,
lineNumber: 7,
columnNumber: 0,
});
InspectorTest.log('Calling `obj.bar()`');
const pausedPromise = Protocol.Debugger.oncePaused();
const evalPromise = Protocol.Runtime.evaluate({
expression: 'obj.bar()',
awaitPromise: true,
});
const {params: {hitBreakpoints}} = await pausedPromise;
if (hitBreakpoints?.length === 1 && hitBreakpoints[0] === breakpointId) {
InspectorTest.log('Hit breakpoint before calling into `this.foo`');
} else {
InspectorTest.log('Missed breakpoint before calling into `this.foo`');
}
await Promise.all([
Protocol.Debugger.removeBreakpoint({breakpointId}),
Protocol.Debugger.disable(),
evalPromise,
Protocol.Runtime.disable(),
]);
},
async function testAwaitInAsyncFunctionWithoutLeadingWhitespace() {
await Promise.all([
Protocol.Debugger.enable(),
Protocol.Runtime.enable(),
]);
InspectorTest.log('Setting breakpoint on `await this.foo()` in `obj.baz`');
const {result: {breakpointId}} =
await Protocol.Debugger.setBreakpointByUrl({
url,
lineNumber: 11,
columnNumber: 0,
});
InspectorTest.log('Calling `obj.baz()`');
const pausedPromise = Protocol.Debugger.oncePaused();
const evalPromise = Protocol.Runtime.evaluate({
expression: 'obj.baz()',
awaitPromise: true,
});
const {params: {hitBreakpoints}} = await pausedPromise;
if (hitBreakpoints?.length === 1 && hitBreakpoints[0] === breakpointId) {
InspectorTest.log('Hit breakpoint before calling into `this.foo`');
} else {
InspectorTest.log('Missed breakpoint before calling into `this.foo`');
}
await Promise.all([
Protocol.Debugger.removeBreakpoint({breakpointId}),
Protocol.Debugger.disable(),
evalPromise,
Protocol.Runtime.disable(),
]);
},
async function testAwaitInAsyncGeneratorWithLeadingWhitespace() {
await Promise.all([
Protocol.Debugger.enable(),
Protocol.Runtime.enable(),
]);
InspectorTest.log(
'Setting breakpoint on `await this.foo()` in `obj.barGenerator`');
const {result: {breakpointId}} =
await Protocol.Debugger.setBreakpointByUrl({
url,
lineNumber: 15,
columnNumber: 0,
});
InspectorTest.log('Calling `obj.barGenerator().next()`');
const pausedPromise = Protocol.Debugger.oncePaused();
const evalPromise = Protocol.Runtime.evaluate({
expression: 'obj.barGenerator().next()',
awaitPromise: true,
});
const {params: {hitBreakpoints}} = await pausedPromise;
if (hitBreakpoints?.length === 1 && hitBreakpoints[0] === breakpointId) {
InspectorTest.log('Hit breakpoint before calling into `this.foo`');
} else {
InspectorTest.log('Missed breakpoint before calling into `this.foo`');
}
await Promise.all([
Protocol.Debugger.removeBreakpoint({breakpointId}),
Protocol.Debugger.disable(),
evalPromise,
Protocol.Runtime.disable(),
]);
},
async function testAwaitInAsyncGeneratorWithoutLeadingWhitespace() {
await Promise.all([
Protocol.Debugger.enable(),
Protocol.Runtime.enable(),
]);
InspectorTest.log(
'Setting breakpoint on `await this.foo()` in `obj.bazGenerator`');
const {result: {breakpointId}} =
await Protocol.Debugger.setBreakpointByUrl({
url,
lineNumber: 19,
columnNumber: 0,
});
InspectorTest.log('Calling `obj.bazGenerator().next()`');
const pausedPromise = Protocol.Debugger.oncePaused();
const evalPromise = Protocol.Runtime.evaluate({
expression: 'obj.bazGenerator().next()',
awaitPromise: true,
});
const {params: {hitBreakpoints}} = await pausedPromise;
if (hitBreakpoints?.length === 1 && hitBreakpoints[0] === breakpointId) {
InspectorTest.log('Hit breakpoint before calling into `this.foo`');
} else {
InspectorTest.log('Missed breakpoint before calling into `this.foo`');
}
await Promise.all([
Protocol.Debugger.removeBreakpoint({breakpointId}),
Protocol.Debugger.disable(),
evalPromise,
Protocol.Runtime.disable(),
]);
},
async function testAwaitInAsyncFunctionMinified() {
await Promise.all([
Protocol.Debugger.enable(),
Protocol.Runtime.enable(),
]);
InspectorTest.log(
'Setting breakpoint on `await this.foo()` in `obj.minified`');
const {result: {breakpointId}} =
await Protocol.Debugger.setBreakpointByUrl({
url,
lineNumber: 22,
columnNumber: 19,
});
InspectorTest.log('Calling `obj.minified()`');
const pausedPromise = Protocol.Debugger.oncePaused();
const evalPromise = Protocol.Runtime.evaluate({
expression: 'obj.minified()',
awaitPromise: true,
});
const {params: {hitBreakpoints}} = await pausedPromise;
if (hitBreakpoints?.length === 1 && hitBreakpoints[0] === breakpointId) {
InspectorTest.log('Hit breakpoint before calling into `this.foo`');
} else {
InspectorTest.log('Missed breakpoint before calling into `this.foo`');
}
await Promise.all([
Protocol.Debugger.removeBreakpoint({breakpointId}),
Protocol.Debugger.disable(),
evalPromise,
Protocol.Runtime.disable(),
]);
},
]);
Line breakpoints for yield
Running test: testYieldInGeneratorWithLeadingWhitespace
Setting breakpoint on `yield this.foo()` in `obj.barGenerator`
Calling `obj.barGenerator().next()`
Hit breakpoint before calling into `this.foo`
Running test: testYieldInGeneratorWithoutLeadingWhitespace
Setting breakpoint on `await this.foo()` in `obj.bazGenerator`
Calling `obj.bazGenerator().next()`
Hit breakpoint before calling into `this.foo`
Running test: testYieldInAsyncGeneratorWithLeadingWhitespace
Setting breakpoint on `yield this.foo()` in `obj.barAsyncGenerator`
Calling `obj.barAsyncGenerator().next()`
Hit breakpoint before calling into `this.foo`
Running test: testYieldInAsyncGeneratorWithoutLeadingWhitespace
Setting breakpoint on `yield this.foo()` in `obj.bazAsyncGenerator`
Calling `obj.bazAsyncGenerator().next()`
Hit breakpoint before calling into `this.foo`
Running test: testYieldInMinifiedGenerator
Setting breakpoint on `yield this.foo()` in `obj.minifiedGenerator`
Calling `obj.minifiedGenerator().next()`
Hit breakpoint before calling into `this.foo`
// Copyright 2022 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
let {session, contextGroup, Protocol} =
InspectorTest.start('Line breakpoints for yield');
// clang-format off
const url = 'line-breakpoint-yield.js';
contextGroup.addScript(`
var obj = {
foo() {
debugger;
},
*barGenerator() {
yield this.foo();
},
*bazGenerator() {
yield this.foo();
},
async* barAsyncGenerator() {
yield this.foo();
},
async* bazAsyncGenerator() {
yield this.foo();
},
*minifiedGenerator(){yield this.foo();}
};
`, 0, 0, url);
// clang-format on
session.setupScriptMap();
InspectorTest.runAsyncTestSuite([
async function testYieldInGeneratorWithLeadingWhitespace() {
await Promise.all([
Protocol.Debugger.enable(),
Protocol.Runtime.enable(),
]);
InspectorTest.log(
'Setting breakpoint on `yield this.foo()` in `obj.barGenerator`');
const {result: {breakpointId}} =
await Protocol.Debugger.setBreakpointByUrl({
url,
lineNumber: 7,
columnNumber: 0,
});
InspectorTest.log('Calling `obj.barGenerator().next()`');
const pausedPromise = Protocol.Debugger.oncePaused();
const evalPromise = Protocol.Runtime.evaluate({
expression: 'obj.barGenerator().next()',
});
const {params: {hitBreakpoints}} = await pausedPromise;
if (hitBreakpoints?.length === 1 && hitBreakpoints[0] === breakpointId) {
InspectorTest.log('Hit breakpoint before calling into `this.foo`');
} else {
InspectorTest.log('Missed breakpoint before calling into `this.foo`');
}
await Promise.all([
Protocol.Debugger.removeBreakpoint({breakpointId}),
Protocol.Debugger.disable(),
evalPromise,
Protocol.Runtime.disable(),
]);
},
async function testYieldInGeneratorWithoutLeadingWhitespace() {
await Promise.all([
Protocol.Debugger.enable(),
Protocol.Runtime.enable(),
]);
InspectorTest.log(
'Setting breakpoint on `await this.foo()` in `obj.bazGenerator`');
const {result: {breakpointId}} =
await Protocol.Debugger.setBreakpointByUrl({
url,
lineNumber: 11,
columnNumber: 0,
});
InspectorTest.log('Calling `obj.bazGenerator().next()`');
const pausedPromise = Protocol.Debugger.oncePaused();
const evalPromise = Protocol.Runtime.evaluate({
expression: 'obj.bazGenerator().next()',
});
const {params: {hitBreakpoints}} = await pausedPromise;
if (hitBreakpoints?.length === 1 && hitBreakpoints[0] === breakpointId) {
InspectorTest.log('Hit breakpoint before calling into `this.foo`');
} else {
InspectorTest.log('Missed breakpoint before calling into `this.foo`');
}
await Promise.all([
Protocol.Debugger.removeBreakpoint({breakpointId}),
Protocol.Debugger.disable(),
evalPromise,
Protocol.Runtime.disable(),
]);
},
async function testYieldInAsyncGeneratorWithLeadingWhitespace() {
await Promise.all([
Protocol.Debugger.enable(),
Protocol.Runtime.enable(),
]);
InspectorTest.log(
'Setting breakpoint on `yield this.foo()` in `obj.barAsyncGenerator`');
const {result: {breakpointId}} =
await Protocol.Debugger.setBreakpointByUrl({
url,
lineNumber: 15,
columnNumber: 0,
});
InspectorTest.log('Calling `obj.barAsyncGenerator().next()`');
const pausedPromise = Protocol.Debugger.oncePaused();
const evalPromise = Protocol.Runtime.evaluate({
expression: 'obj.barAsyncGenerator().next()',
awaitPromise: true,
});
const {params: {hitBreakpoints}} = await pausedPromise;
if (hitBreakpoints?.length === 1 && hitBreakpoints[0] === breakpointId) {
InspectorTest.log('Hit breakpoint before calling into `this.foo`');
} else {
InspectorTest.log('Missed breakpoint before calling into `this.foo`');
}
await Promise.all([
Protocol.Debugger.removeBreakpoint({breakpointId}),
Protocol.Debugger.disable(),
evalPromise,
Protocol.Runtime.disable(),
]);
},
async function testYieldInAsyncGeneratorWithoutLeadingWhitespace() {
await Promise.all([
Protocol.Debugger.enable(),
Protocol.Runtime.enable(),
]);
InspectorTest.log(
'Setting breakpoint on `yield this.foo()` in `obj.bazAsyncGenerator`');
const {result: {breakpointId}} =
await Protocol.Debugger.setBreakpointByUrl({
url,
lineNumber: 19,
columnNumber: 0,
});
InspectorTest.log('Calling `obj.bazAsyncGenerator().next()`');
const pausedPromise = Protocol.Debugger.oncePaused();
const evalPromise = Protocol.Runtime.evaluate({
expression: 'obj.bazAsyncGenerator().next()',
awaitPromise: true,
});
const {params: {hitBreakpoints}} = await pausedPromise;
if (hitBreakpoints?.length === 1 && hitBreakpoints[0] === breakpointId) {
InspectorTest.log('Hit breakpoint before calling into `this.foo`');
} else {
InspectorTest.log('Missed breakpoint before calling into `this.foo`');
}
await Promise.all([
Protocol.Debugger.removeBreakpoint({breakpointId}),
Protocol.Debugger.disable(),
evalPromise,
Protocol.Runtime.disable(),
]);
},
async function testYieldInMinifiedGenerator() {
await Promise.all([
Protocol.Debugger.enable(),
Protocol.Runtime.enable(),
]);
InspectorTest.log(
'Setting breakpoint on `yield this.foo()` in `obj.minifiedGenerator`');
const {result: {breakpointId}} =
await Protocol.Debugger.setBreakpointByUrl({
url,
lineNumber: 22,
columnNumber: 23,
});
InspectorTest.log('Calling `obj.minifiedGenerator().next()`');
const pausedPromise = Protocol.Debugger.oncePaused();
const evalPromise = Protocol.Runtime.evaluate({
expression: 'obj.minifiedGenerator().next()',
});
const {params: {hitBreakpoints}} = await pausedPromise;
if (hitBreakpoints?.length === 1 && hitBreakpoints[0] === breakpointId) {
InspectorTest.log('Hit breakpoint before calling into `this.foo`');
} else {
InspectorTest.log('Missed breakpoint before calling into `this.foo`');
}
await Promise.all([
Protocol.Debugger.removeBreakpoint({breakpointId}),
Protocol.Debugger.disable(),
evalPromise,
Protocol.Runtime.disable(),
]);
},
]);
...@@ -682,11 +682,6 @@ function testGenerator() { ...@@ -682,11 +682,6 @@ function testGenerator() {
var gen = #idMaker(); var gen = #idMaker();
return42(); return42();
break at:
function* idMaker#() {
yield 1;
break at: break at:
var gen = idMaker(); var gen = idMaker();
#return42(); #return42();
......
Async generator stepping Async generator stepping
Running test: testStepOverFromInitialYield
Setting breakpoint on implicit initial yield
Calling callGenerator()
async function* generator#() {
var a = 42;
Stepping over while paused on the initial yield
function callGenerator() {
return generator();#
}
Running test: testStepIntoInitialYield Running test: testStepIntoInitialYield
Setting breakpoint on call to generator() Setting breakpoint on call to generator()
Calling callGenerator() Calling callGenerator()
...@@ -21,11 +8,6 @@ function callGenerator() { ...@@ -21,11 +8,6 @@ function callGenerator() {
} }
Stepping into the generator() Stepping into the generator()
async function* generator#() {
var a = 42;
Stepping into while paused on the initial yield
function callGenerator() { function callGenerator() {
return generator();# return generator();#
} }
......
...@@ -18,36 +18,6 @@ function callGenerator() { ...@@ -18,36 +18,6 @@ function callGenerator() {
session.setupScriptMap(); session.setupScriptMap();
InspectorTest.runAsyncTestSuite([ InspectorTest.runAsyncTestSuite([
async function testStepOverFromInitialYield() {
await Promise.all([Protocol.Debugger.enable(), Protocol.Runtime.enable()]);
InspectorTest.log(`Setting breakpoint on implicit initial yield`);
const {result: {breakpointId}} = await Protocol.Debugger.setBreakpointByUrl({
url,
lineNumber: 1,
columnNumber: 0,
})
InspectorTest.log(`Calling callGenerator()`);
const pausedPromise = Protocol.Debugger.oncePaused();
const evalPromise = Protocol.Runtime.evaluate({expression: 'callGenerator()'});
const {method, params} = await Promise.race([pausedPromise, evalPromise]);
if (method === 'Debugger.paused') {
await session.logSourceLocation(params.callFrames[0].location);
InspectorTest.log('Stepping over while paused on the initial yield');
const [{params: {callFrames:[{location}]}}] = await Promise.all([
Protocol.Debugger.oncePaused(),
Protocol.Debugger.stepOver(),
]);
await session.logSourceLocation(location);
await Promise.all([Protocol.Debugger.resume(), evalPromise]);
} else {
InspectorTest.log('Did not pause');
}
await Protocol.Debugger.removeBreakpoint({breakpointId});
await Promise.all([Protocol.Debugger.disable(), Protocol.Runtime.disable()]);
},
async function testStepIntoInitialYield() { async function testStepIntoInitialYield() {
await Promise.all([Protocol.Debugger.enable(), Protocol.Runtime.enable()]); await Promise.all([Protocol.Debugger.enable(), Protocol.Runtime.enable()]);
InspectorTest.log(`Setting breakpoint on call to generator()`); InspectorTest.log(`Setting breakpoint on call to generator()`);
...@@ -70,13 +40,6 @@ InspectorTest.runAsyncTestSuite([ ...@@ -70,13 +40,6 @@ InspectorTest.runAsyncTestSuite([
]); ]);
await session.logSourceLocation(location); await session.logSourceLocation(location);
InspectorTest.log('Stepping into while paused on the initial yield');
([{params: {callFrames:[{location}]}}] = await Promise.all([
Protocol.Debugger.oncePaused(),
Protocol.Debugger.stepInto(),
]));
await session.logSourceLocation(location);
await Promise.all([Protocol.Debugger.resume(), evalPromise]); await Promise.all([Protocol.Debugger.resume(), evalPromise]);
} else { } else {
InspectorTest.log('Did not pause'); InspectorTest.log('Did not pause');
......
Generator stepping Generator stepping
Running test: testStepOverFromInitialYield
Setting breakpoint on implicit initial yield
Calling callGenerator()
function* generator#() {
var a = 42;
Stepping over while paused on the initial yield
function callGenerator() {
return generator();#
}
Running test: testStepIntoInitialYield Running test: testStepIntoInitialYield
Setting breakpoint on call to generator() Setting breakpoint on call to generator()
Calling callGenerator() Calling callGenerator()
...@@ -21,11 +8,6 @@ function callGenerator() { ...@@ -21,11 +8,6 @@ function callGenerator() {
} }
Stepping into the generator() Stepping into the generator()
function* generator#() {
var a = 42;
Stepping into while paused on the initial yield
function callGenerator() { function callGenerator() {
return generator();# return generator();#
} }
......
Generator stepping with non-simple parameters Generator stepping with non-simple parameters
Running test: testStepOverFromInitialYield
Setting breakpoint on implicit initial yield
Calling callGenerator()
function* generator(a = (x => x)(42)) #{
yield a;
Stepping over while paused on the initial yield
function callGenerator() {
return generator(1);#
}
Running test: testStepIntoInitialYield Running test: testStepIntoInitialYield
Setting breakpoint on call to generator() Setting breakpoint on call to generator()
Calling callGenerator() Calling callGenerator()
...@@ -21,11 +8,6 @@ function callGenerator() { ...@@ -21,11 +8,6 @@ function callGenerator() {
} }
Stepping into the generator() Stepping into the generator()
function* generator(a = (x => x)(42)) #{
yield a;
Stepping into while paused on the initial yield
function callGenerator() { function callGenerator() {
return generator(1);# return generator(1);#
} }
......
...@@ -17,36 +17,6 @@ function callGenerator() { ...@@ -17,36 +17,6 @@ function callGenerator() {
session.setupScriptMap(); session.setupScriptMap();
InspectorTest.runAsyncTestSuite([ InspectorTest.runAsyncTestSuite([
async function testStepOverFromInitialYield() {
await Promise.all([Protocol.Debugger.enable(), Protocol.Runtime.enable()]);
InspectorTest.log(`Setting breakpoint on implicit initial yield`);
const {result: {breakpointId}} = await Protocol.Debugger.setBreakpointByUrl({
url,
lineNumber: 1,
columnNumber: 38,
})
InspectorTest.log(`Calling callGenerator()`);
const pausedPromise = Protocol.Debugger.oncePaused();
const evalPromise = Protocol.Runtime.evaluate({expression: 'callGenerator()'});
const {method, params} = await Promise.race([pausedPromise, evalPromise]);
if (method === 'Debugger.paused') {
await session.logSourceLocation(params.callFrames[0].location);
InspectorTest.log('Stepping over while paused on the initial yield');
const [{params: {callFrames:[{location}]}}] = await Promise.all([
Protocol.Debugger.oncePaused(),
Protocol.Debugger.stepOver(),
]);
await session.logSourceLocation(location);
await Promise.all([Protocol.Debugger.resume(), evalPromise]);
} else {
InspectorTest.log('Did not pause');
}
await Protocol.Debugger.removeBreakpoint({breakpointId});
await Promise.all([Protocol.Debugger.disable(), Protocol.Runtime.disable()]);
},
async function testStepIntoInitialYield() { async function testStepIntoInitialYield() {
await Promise.all([Protocol.Debugger.enable(), Protocol.Runtime.enable()]); await Promise.all([Protocol.Debugger.enable(), Protocol.Runtime.enable()]);
InspectorTest.log(`Setting breakpoint on call to generator()`); InspectorTest.log(`Setting breakpoint on call to generator()`);
...@@ -69,13 +39,6 @@ InspectorTest.runAsyncTestSuite([ ...@@ -69,13 +39,6 @@ InspectorTest.runAsyncTestSuite([
]); ]);
await session.logSourceLocation(location); await session.logSourceLocation(location);
InspectorTest.log('Stepping into while paused on the initial yield');
([{params: {callFrames:[{location}]}}] = await Promise.all([
Protocol.Debugger.oncePaused(),
Protocol.Debugger.stepInto(),
]));
await session.logSourceLocation(location);
await Promise.all([Protocol.Debugger.resume(), evalPromise]); await Promise.all([Protocol.Debugger.resume(), evalPromise]);
} else { } else {
InspectorTest.log('Did not pause'); InspectorTest.log('Did not pause');
......
...@@ -18,36 +18,6 @@ function callGenerator() { ...@@ -18,36 +18,6 @@ function callGenerator() {
session.setupScriptMap(); session.setupScriptMap();
InspectorTest.runAsyncTestSuite([ InspectorTest.runAsyncTestSuite([
async function testStepOverFromInitialYield() {
await Promise.all([Protocol.Debugger.enable(), Protocol.Runtime.enable()]);
InspectorTest.log(`Setting breakpoint on implicit initial yield`);
const {result: {breakpointId}} = await Protocol.Debugger.setBreakpointByUrl({
url,
lineNumber: 1,
columnNumber: 0,
})
InspectorTest.log(`Calling callGenerator()`);
const pausedPromise = Protocol.Debugger.oncePaused();
const evalPromise = Protocol.Runtime.evaluate({expression: 'callGenerator()'});
const {method, params} = await Promise.race([pausedPromise, evalPromise]);
if (method === 'Debugger.paused') {
await session.logSourceLocation(params.callFrames[0].location);
InspectorTest.log('Stepping over while paused on the initial yield');
const [{params: {callFrames:[{location}]}}] = await Promise.all([
Protocol.Debugger.oncePaused(),
Protocol.Debugger.stepOver(),
]);
await session.logSourceLocation(location);
await Promise.all([Protocol.Debugger.resume(), evalPromise]);
} else {
InspectorTest.log('Did not pause');
}
await Protocol.Debugger.removeBreakpoint({breakpointId});
await Promise.all([Protocol.Debugger.disable(), Protocol.Runtime.disable()]);
},
async function testStepIntoInitialYield() { async function testStepIntoInitialYield() {
await Promise.all([Protocol.Debugger.enable(), Protocol.Runtime.enable()]); await Promise.all([Protocol.Debugger.enable(), Protocol.Runtime.enable()]);
InspectorTest.log(`Setting breakpoint on call to generator()`); InspectorTest.log(`Setting breakpoint on call to generator()`);
...@@ -70,13 +40,6 @@ InspectorTest.runAsyncTestSuite([ ...@@ -70,13 +40,6 @@ InspectorTest.runAsyncTestSuite([
]); ]);
await session.logSourceLocation(location); await session.logSourceLocation(location);
InspectorTest.log('Stepping into while paused on the initial yield');
([{params: {callFrames:[{location}]}}] = await Promise.all([
Protocol.Debugger.oncePaused(),
Protocol.Debugger.stepInto(),
]));
await session.logSourceLocation(location);
await Promise.all([Protocol.Debugger.resume(), evalPromise]); await Promise.all([Protocol.Debugger.resume(), evalPromise]);
} else { } else {
InspectorTest.log('Did not pause'); InspectorTest.log('Did not pause');
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment