@@ -1021,8 +1021,11 @@ class BytecodeGenerator extends RecursiveVisitor {
1021
1021
// variable 'foo' has type 'dynamic'.
1022
1022
late final implicitCallName = Name ('implicit:call' );
1023
1023
1024
- void _recordSourcePosition (int fileOffset) {
1024
+ void _recordSourcePosition (int fileOffset, [ int ? flags] ) {
1025
1025
asm.currentSourcePosition = fileOffset;
1026
+ if (flags != null ) {
1027
+ asm.currentSourcePositionFlags = flags;
1028
+ }
1026
1029
maxSourcePosition = math.max (maxSourcePosition, fileOffset);
1027
1030
}
1028
1031
@@ -1031,9 +1034,11 @@ class BytecodeGenerator extends RecursiveVisitor {
1031
1034
return ;
1032
1035
}
1033
1036
final savedSourcePosition = asm.currentSourcePosition;
1034
- _recordSourcePosition (node.fileOffset);
1037
+ final savedFlags = asm.currentSourcePositionFlags;
1038
+ _recordSourcePosition (node.fileOffset, 0 );
1035
1039
node.accept (this );
1036
1040
asm.currentSourcePosition = savedSourcePosition;
1041
+ asm.currentSourcePositionFlags = savedFlags;
1037
1042
}
1038
1043
1039
1044
void _generateNodeList (List <TreeNode > nodes) {
@@ -1216,6 +1221,9 @@ class BytecodeGenerator extends RecursiveVisitor {
1216
1221
break ;
1217
1222
}
1218
1223
if (returnMethod != null ) {
1224
+ // Unlike other async machinery, this can't be marked synthetic
1225
+ // as the method may return directly from the direct call and so
1226
+ // the debugger needs to pause at it, not the following return.
1219
1227
asm.emitPopLocal (locals.returnVarIndexInFrame);
1220
1228
asm.emitPush (locals.suspendStateVarIndexInFrame);
1221
1229
asm.emitPush (locals.returnVarIndexInFrame);
@@ -1633,17 +1641,19 @@ class BytecodeGenerator extends RecursiveVisitor {
1633
1641
savedAssemblers = null ;
1634
1642
currentLoopDepth = 0 ;
1635
1643
savedMaxSourcePositions = < int > [];
1636
- if (node is Procedure ) {
1637
- maxSourcePosition = node.fileStartOffset;
1638
- } else if (node is Constructor ) {
1639
- maxSourcePosition = node.startFileOffset;
1640
- } else {
1641
- maxSourcePosition = node.fileOffset;
1642
- }
1643
1644
1644
1645
locals = new LocalVariables (node, options, staticTypeContext);
1645
1646
locals.enterScope (node);
1646
1647
1648
+ final int startPosition;
1649
+ if (node is Procedure ) {
1650
+ startPosition = node.fileStartOffset;
1651
+ } else if (node is Constructor ) {
1652
+ startPosition = node.startFileOffset;
1653
+ } else {
1654
+ startPosition = node.fileOffset;
1655
+ }
1656
+ _recordSourcePosition (startPosition, SourcePositions .syntheticFlag);
1647
1657
_genPrologue (node, node.function);
1648
1658
_setupInitialContext (node.function);
1649
1659
_emitFirstDebugCheck (node, node.function);
@@ -1677,6 +1687,9 @@ class BytecodeGenerator extends RecursiveVisitor {
1677
1687
if (! locals.isSuspendableFunction) {
1678
1688
return ;
1679
1689
}
1690
+
1691
+ final savedFlags = asm.currentSourcePositionFlags;
1692
+ asm.currentSourcePositionFlags | = SourcePositions .syntheticFlag;
1680
1693
Procedure initMethod;
1681
1694
switch (function! .dartAsyncMarker) {
1682
1695
case AsyncMarker .Async :
@@ -1696,6 +1709,10 @@ class BytecodeGenerator extends RecursiveVisitor {
1696
1709
asm.emitPopLocal (locals.suspendStateVarIndexInFrame);
1697
1710
1698
1711
if (function.dartAsyncMarker != AsyncMarker .Async ) {
1712
+ final savedFlags = asm.currentSourcePositionFlags;
1713
+ // Mark all of the code in this block as within the yield point.
1714
+ asm.currentSourcePositionFlags | = SourcePositions .yieldPointFlag;
1715
+ asm.emitSourcePositionForCall ();
1699
1716
// Suspend async* and sync* functions after prologue is finished.
1700
1717
Label done = Label ();
1701
1718
asm.emitSuspend (done);
@@ -1710,6 +1727,7 @@ class BytecodeGenerator extends RecursiveVisitor {
1710
1727
1711
1728
asm.bind (done);
1712
1729
asm.emitDrop1 (); // Discard result of Suspend.
1730
+ asm.currentSourcePositionFlags = savedFlags;
1713
1731
}
1714
1732
1715
1733
if (function.dartAsyncMarker == AsyncMarker .SyncStar &&
@@ -1729,6 +1747,7 @@ class BytecodeGenerator extends RecursiveVisitor {
1729
1747
asyncTryBlock.needsStackTrace = true ;
1730
1748
asyncTryBlock.types.add (cp.addType (const DynamicType ()));
1731
1749
}
1750
+ asm.currentSourcePositionFlags = savedFlags;
1732
1751
}
1733
1752
1734
1753
void _endSuspendableFunction (FunctionNode ? function) {
@@ -1744,6 +1763,8 @@ class BytecodeGenerator extends RecursiveVisitor {
1744
1763
// Exception handlers are reachable although there are no labels or jumps.
1745
1764
asm.isUnreachable = false ;
1746
1765
1766
+ final savedFlags = asm.currentSourcePositionFlags;
1767
+ asm.currentSourcePositionFlags | = SourcePositions .syntheticFlag;
1747
1768
asm.emitSetFrame (locals.frameSize);
1748
1769
1749
1770
final rethrowException = Label ();
@@ -1765,6 +1786,7 @@ class BytecodeGenerator extends RecursiveVisitor {
1765
1786
asm.emitMoveSpecial (SpecialIndex .stackTrace, temp);
1766
1787
asm.emitPush (temp);
1767
1788
asm.emitThrow (1 );
1789
+ asm.currentSourcePositionFlags = savedFlags;
1768
1790
}
1769
1791
}
1770
1792
@@ -1954,9 +1976,11 @@ class BytecodeGenerator extends RecursiveVisitor {
1954
1976
}
1955
1977
}
1956
1978
1979
+ // The CheckStack below is the instruction which should be used for function
1980
+ // entry breakpoints.
1981
+ _recordInitialSourcePositionForFunction (node, function);
1957
1982
// CheckStack must see a properly initialized context when stress-testing
1958
1983
// stack trace collection.
1959
- _recordInitialSourcePositionForFunction (node, function);
1960
1984
asm.emitCheckStack (0 );
1961
1985
1962
1986
if (locals.hasFunctionTypeArgsVar && isClosure) {
@@ -2063,7 +2087,8 @@ class BytecodeGenerator extends RecursiveVisitor {
2063
2087
2064
2088
void _recordInitialSourcePositionForFunction (
2065
2089
TreeNode node, FunctionNode ? function) {
2066
- _recordSourcePosition (_initialSourcePositionForFunction (node, function));
2090
+ final position = _initialSourcePositionForFunction (node, function);
2091
+ _recordSourcePosition (position, 0 );
2067
2092
}
2068
2093
2069
2094
void _emitFirstDebugCheck (TreeNode node, FunctionNode ? function) {
@@ -2417,7 +2442,7 @@ class BytecodeGenerator extends RecursiveVisitor {
2417
2442
2418
2443
final int closureFunctionIndex = cp.addClosureFunction (closureIndex);
2419
2444
2420
- maxSourcePosition = math. max (maxSourcePosition, function.fileOffset);
2445
+ _recordSourcePosition ( function.fileOffset, SourcePositions .syntheticFlag );
2421
2446
_genPrologue (node, function);
2422
2447
_setupInitialContext (function);
2423
2448
_emitFirstDebugCheck (node, function);
@@ -2695,7 +2720,8 @@ class BytecodeGenerator extends RecursiveVisitor {
2695
2720
if (options.emitSourcePositions) {
2696
2721
asm.emitSourcePosition ();
2697
2722
}
2698
- if (options.emitDebuggerStops) {
2723
+ if (options.emitDebuggerStops &&
2724
+ (asm.currentSourcePositionFlags & SourcePositions .syntheticFlag) == 0 ) {
2699
2725
asm.emitDebugCheck ();
2700
2726
}
2701
2727
}
@@ -3413,8 +3439,7 @@ class BytecodeGenerator extends RecursiveVisitor {
3413
3439
tryCatches! [tryCatch]! .needsStackTrace = true ;
3414
3440
3415
3441
// Allow breakpoint on explicit rethrow statement.
3416
- _emitSourcePosition ();
3417
- _genRethrow (tryCatch);
3442
+ _genRethrow (tryCatch, isSynthetic: false );
3418
3443
}
3419
3444
3420
3445
bool _hasNonTrivialInitializer (Field field) {
@@ -4147,7 +4172,13 @@ class BytecodeGenerator extends RecursiveVisitor {
4147
4172
}
4148
4173
}
4149
4174
4150
- void _genRethrow (TreeNode node) {
4175
+ void _genRethrow (TreeNode node, {required bool isSynthetic}) {
4176
+ final savedFlags = asm.currentSourcePositionFlags;
4177
+ if (isSynthetic) {
4178
+ asm.currentSourcePositionFlags | = SourcePositions .syntheticFlag;
4179
+ } else {
4180
+ asm.currentSourcePositionFlags & = ~ SourcePositions .syntheticFlag;
4181
+ }
4151
4182
final capturedExceptionVar = locals.capturedExceptionVar (node);
4152
4183
if (capturedExceptionVar != null ) {
4153
4184
assert (locals.isCaptured (capturedExceptionVar));
@@ -4165,6 +4196,7 @@ class BytecodeGenerator extends RecursiveVisitor {
4165
4196
}
4166
4197
4167
4198
asm.emitThrow (1 );
4199
+ asm.currentSourcePositionFlags = savedFlags;
4168
4200
}
4169
4201
4170
4202
@override
@@ -4241,7 +4273,7 @@ class BytecodeGenerator extends RecursiveVisitor {
4241
4273
4242
4274
if (! hasCatchAll) {
4243
4275
tryBlock.needsStackTrace = true ;
4244
- _genRethrow (node);
4276
+ _genRethrow (node, isSynthetic : true );
4245
4277
}
4246
4278
4247
4279
asm.bind (done);
@@ -4277,7 +4309,7 @@ class BytecodeGenerator extends RecursiveVisitor {
4277
4309
_generateNode (node.finalizer);
4278
4310
4279
4311
tryBlock.needsStackTrace = true ; // For rethrowing.
4280
- _genRethrow (node);
4312
+ _genRethrow (node, isSynthetic : true );
4281
4313
4282
4314
for (var finallyBlock in finallyBlocks[node]! ) {
4283
4315
asm.bind (finallyBlock.entry);
@@ -4457,6 +4489,14 @@ class BytecodeGenerator extends RecursiveVisitor {
4457
4489
void visitAwaitExpression (AwaitExpression node) {
4458
4490
_generateNode (node.operand);
4459
4491
4492
+ // The rest of the await expression bytecode is the yield point.
4493
+ // Emit a source position at the start to ensure that if the debugger
4494
+ // is paused anywhere in this bytecode, a request to step over the await
4495
+ // doesn't pause at either the direct call or the return, which have the
4496
+ // same source position information.
4497
+ final savedFlags = asm.currentSourcePositionFlags;
4498
+ asm.currentSourcePositionFlags | = SourcePositions .yieldPointFlag;
4499
+ asm.emitSourcePositionForCall ();
4460
4500
final int temp = locals.tempIndexInFrame (node);
4461
4501
asm.emitPopLocal (temp);
4462
4502
@@ -4478,6 +4518,7 @@ class BytecodeGenerator extends RecursiveVisitor {
4478
4518
_genDirectCall (_await, objectTable.getArgDescHandle (2 ), 2 );
4479
4519
}
4480
4520
asm.emitReturnTOS ();
4521
+ asm.currentSourcePositionFlags = savedFlags;
4481
4522
4482
4523
asm.bind (done);
4483
4524
}
0 commit comments