Skip to content

Commit 74f753f

Browse files
sstricklCommit Queue
authored andcommitted
[vm,dyn_modules] More work on bytecode debugger support.
Detects yield points in Debugger::IsAtAsyncJump for bytecode by seeing if the currently executing instruction is a direct call to an await or yield compiled stub. Adds a ResumptionBreakpointHandler runtime entry that is called during Interpreter::Resume() if the current isolate has resumption breakpoints. Similarly, all the places where a DebugCheck could be emitted if debugging stops are requested now include an explicit source position emission when source positions are requested but debugger stops are not, to ensure the debugger has appropriate information. Fixes CompareTopDartFrameTo returning kSelf for non-top frames when the top frame was interpreted but the stepping frame was not or vice versa. TEST=pkg/vm_service/test Change-Id: I88cdc37cf745f30e8dfb6b14c19fc9b2c4cbaf2d Cq-Include-Trybots: luci.dart.try:vm-dyn-linux-debug-x64-try,vm-aot-dyn-linux-debug-x64-try,vm-aot-dyn-linux-product-x64-try,vm-dyn-mac-debug-arm64-try Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/446300 Commit-Queue: Tess Strickland <[email protected]> Reviewed-by: Alexander Markov <[email protected]>
1 parent 0908a80 commit 74f753f

File tree

14 files changed

+1597
-1520
lines changed

14 files changed

+1597
-1520
lines changed

pkg/dart2bytecode/lib/bytecode_generator.dart

Lines changed: 70 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -1479,12 +1479,8 @@ class BytecodeGenerator extends RecursiveVisitor {
14791479
}
14801480
if (condition is EqualsNull) {
14811481
_generateNode(condition.expression);
1482-
if (options.emitDebuggerStops &&
1483-
condition.fileOffset != TreeNode.noOffset) {
1484-
final savedSourcePosition = asm.currentSourcePosition;
1485-
_recordSourcePosition(condition.fileOffset);
1486-
asm.emitDebugCheck();
1487-
asm.currentSourcePosition = savedSourcePosition;
1482+
if (condition.fileOffset != TreeNode.noOffset) {
1483+
_emitLocalSourcePosition(condition.fileOffset);
14881484
}
14891485
if (value) {
14901486
asm.emitJumpIfNull(dest);
@@ -1631,23 +1627,20 @@ class BytecodeGenerator extends RecursiveVisitor {
16311627
savedAssemblers = null;
16321628
currentLoopDepth = 0;
16331629
savedMaxSourcePositions = <int>[];
1634-
maxSourcePosition = node.fileOffset;
1635-
1636-
locals = new LocalVariables(node, options, staticTypeContext);
1637-
locals.enterScope(node);
1638-
1639-
int position;
16401630
if (node is Procedure) {
1641-
position = node.fileStartOffset;
1631+
maxSourcePosition = node.fileStartOffset;
16421632
} else if (node is Constructor) {
1643-
position = node.startFileOffset;
1633+
maxSourcePosition = node.startFileOffset;
16441634
} else {
1645-
position = node.fileOffset;
1635+
maxSourcePosition = node.fileOffset;
16461636
}
1647-
_recordSourcePosition(position);
1637+
1638+
locals = new LocalVariables(node, options, staticTypeContext);
1639+
locals.enterScope(node);
1640+
16481641
_genPrologue(node, node.function);
16491642
_setupInitialContext(node.function);
1650-
_emitFirstDebugCheck(node.function);
1643+
_emitFirstDebugCheck(node, node.function);
16511644
_genEqualsOperatorNullHandling(node);
16521645
if (node is Procedure && node.isInstanceMember) {
16531646
_checkArguments(node.function);
@@ -1864,7 +1857,7 @@ class BytecodeGenerator extends RecursiveVisitor {
18641857
return localVariables;
18651858
}
18661859

1867-
void _genPrologue(Node node, FunctionNode? function) {
1860+
void _genPrologue(TreeNode node, FunctionNode? function) {
18681861
if (locals.makesCopyOfParameters) {
18691862
final int numOptionalPositional = function!.positionalParameters.length -
18701863
function.requiredParameterCount;
@@ -1957,6 +1950,7 @@ class BytecodeGenerator extends RecursiveVisitor {
19571950

19581951
// CheckStack must see a properly initialized context when stress-testing
19591952
// stack trace collection.
1953+
_recordInitialSourcePositionForFunction(node, function);
19601954
asm.emitCheckStack(0);
19611955

19621956
if (locals.hasFunctionTypeArgsVar && isClosure) {
@@ -2047,25 +2041,31 @@ class BytecodeGenerator extends RecursiveVisitor {
20472041
}
20482042
}
20492043

2050-
void _emitFirstDebugCheck(FunctionNode? function) {
2044+
int _initialSourcePositionForFunction(TreeNode node, FunctionNode? function) {
2045+
// The debugger expects the initial source position to correspond to the
2046+
// declaration position of the last parameter, if any, or of the function.
2047+
if (function?.namedParameters.isNotEmpty ?? false) {
2048+
return function!.namedParameters.last.fileOffset;
2049+
} else if (function?.positionalParameters.isNotEmpty ?? false) {
2050+
return function!.positionalParameters.last.fileOffset;
2051+
} else if (function != null) {
2052+
return function.fileOffset;
2053+
} else {
2054+
return node.fileOffset;
2055+
}
2056+
}
2057+
2058+
void _recordInitialSourcePositionForFunction(
2059+
TreeNode node, FunctionNode? function) {
2060+
_recordSourcePosition(_initialSourcePositionForFunction(node, function));
2061+
}
2062+
2063+
void _emitFirstDebugCheck(TreeNode node, FunctionNode? function) {
20512064
if (options.emitDebuggerStops) {
20522065
// DebugCheck instruction should be emitted after parameter variables
20532066
// are declared and copied into context.
2054-
// The debugger expects the source position to correspond to the
2055-
// declaration position of the last parameter, if any, or of the function.
20562067
// The DebugCheck must be encountered each time an async op is reentered.
2057-
if (options.emitSourcePositions && function != null) {
2058-
var pos = TreeNode.noOffset;
2059-
if (function.namedParameters.isNotEmpty) {
2060-
pos = function.namedParameters.last.fileOffset;
2061-
} else if (function.positionalParameters.isNotEmpty) {
2062-
pos = function.positionalParameters.last.fileOffset;
2063-
}
2064-
if (pos == TreeNode.noOffset) {
2065-
pos = function.fileOffset;
2066-
}
2067-
_recordSourcePosition(pos);
2068-
}
2068+
_recordInitialSourcePositionForFunction(node, function);
20692069
asm.emitDebugCheck();
20702070
}
20712071
}
@@ -2411,11 +2411,10 @@ class BytecodeGenerator extends RecursiveVisitor {
24112411

24122412
final int closureFunctionIndex = cp.addClosureFunction(closureIndex);
24132413

2414-
_recordSourcePosition(function.fileOffset);
2414+
maxSourcePosition = math.max(maxSourcePosition, function.fileOffset);
24152415
_genPrologue(node, function);
2416-
24172416
_setupInitialContext(function);
2418-
_emitFirstDebugCheck(function);
2417+
_emitFirstDebugCheck(node, function);
24192418
_checkArguments(function);
24202419
_initSuspendableFunction(function);
24212420

@@ -2685,16 +2684,34 @@ class BytecodeGenerator extends RecursiveVisitor {
26852684
continuation();
26862685
}
26872686

2687+
// Emits a source position entry and/or debugger stop as appropriate.
2688+
void _emitSourcePosition() {
2689+
if (options.emitSourcePositions) {
2690+
asm.emitSourcePosition();
2691+
}
2692+
if (options.emitDebuggerStops) {
2693+
asm.emitDebugCheck();
2694+
}
2695+
}
2696+
2697+
// Records the given file offset as the current source position and
2698+
// emits a source position entry and/or debugger stop as appropriate,
2699+
// restoring the current source position afterwards.
2700+
void _emitLocalSourcePosition(int fileOffset) {
2701+
final savedSourcePosition = asm.currentSourcePosition;
2702+
_recordSourcePosition(fileOffset);
2703+
_emitSourcePosition();
2704+
asm.currentSourcePosition = savedSourcePosition;
2705+
}
2706+
26882707
/// Generates non-local transfer from inner node [from] into the outer
26892708
/// node, executing finally blocks on the way out. [to] can be null,
26902709
/// in such case all enclosing finally blocks are executed.
26912710
/// [continuation] is invoked to generate control transfer code following
26922711
/// the last finally block.
26932712
void _generateNonLocalControlTransfer(
26942713
TreeNode from, TreeNode to, GenerateContinuation continuation) {
2695-
if (options.emitDebuggerStops && from.fileOffset != TreeNode.noOffset) {
2696-
asm.emitDebugCheck(); // Before context is unwound.
2697-
}
2714+
_emitLocalSourcePosition(from.fileOffset);
26982715
List<TryFinally> tryFinallyBlocks = _getEnclosingTryFinallyBlocks(from, to);
26992716
_addFinallyBlocks(tryFinallyBlocks, continuation);
27002717
}
@@ -3389,9 +3406,8 @@ class BytecodeGenerator extends RecursiveVisitor {
33893406
}
33903407
tryCatches![tryCatch]!.needsStackTrace = true;
33913408

3392-
if (options.emitDebuggerStops) {
3393-
asm.emitDebugCheck(); // Allow breakpoint on explicit rethrow statement.
3394-
}
3409+
// Allow breakpoint on explicit rethrow statement.
3410+
_emitSourcePosition();
33953411
_genRethrow(tryCatch);
33963412
}
33973413

@@ -3505,9 +3521,8 @@ class BytecodeGenerator extends RecursiveVisitor {
35053521

35063522
final target = node.target;
35073523
if (target is Field && !_needsSetter(target)) {
3508-
if (options.emitDebuggerStops &&
3509-
_variableSetNeedsDebugCheck(node.value)) {
3510-
asm.emitDebugCheck();
3524+
if (_variableSetNeedsDebugCheck(node.value)) {
3525+
_emitSourcePosition();
35113526
}
35123527
int cpIndex = cp.addStaticField(target);
35133528
asm.emitStoreStaticTOS(cpIndex);
@@ -3562,9 +3577,7 @@ class BytecodeGenerator extends RecursiveVisitor {
35623577
void visitThrow(Throw node) {
35633578
_generateNode(node.expression);
35643579

3565-
if (options.emitDebuggerStops) {
3566-
asm.emitDebugCheck();
3567-
}
3580+
_emitSourcePosition();
35683581
asm.emitThrow(0);
35693582
}
35703583

@@ -3649,8 +3662,8 @@ class BytecodeGenerator extends RecursiveVisitor {
36493662

36503663
_generateNode(node.value);
36513664

3652-
if (options.emitDebuggerStops && _variableSetNeedsDebugCheck(node.value)) {
3653-
asm.emitDebugCheck();
3665+
if (_variableSetNeedsDebugCheck(node.value)) {
3666+
_emitSourcePosition();
36543667
}
36553668

36563669
if (isLateFinal) {
@@ -3902,9 +3915,7 @@ class BytecodeGenerator extends RecursiveVisitor {
39023915

39033916
@override
39043917
void visitFunctionDeclaration(ast.FunctionDeclaration node) {
3905-
if (options.emitDebuggerStops) {
3906-
asm.emitDebugCheck();
3907-
}
3918+
_emitSourcePosition();
39083919
_genPushContextIfCaptured(node.variable);
39093920
_genClosure(node, node.variable.name!, node.function);
39103921
_genStoreVar(node.variable);
@@ -4311,14 +4322,12 @@ class BytecodeGenerator extends RecursiveVisitor {
43114322
}
43124323
}
43134324

4314-
if (options.emitDebuggerStops &&
4315-
(initializer == null || _variableSetNeedsDebugCheck(initializer))) {
4316-
final savedSourcePosition = asm.currentSourcePosition;
4317-
if (node.fileEqualsOffset != TreeNode.noOffset) {
4318-
_recordSourcePosition(node.fileEqualsOffset);
4319-
}
4320-
asm.emitDebugCheck();
4321-
asm.currentSourcePosition = savedSourcePosition;
4325+
// Emit a source position only as part of a DebugCheck instruction or
4326+
// if there's a store instruction to be emitted for the current PC offset.
4327+
if ((initializer == null || _variableSetNeedsDebugCheck(initializer)) &&
4328+
(options.emitDebuggerStops || emitStore)) {
4329+
_recordSourcePosition(node.fileEqualsOffset);
4330+
_emitSourcePosition();
43224331
}
43234332

43244333
if (options.emitLocalVarInfo && !asm.isUnreachable && node.name != null) {

pkg/dart2bytecode/lib/source_positions.dart

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,15 @@ class SourcePositions extends BytecodeDeclaration {
2424

2525
SourcePositions();
2626

27+
// Maps the given PC to the given file offset.
2728
void add(int pc, int fileOffset) {
28-
assert(pc > _lastPc);
2929
assert((fileOffset >= 0) || (fileOffset == syntheticCodeMarker));
3030
if (fileOffset != _lastOffset) {
31+
if (pc <= _lastPc) {
32+
throw ArgumentError(
33+
'$pc <= $_lastPc for change in source position $fileOffset != $_lastOffset',
34+
'pc');
35+
}
3136
_positions.add(pc);
3237
_positions.add(fileOffset);
3338
_lastPc = pc;

pkg/vm_service/test/common/service_test_common.dart

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -471,14 +471,22 @@ Future<String> _locationToString(
471471
IsolateRef isolateRef,
472472
Frame frame,
473473
) async {
474+
final buffer = StringBuffer();
474475
final location = frame.location!;
475-
final Script script =
476+
final script =
476477
await service.getObject(isolateRef.id!, location.script!.id!) as Script;
477478
final scriptName = p.basename(script.uri!);
479+
buffer.write(scriptName);
478480
final tokenPos = location.tokenPos!;
479481
final line = script.getLineNumberFromTokenPos(tokenPos);
480-
final column = script.getColumnNumberFromTokenPos(tokenPos);
481-
return '$scriptName:$line:$column';
482+
if (line != null) {
483+
buffer.write(':$line');
484+
final column = script.getColumnNumberFromTokenPos(tokenPos);
485+
if (column != null) {
486+
buffer.write(':$column');
487+
}
488+
}
489+
return buffer.toString();
482490
}
483491

484492
IsolateTest runStepThroughProgramRecordingStops(List<String> recordStops) {

runtime/vm/bytecode_reader.cc

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,17 @@
3535
namespace dart {
3636

3737
DEFINE_FLAG(bool, dump_kernel_bytecode, false, "Dump kernel bytecode");
38+
DEFINE_FLAG(charp,
39+
dump_kernel_bytecode_filter,
40+
nullptr,
41+
"Dump only kernel bytecode of functions with matching names");
3842

3943
namespace bytecode {
4044

45+
static bool ShouldPrint(const Function& function) {
46+
return function.NamePassesFilter(FLAG_dump_kernel_bytecode_filter);
47+
}
48+
4149
class BytecodeOffsetsMapTraits {
4250
public:
4351
static const char* Name() { return "BytecodeOffsetsMapTraits"; }
@@ -256,7 +264,9 @@ void BytecodeReaderHelper::ReadCode(const Function& function,
256264
ReadLocalVariables(bytecode, has_local_variables);
257265

258266
if (FLAG_dump_kernel_bytecode) {
259-
KernelBytecodeDisassembler::Disassemble(function);
267+
if (ShouldPrint(function)) {
268+
KernelBytecodeDisassembler::Disassemble(function);
269+
}
260270
}
261271

262272
// Initialization of fields with null literal is elided from bytecode.
@@ -303,7 +313,9 @@ void BytecodeReaderHelper::ReadCode(const Function& function,
303313
ReadLocalVariables(closure_bytecode, has_local_variables);
304314

305315
if (FLAG_dump_kernel_bytecode) {
306-
KernelBytecodeDisassembler::Disassemble(closure);
316+
if (ShouldPrint(closure)) {
317+
KernelBytecodeDisassembler::Disassemble(closure);
318+
}
307319
}
308320
}
309321
}

runtime/vm/code_patcher.cc

Lines changed: 4 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -87,24 +87,12 @@ void BytecodePatcher::RemoveBreakpointAt(uword return_address,
8787
});
8888
}
8989

90-
KBCInstr* GetInstructionBefore(const Bytecode& bytecode, uword return_address) {
91-
ASSERT(bytecode.ContainsInstructionAt(return_address));
92-
ASSERT(return_address != bytecode.PayloadStart());
93-
uword prev = bytecode.PayloadStart();
94-
uword current = KernelBytecode::Next(prev);
95-
while (current < return_address) {
96-
prev = current;
97-
current = KernelBytecode::Next(prev);
98-
}
99-
ASSERT_EQUAL(current, return_address);
100-
return reinterpret_cast<KBCInstr*>(prev);
101-
}
102-
10390
uint32_t BytecodePatcher::AddBreakpointAtWithMutatorsStopped(
10491
Thread* thread,
10592
uword return_address,
10693
const Bytecode& bytecode) {
107-
auto* const instr = GetInstructionBefore(bytecode, return_address);
94+
auto* const instr = reinterpret_cast<KBCInstr*>(
95+
bytecode.GetInstructionBefore(return_address));
10896
uint32_t old_opcode = *instr;
10997
*instr = KernelBytecode::BreakpointOpcode(instr);
11098
return old_opcode;
@@ -115,7 +103,8 @@ void BytecodePatcher::RemoveBreakpointAtWithMutatorsStopped(
115103
uword return_address,
116104
const Bytecode& bytecode,
117105
uint32_t opcode) {
118-
auto* const instr = GetInstructionBefore(bytecode, return_address);
106+
auto* const instr = reinterpret_cast<KBCInstr*>(
107+
bytecode.GetInstructionBefore(return_address));
119108
// Must be previously enabled and not yet removed.
120109
ASSERT(*instr == KernelBytecode::BreakpointOpcode(
121110
static_cast<KernelBytecode::Opcode>(opcode)));

0 commit comments

Comments
 (0)