[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);