[VM/Debugger] Mark the `=` tokens within assignment statements as locations where breakpoints can be set
TEST=pkg/vm_service/test/break_on_equals_signs_of_assignments_test.dart
Fixes: https://github.com/dart-lang/sdk/issues/56932
Change-Id: Id5ed23c645b614586e4bf769dbbea9704035746b
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/398680
Commit-Queue: Derek Xu <derekx@google.com>
Reviewed-by: Ben Konyi <bkonyi@google.com>
diff --git a/pkg/vm_service/test/async_star_step_out_test.dart b/pkg/vm_service/test/async_star_step_out_test.dart
index 4f6e3d5..879599f 100644
--- a/pkg/vm_service/test/async_star_step_out_test.dart
+++ b/pkg/vm_service/test/async_star_step_out_test.dart
@@ -77,7 +77,7 @@
stepOut, // step out of generator.
hasStoppedAtBreakpoint,
- stoppedAtLine(LINE_H), // await for.
+ stoppedAtLineColumn(line: LINE_H, column: 46), // on '{'
stepInto,
hasStoppedAtBreakpoint, // debugger().
@@ -95,7 +95,7 @@
stepOut, // step out of generator.
hasStoppedAtBreakpoint,
- stoppedAtLine(LINE_H), // await for.
+ stoppedAtLineColumn(line: LINE_H, column: 46), // on '{'
stepInto,
hasStoppedAtBreakpoint, // debugger().
diff --git a/pkg/vm_service/test/break_on_equals_signs_of_assignments_test.dart b/pkg/vm_service/test/break_on_equals_signs_of_assignments_test.dart
new file mode 100644
index 0000000..5bfafe4
--- /dev/null
+++ b/pkg/vm_service/test/break_on_equals_signs_of_assignments_test.dart
@@ -0,0 +1,96 @@
+// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'common/service_test_common.dart';
+import 'common/test_helper.dart';
+
+const String shortFile = 'break_on_equals_signs_of_assignments_test.dart';
+
+// AUTOGENERATED START
+//
+// Update these constants by running:
+//
+// dart pkg/vm_service/test/update_line_numbers.dart <test.dart>
+//
+const LINE_A = 38;
+const LINE_B = 40;
+const LINE_C = 42;
+const LINE_D = 44;
+const LINE_E = 46;
+const LINE_F = 48;
+const LINE_G = 51;
+// AUTOGENERATED END
+
+class E {
+ int x = 0;
+}
+
+void testeeMain() {
+ // In https://dartbug.com/56932, it was brought up that requesting a
+ // breakpoint on line A below used to result in a breakpoint getting set on
+ // the next line, but after we made some changes to breakpoint resolution
+ // (https://github.com/dart-lang/sdk/commit/cdacfd80f1f5e2940056dbc32e9a8faaf1928db1),
+ // requesting a breakpoint line A resulted in no breakpoint getting set. After
+ // having a discussion on that issue, we decided to mark the `=` tokens within
+ // assignment statements as locations where breakpoints can be set, and this
+ // test ensures that the marking is happening correctly.
+ var a = // LINE_A
+ 123;
+ late var b = // LINE_B
+ 123;
+ final c = // LINE_C
+ 123;
+ late final d = // LINE_D
+ 123;
+ a = // LINE_E
+ 456;
+ b = // LINE_F
+ 456;
+ final e = E();
+ e.x = // LINE_G
+ 123;
+
+ print(a);
+ print(b);
+ print(c);
+ print(d);
+ print(e);
+}
+
+List<String> stops = [];
+
+const List<String> expected = [
+ '$shortFile:$LINE_A:9', // on '='
+ '$shortFile:$LINE_B:14', // on '='
+ '$shortFile:$LINE_C:11', // on '='
+ '$shortFile:$LINE_D:16', // on '='
+ // Lines E, F and G contain assignment expressions instead of assignment
+ // statements, so breakpoints get resolved on the LHS of them instead of on
+ // the '=' tokens.
+ '$shortFile:$LINE_E:3', // on 'a'
+ '$shortFile:$LINE_F:3', // on 'b'
+ '$shortFile:$LINE_G:5', // on 'x'
+];
+
+final tests = <IsolateTest>[
+ hasPausedAtStart,
+ setBreakpointAtLine(LINE_A),
+ setBreakpointAtLine(LINE_B),
+ setBreakpointAtLine(LINE_C),
+ setBreakpointAtLine(LINE_D),
+ setBreakpointAtLine(LINE_E),
+ setBreakpointAtLine(LINE_F),
+ setBreakpointAtLine(LINE_G),
+ resumeProgramRecordingStops(stops, false),
+ checkRecordedStops(stops, expected),
+];
+
+Future<void> main([args = const <String>[]]) => runIsolateTests(
+ args,
+ tests,
+ shortFile,
+ testeeConcurrent: testeeMain,
+ pauseOnStart: true,
+ pauseOnExit: true,
+ );
diff --git a/pkg/vm_service/test/breakpoints_ignore_late_initialization_error_instructions_test.dart b/pkg/vm_service/test/breakpoints_ignore_late_initialization_error_instructions_test.dart
index 1310b49..c22990d 100644
--- a/pkg/vm_service/test/breakpoints_ignore_late_initialization_error_instructions_test.dart
+++ b/pkg/vm_service/test/breakpoints_ignore_late_initialization_error_instructions_test.dart
@@ -16,9 +16,9 @@
//
// dart pkg/vm_service/test/update_line_numbers.dart <test.dart>
//
-const LINE_A = 33;
-const LINE_B = 42;
-const LINE_C = 51;
+const LINE_A = 34;
+const LINE_B = 44;
+const LINE_C = 53;
// AUTOGENERATED END
int getThree() => 3;
@@ -26,28 +26,30 @@
void testeeMain() {
// ignore: prefer_final_locals
late int x = 1;
- // When a late variable is read, the VM performs checks to ensure that the
- // variable has been initialized. When a breakpoint is set on the following
- // line, it should resolve to the [toDouble] call instruction, not to an
- // instruction part of the late variable initialization checks.
- final double xd = x.toDouble(); // LINE_A
+ final double xd =
+ // When a late variable is read, the VM performs checks to ensure that the
+ // variable has been initialized. When a breakpoint is set on the
+ // following line, it should resolve to the [toDouble] call instruction,
+ // not to an instruction part of the late variable initialization checks.
+ x.toDouble(); // LINE_A
print(xd);
late final int y = 2;
- // When a late final variable is read, the VM performs checks to ensure that
- // the variable has been assigned a value exactly once. When a breakpoint is
- // set on the following line, it should resolve to the [toDouble] call
- // instruction, not to an instruction part of the late variable assignment
- // checks.
- final double yd = y.toDouble(); // LINE_B
+ final double yd =
+ // When a late final variable is read, the VM performs checks to ensure
+ // that the variable has been assigned a value exactly once. When a
+ // breakpoint is set on the following line, it should resolve to the
+ // [toDouble] call instruction, not to an instruction part of the late
+ // variable assignment checks.
+ y.toDouble(); // LINE_B
print(yd);
late final int z;
// When a late final variable is assigned a value, the VM performs checks to
// ensure that the variable has not already been initialized. When a
- // breakpoint is set on the following line, it should resolve to the
- // [getThree] call instruction, not to an instruction part of the late
- // variable initialization checks.
+ // breakpoint is set on the following line, it should resolve on the '='
+ // token, not to an instruction part of the late variable initialization
+ // checks.
z = getThree(); // LINE_C
print(z);
}
@@ -55,8 +57,8 @@
List<String> stops = [];
const List<String> expected = [
- '$shortFile:$LINE_A:23', // on 'toDouble'
- '$shortFile:$LINE_B:23', // on 'toDouble'
+ '$shortFile:$LINE_A:9', // on 'toDouble'
+ '$shortFile:$LINE_B:9', // on 'toDouble'
'$shortFile:$LINE_C:7', // on 'getThree'
];
diff --git a/pkg/vm_service/test/issue_27238_test.dart b/pkg/vm_service/test/issue_27238_test.dart
index c1ded19..11aa19a 100644
--- a/pkg/vm_service/test/issue_27238_test.dart
+++ b/pkg/vm_service/test/issue_27238_test.dart
@@ -15,24 +15,25 @@
//
// dart pkg/vm_service/test/update_line_numbers.dart <test.dart>
//
-const LINE_0 = 27;
-const LINE_A = 28;
-const LINE_B = 31;
+const LINE_0 = 28;
+const LINE_A = 29;
+const LINE_B = 30;
const LINE_C = 32;
-const LINE_D = 34;
+const LINE_D = 33;
const LINE_E = 35;
+const LINE_F = 36;
// AUTOGENERATED END
Future<void> testMain() async {
debugger(); // LINE_0.
final future1 = Future.value(); // LINE_A.
- final future2 = Future.value();
+ final future2 = Future.value(); // LINE_B.
- await future1; // LINE_B.
- await future2; // LINE_C.
+ await future1; // LINE_C.
+ await future2; // LINE_D.
- print('foo1'); // LINE_D.
- print('foo2'); // LINE_E.
+ print('foo1'); // LINE_E.
+ print('foo2'); // LINE_F.
}
final tests = <IsolateTest>[
@@ -40,18 +41,28 @@
stoppedAtLine(LINE_0),
stepOver,
hasStoppedAtBreakpoint,
- stoppedAtLine(LINE_A),
+ stoppedAtLineColumn(line: LINE_A, column: 17), // on '='
smartNext,
hasStoppedAtBreakpoint,
+ stoppedAtLineColumn(line: LINE_A, column: 26), // on 'value'
smartNext,
hasStoppedAtBreakpoint,
- stoppedAtLine(LINE_B),
+ stoppedAtLineColumn(line: LINE_B, column: 17), // on '='
+ smartNext,
+ hasStoppedAtBreakpoint,
+ stoppedAtLineColumn(line: LINE_B, column: 26), // on 'value'
smartNext,
hasStoppedAtBreakpoint,
stoppedAtLine(LINE_C),
smartNext,
hasStoppedAtBreakpoint,
stoppedAtLine(LINE_D),
+ smartNext,
+ hasStoppedAtBreakpoint,
+ stoppedAtLine(LINE_E),
+ smartNext,
+ hasStoppedAtBreakpoint,
+ stoppedAtLine(LINE_F),
resumeIsolate,
];
diff --git a/runtime/observatory/tests/service/async_star_step_out_test.dart b/runtime/observatory/tests/service/async_star_step_out_test.dart
deleted file mode 100644
index 110f704..0000000
--- a/runtime/observatory/tests/service/async_star_step_out_test.dart
+++ /dev/null
@@ -1,115 +0,0 @@
-// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-//
-// VMOptions=--async-debugger --verbose-debug
-
-import 'dart:developer';
-import 'service_test_common.dart';
-import 'test_helper.dart';
-
-const LINE_A = 25;
-const LINE_B = 26;
-const LINE_C = 30;
-const LINE_D = 33;
-const LINE_E = 40;
-const LINE_F = 41;
-const LINE_G = 42;
-const LINE_H = 31;
-const LINE_I = 35;
-
-const LINE_0 = 31;
-const LINE_1 = 39;
-
-foobar() async* {
- yield 1; // LINE_A.
- yield 2; // LINE_B.
-}
-
-helper() async {
- print('helper'); // LINE_C.
- await for (var _ in foobar()) /* LINE_H */ {
- debugger(); // LINE_0.
- print('loop'); // LINE_D.
- }
- return null; // LINE_I.
-}
-
-testMain() {
- debugger(); // LINE_1.
- print('mmmmm'); // LINE_E.
- helper(); // LINE_F.
- print('z'); // LINE_G.
-}
-
-var tests = <IsolateTest>[
- hasStoppedAtBreakpoint,
- stoppedAtLine(LINE_1),
- stepOver, // debugger.
-
- hasStoppedAtBreakpoint,
- stoppedAtLine(LINE_E),
- stepOver, // print.
-
- hasStoppedAtBreakpoint,
- stoppedAtLine(LINE_F),
- stepInto,
-
- hasStoppedAtBreakpoint,
- stoppedAtLine(LINE_C),
- stepOver, // print.
-
- hasStoppedAtBreakpoint,
- stoppedAtLine(LINE_H), // foobar().
- stepInto,
-
- hasStoppedAtBreakpoint,
- stoppedAtLine(LINE_H), // await for.
- stepInto,
-
- hasStoppedAtBreakpoint,
- stoppedAtLine(LINE_A),
- stepOut, // step out of generator.
-
- hasStoppedAtBreakpoint,
- stoppedAtLine(LINE_H), // await for.
- stepInto,
-
- hasStoppedAtBreakpoint, // debugger().
- stepInto,
-
- hasStoppedAtBreakpoint,
- stoppedAtLine(LINE_D), // print.
- stepInto,
-
- hasStoppedAtBreakpoint, // await for.
- stepInto,
-
- hasStoppedAtBreakpoint, // back in generator.
- stoppedAtLine(LINE_B),
- stepOut, // step out of generator.
-
- hasStoppedAtBreakpoint,
- stoppedAtLine(LINE_H), // await for.
- stepInto,
-
- hasStoppedAtBreakpoint, // debugger().
- stepInto,
-
- hasStoppedAtBreakpoint,
- stoppedAtLine(LINE_D), // print.
- stepInto,
-
- hasStoppedAtBreakpoint,
- stoppedAtLine(LINE_H), // await for.
- stepInto,
-
- hasStoppedAtBreakpoint,
- stepOut, // step out of generator.
-
- hasStoppedAtBreakpoint,
- stoppedAtLine(LINE_I), // return null.
-];
-
-main(args) => runIsolateTestsSynchronous(args, tests,
- testeeConcurrent: testMain, extraArgs: extraDebuggingArgs);
diff --git a/runtime/observatory/tests/service/async_step_out_test.dart b/runtime/observatory/tests/service/async_step_out_test.dart
deleted file mode 100644
index 1a728bb..0000000
--- a/runtime/observatory/tests/service/async_step_out_test.dart
+++ /dev/null
@@ -1,85 +0,0 @@
-// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-//
-// VMOptions=--async-debugger --verbose-debug
-
-import 'dart:developer';
-import 'service_test_common.dart';
-import 'test_helper.dart';
-
-// AUTOGENERATED START
-//
-// Update these constants by running:
-//
-// dart runtime/observatory/tests/service/update_line_numbers.dart <test.dart>
-//
-const int LINE_A = 29;
-const int LINE_B = 30;
-const int LINE_C = 31;
-const int LINE_G = 36;
-const int LINE_0 = 40;
-const int LINE_D = 41;
-const int LINE_E = 42;
-const int LINE_F = 43;
-const int LINE_H = 44;
-// AUTOGENERATED END
-
-Future<int> helper() async {
- await null; // LINE_A.
- print('line b'); // LINE_B.
- print('line c'); // LINE_C.
- return 0;
-}
-
-Future<void> testMain() async {
- int process(int value) /* LINE_G */ {
- return value + 1;
- }
-
- debugger(); // LINE_0.
- print('line d'); // LINE_D.
- await helper().then(process); // LINE_E.
- final v = process(10); // LINE_F.
- print('line h'); // LINE_H.
-}
-
-var tests = <IsolateTest>[
- hasStoppedAtBreakpoint,
- stoppedAtLine(LINE_0),
- stepOver, // debugger.
-
- hasStoppedAtBreakpoint,
- stoppedAtLine(LINE_D),
- stepOver, // print.
-
- hasStoppedAtBreakpoint,
- stoppedAtLine(LINE_E),
- stepInto,
-
- hasStoppedAtBreakpoint,
- stoppedAtLine(LINE_A),
- asyncNext,
-
- hasStoppedAtBreakpoint,
- stoppedAtLine(LINE_B),
- stepOver, // print.
-
- hasStoppedAtBreakpoint,
- stoppedAtLine(LINE_C),
- stepOut, // out of helper to awaiter testMain.
-
- hasStoppedAtBreakpoint,
- stoppedAtLine(LINE_G),
- stepOut, // out of helper to awaiter testMain.
-
- hasStoppedAtBreakpoint,
- stoppedAtLine(LINE_F),
- stepOver,
-
- hasStoppedAtBreakpoint,
- stoppedAtLine(LINE_H),
-];
-
-main(args) => runIsolateTests(args, tests,
- testeeConcurrent: testMain, extraArgs: extraDebuggingArgs);
diff --git a/runtime/observatory/tests/service/issue_27238_test.dart b/runtime/observatory/tests/service/issue_27238_test.dart
deleted file mode 100644
index 2b7d380..0000000
--- a/runtime/observatory/tests/service/issue_27238_test.dart
+++ /dev/null
@@ -1,51 +0,0 @@
-// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-// VMOptions=--verbose_debug
-
-import 'service_test_common.dart';
-import 'dart:async';
-import 'test_helper.dart';
-import 'dart:developer';
-
-const int LINE_A = 21;
-const int LINE_B = 24;
-const int LINE_C = 25;
-const int LINE_D = 27;
-const int LINE_E = 28;
-
-const int LINE_0 = 20;
-
-testMain() async {
- debugger(); // LINE_0.
- Future future1 = new Future.value(); // LINE_A.
- Future future2 = new Future.value();
-
- await future1; // LINE_B.
- await future2; // LINE_C.
-
- print('foo1'); // LINE_D.
- print('foo2'); // LINE_E.
-}
-
-var tests = <IsolateTest>[
- hasStoppedAtBreakpoint,
- stoppedAtLine(LINE_0),
- stepOver,
- hasStoppedAtBreakpoint,
- stoppedAtLine(LINE_A),
- smartNext,
- hasStoppedAtBreakpoint,
- smartNext,
- hasStoppedAtBreakpoint,
- stoppedAtLine(LINE_B),
- smartNext,
- hasStoppedAtBreakpoint,
- stoppedAtLine(LINE_C),
- smartNext,
- hasStoppedAtBreakpoint,
- stoppedAtLine(LINE_D),
- resumeIsolate,
-];
-
-main(args) => runIsolateTests(args, tests, testeeConcurrent: testMain);
diff --git a/runtime/vm/compiler/backend/memory_copy_test.cc b/runtime/vm/compiler/backend/memory_copy_test.cc
index 47b6aa7..014d646 100644
--- a/runtime/vm/compiler/backend/memory_copy_test.cc
+++ b/runtime/vm/compiler/backend/memory_copy_test.cc
@@ -209,8 +209,11 @@
EXPECT(cursor.TryMatch({
kMoveGlob,
+ kMatchAndMoveDebugStepCheck,
+ kMatchAndMoveDebugStepCheck,
kMatchAndMoveRecordCoverage,
{kMatchAndMoveStaticCall, &pointer},
+ kMatchAndMoveDebugStepCheck,
kMatchAndMoveRecordCoverage,
{kMatchAndMoveStaticCall, &pointer2},
kMatchAndMoveRecordCoverage,
@@ -246,8 +249,11 @@
ILMatcher cursor(flow_graph, flow_graph->graph_entry()->normal_entry());
EXPECT(cursor.TryMatch({
kMoveGlob,
+ kMatchAndMoveDebugStepCheck,
+ kMatchAndMoveDebugStepCheck,
kMatchAndMoveRecordCoverage,
kMatchAndMoveStaticCall,
+ kMatchAndMoveDebugStepCheck,
kMatchAndMoveRecordCoverage,
kMatchAndMoveStaticCall,
kMatchAndMoveRecordCoverage,
diff --git a/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc b/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc
index eb4cf85..6efe51a 100644
--- a/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc
+++ b/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc
@@ -5894,7 +5894,11 @@
? helper.equals_position_
: helper.position_;
if (position != nullptr) *position = helper.position_;
- if (NeedsDebugStepCheck(stack(), debug_position) && !helper.IsHoisted()) {
+ if (debug_position.IsDebugPause() && !helper.IsHoisted() &&
+ // We always make it possible to add a breakpoint on the equals sign if it
+ // exists.
+ (helper.equals_position_.IsReal() ||
+ NeedsDebugStepCheck(stack(), debug_position))) {
instructions = DebugStepCheck(debug_position) + instructions;
}
instructions += StoreLocal(helper.position_, variable);