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)
int BreakIterator::BreakIndexFromPosition(int source_position) {
for (; !Done(); Next()) {
if (GetDebugBreakType() == DEBUG_BREAK_SLOT_AT_SUSPEND) continue;
if (source_position <= position()) {
int first_break = break_index();
for (; !Done(); Next()) {
if (GetDebugBreakType() == DEBUG_BREAK_SLOT_AT_SUSPEND) continue;
if (source_position == position()) return break_index();
}
return first_break;
......@@ -297,6 +299,10 @@ DebugBreakType BreakIterator::GetDebugBreakType() {
} else if (bytecode == interpreter::Bytecode::kReturn) {
return DEBUG_BREAK_SLOT_AT_RETURN;
} 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;
} else if (interpreter::Bytecodes::IsCallOrConstruct(bytecode)) {
return DEBUG_BREAK_SLOT_AT_CALL;
......@@ -574,20 +580,21 @@ void Debug::Break(JavaScriptFrame* frame, Handle<JSFunction> break_target) {
if (current_frame_count > target_frame_count) return;
V8_FALLTHROUGH;
case StepInto: {
// Special case StepInto and StepOver for generators that are about to
// suspend, in which case we go into "generator stepping" mode. The
// exception here is the initial implicit yield in generators (which
// always has a suspend ID of 0), where we return to the caller first,
// instead of triggering "generator stepping" mode straight away.
if (location.IsSuspend() && (!IsGeneratorFunction(shared->kind()) ||
location.generator_suspend_id() > 0)) {
// StepInto and StepOver should enter "generator stepping" mode, except
// for the implicit initial yield in generators, where it should simply
// step out of the generator function.
if (location.IsSuspend()) {
DCHECK(!has_suspended_generator());
thread_local_.suspended_generator_ =
location.GetGeneratorObjectForSuspendedFrame(frame);
ClearStepping();
if (!IsGeneratorFunction(shared->kind()) ||
location.generator_suspend_id() > 0) {
thread_local_.suspended_generator_ =
location.GetGeneratorObjectForSuspendedFrame(frame);
} else {
PrepareStep(StepOut);
}
return;
}
FrameSummary summary = FrameSummary::GetTop(frame);
step_break = step_break || location.IsReturn() ||
current_frame_count != last_frame_count ||
......@@ -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
// like a return.
if (location.IsReturn() ||
(location.IsSuspend() &&
(step_action == StepOut || (IsGeneratorFunction(shared->kind()) &&
location.generator_suspend_id() == 0)))) {
(location.IsSuspend() && step_action == StepOut)) {
// On StepOut we'll ignore our further calls to current function in
// PrepareStepIn callback.
if (last_step_action() == StepOut) {
......@@ -1637,23 +1642,18 @@ void Debug::InstallDebugBreakTrampoline() {
}
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,
int end_position,
std::vector<BreakLocation>* locations) {
DCHECK(debug_info->HasInstrumentedBytecodeArray());
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) {
......
......@@ -148,13 +148,13 @@ class V8_EXPORT_PRIVATE BreakIterator {
void ClearDebugBreak();
void SetDebugBreak();
DebugBreakType GetDebugBreakType();
private:
int BreakIndexFromPosition(int position);
Isolate* isolate();
DebugBreakType GetDebugBreakType();
Handle<DebugInfo> debug_info_;
int break_index_;
int position_;
......
......@@ -5,11 +5,11 @@ Running test: testBreakLocations
function testFunction() {
async function f1() {
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() {
let r = |_|await |C|f1() + |_|await |C|f1();
let r = |_|await |C|f1() + await |C|f1();
|_|await |C|f1();
|_|await |C|f1().|C|then(x => x |_|* 2|R|);
|_|await [1].|C|map(x => Promise.|C|resolve(x)|R|)[0];
......
......@@ -99,7 +99,7 @@ let x = |R|class {}
}|R|
|_|x = |R|class {
x = |_|function*|_|() {
x = |_|function*() {
|_|yield 1;
|R|};
}|R|
......@@ -190,7 +190,7 @@ let x = |R|class {}
}
|_|x = |R|class {
static x = |_|function*|_|() {
static x = |_|function*() {
|_|yield 1;
|R|}|R|;
}
......@@ -204,3 +204,4 @@ let x = |R|class {}
[|C|bar()] = |_|6;
}|R|
|R|
......@@ -152,7 +152,7 @@ function testSwitch() {
}
|R|}
function* idMaker|_|() {
function* idMaker() {
|_|yield 1;
|_|yield 2;
|_|yield 3;
......@@ -230,8 +230,8 @@ async function testPromiseAsyncWithCode() {
|_|await p;
|R|}
|C|setTimeout(returnCall, 0);
|_|await |C|foo();
|_|await |C|foo();
await |C|foo();
await |C|foo();
|C|nextTest();
|R|}
|C|main();
......@@ -252,7 +252,7 @@ async function testPromiseComplex() {
}
var x = |_|1;
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();
|R|}
|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() {
var gen = #idMaker();
return42();
break at:
function* idMaker#() {
yield 1;
break at:
var gen = idMaker();
#return42();
......
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
Setting breakpoint on call to generator()
Calling callGenerator()
......@@ -21,11 +8,6 @@ function callGenerator() {
}
Stepping into the generator()
async function* generator#() {
var a = 42;
Stepping into while paused on the initial yield
function callGenerator() {
return generator();#
}
......
......@@ -18,36 +18,6 @@ function callGenerator() {
session.setupScriptMap();
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() {
await Promise.all([Protocol.Debugger.enable(), Protocol.Runtime.enable()]);
InspectorTest.log(`Setting breakpoint on call to generator()`);
......@@ -70,13 +40,6 @@ InspectorTest.runAsyncTestSuite([
]);
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]);
} else {
InspectorTest.log('Did not pause');
......
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
Setting breakpoint on call to generator()
Calling callGenerator()
......@@ -21,11 +8,6 @@ function callGenerator() {
}
Stepping into the generator()
function* generator#() {
var a = 42;
Stepping into while paused on the initial yield
function callGenerator() {
return generator();#
}
......
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
Setting breakpoint on call to generator()
Calling callGenerator()
......@@ -21,11 +8,6 @@ function callGenerator() {
}
Stepping into the generator()
function* generator(a = (x => x)(42)) #{
yield a;
Stepping into while paused on the initial yield
function callGenerator() {
return generator(1);#
}
......
......@@ -17,36 +17,6 @@ function callGenerator() {
session.setupScriptMap();
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() {
await Promise.all([Protocol.Debugger.enable(), Protocol.Runtime.enable()]);
InspectorTest.log(`Setting breakpoint on call to generator()`);
......@@ -69,13 +39,6 @@ InspectorTest.runAsyncTestSuite([
]);
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]);
} else {
InspectorTest.log('Did not pause');
......
......@@ -18,36 +18,6 @@ function callGenerator() {
session.setupScriptMap();
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() {
await Promise.all([Protocol.Debugger.enable(), Protocol.Runtime.enable()]);
InspectorTest.log(`Setting breakpoint on call to generator()`);
......@@ -70,13 +40,6 @@ InspectorTest.runAsyncTestSuite([
]);
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]);
} else {
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