OLD | NEW |
1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 library debugger_page_element; | 5 library debugger_page_element; |
6 | 6 |
7 import 'dart:async'; | 7 import 'dart:async'; |
8 import 'dart:html'; | 8 import 'dart:html'; |
9 import 'observatory_element.dart'; | 9 import 'observatory_element.dart'; |
10 import 'package:observatory/cli.dart'; | 10 import 'package:observatory/cli.dart'; |
(...skipping 124 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
135 '\n' | 135 '\n' |
136 'Syntax: continue\n'; | 136 'Syntax: continue\n'; |
137 } | 137 } |
138 | 138 |
139 class NextCommand extends DebuggerCommand { | 139 class NextCommand extends DebuggerCommand { |
140 NextCommand(Debugger debugger) : super(debugger, 'next', []); | 140 NextCommand(Debugger debugger) : super(debugger, 'next', []); |
141 | 141 |
142 Future run(List<String> args) { | 142 Future run(List<String> args) { |
143 if (debugger.isolatePaused()) { | 143 if (debugger.isolatePaused()) { |
144 var event = debugger.isolate.pauseEvent; | 144 var event = debugger.isolate.pauseEvent; |
145 if (event.eventType == 'IsolateCreated') { | 145 if (event.eventType == ServiceEvent.kPauseStart) { |
146 debugger.console.print("Type 'continue' to start the isolate"); | 146 debugger.console.print("Type 'continue' to start the isolate"); |
147 return new Future.value(null); | 147 return new Future.value(null); |
148 } | 148 } |
149 if (event.eventType == 'IsolateShutdown') { | 149 if (event.eventType == ServiceEvent.kPauseExit) { |
150 debugger.console.print("Type 'continue' to exit the isolate"); | 150 debugger.console.print("Type 'continue' to exit the isolate"); |
151 return new Future.value(null); | 151 return new Future.value(null); |
152 } | 152 } |
153 return debugger.isolate.stepOver(); | 153 return debugger.isolate.stepOver(); |
154 } else { | 154 } else { |
155 debugger.console.print('The program is already running'); | 155 debugger.console.print('The program is already running'); |
156 return new Future.value(null); | 156 return new Future.value(null); |
157 } | 157 } |
158 } | 158 } |
159 | 159 |
160 String helpShort = | 160 String helpShort = |
161 'Continue running the isolate until it reaches the next source location ' | 161 'Continue running the isolate until it reaches the next source location ' |
162 'in the current function'; | 162 'in the current function'; |
163 | 163 |
164 String helpLong = | 164 String helpLong = |
165 'Continue running the isolate until it reaches the next source location ' | 165 'Continue running the isolate until it reaches the next source location ' |
166 'in the current function.\n' | 166 'in the current function.\n' |
167 '\n' | 167 '\n' |
168 'Syntax: next\n'; | 168 'Syntax: next\n'; |
169 } | 169 } |
170 | 170 |
171 class StepCommand extends DebuggerCommand { | 171 class StepCommand extends DebuggerCommand { |
172 StepCommand(Debugger debugger) : super(debugger, 'step', []); | 172 StepCommand(Debugger debugger) : super(debugger, 'step', []); |
173 | 173 |
174 Future run(List<String> args) { | 174 Future run(List<String> args) { |
175 if (debugger.isolatePaused()) { | 175 if (debugger.isolatePaused()) { |
176 var event = debugger.isolate.pauseEvent; | 176 var event = debugger.isolate.pauseEvent; |
177 if (event.eventType == 'IsolateCreated') { | 177 if (event.eventType == ServiceEvent.kPauseStart) { |
178 debugger.console.print("Type 'continue' to start the isolate"); | 178 debugger.console.print("Type 'continue' to start the isolate"); |
179 return new Future.value(null); | 179 return new Future.value(null); |
180 } | 180 } |
181 if (event.eventType == 'IsolateShutdown') { | 181 if (event.eventType == ServiceEvent.kPauseExit) { |
182 debugger.console.print("Type 'continue' to exit the isolate"); | 182 debugger.console.print("Type 'continue' to exit the isolate"); |
183 return new Future.value(null); | 183 return new Future.value(null); |
184 } | 184 } |
185 return debugger.isolate.stepInto(); | 185 return debugger.isolate.stepInto(); |
186 } else { | 186 } else { |
187 debugger.console.print('The program is already running'); | 187 debugger.console.print('The program is already running'); |
188 return new Future.value(null); | 188 return new Future.value(null); |
189 } | 189 } |
190 } | 190 } |
191 | 191 |
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
251 }); | 251 }); |
252 } | 252 } |
253 | 253 |
254 Future _handleBreakpointResult(loc, result) { | 254 Future _handleBreakpointResult(loc, result) { |
255 if (result is DartError) { | 255 if (result is DartError) { |
256 debugger.console.print('Unable to set breakpoint at ${loc}'); | 256 debugger.console.print('Unable to set breakpoint at ${loc}'); |
257 } else { | 257 } else { |
258 // TODO(turnidge): Adding a duplicate breakpoint is | 258 // TODO(turnidge): Adding a duplicate breakpoint is |
259 // currently ignored. May want to change the protocol to | 259 // currently ignored. May want to change the protocol to |
260 // inform us when this happens. | 260 // inform us when this happens. |
261 | |
262 // The BreakpointResolved event prints resolved | |
263 // breakpoints already. Just print the unresolved ones here. | |
264 Breakpoint bpt = result; | |
265 if (!bpt.resolved) { | |
266 return debugger._reportBreakpointAdded(bpt); | |
267 } | |
268 } | 261 } |
269 return new Future.value(null); | 262 return new Future.value(null); |
270 } | 263 } |
271 | 264 |
272 Future<List<String>> complete(List<String> args) { | 265 Future<List<String>> complete(List<String> args) { |
273 if (args.length != 1) { | 266 if (args.length != 1) { |
274 return new Future.value([]); | 267 return new Future.value([]); |
275 } | 268 } |
276 // TODO - fix SourceLocation complete | 269 // TODO - fix SourceLocation complete |
277 return new Future.value(SourceLocation.complete(debugger, args[0])); | 270 return new Future.value(SourceLocation.complete(debugger, args[0])); |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
323 'Function entry breakpoints not yet implemented'); | 316 'Function entry breakpoints not yet implemented'); |
324 return null; | 317 return null; |
325 } | 318 } |
326 if (loc.col != null) { | 319 if (loc.col != null) { |
327 // TODO(turnidge): Add tokenPos clear support. | 320 // TODO(turnidge): Add tokenPos clear support. |
328 debugger.console.print( | 321 debugger.console.print( |
329 'Ignoring column: ' | 322 'Ignoring column: ' |
330 'clearing breakpoint at a specific column not yet implemented'); | 323 'clearing breakpoint at a specific column not yet implemented'); |
331 } | 324 } |
332 | 325 |
333 for (var bpt in debugger.isolate.breakpoints) { | 326 for (var bpt in debugger.isolate.breakpoints.values) { |
334 var script = bpt.script; | 327 var script = bpt.script; |
335 if (script.id == loc.script.id) { | 328 if (script.id == loc.script.id) { |
336 assert(script.loaded); | 329 assert(script.loaded); |
337 var line = script.tokenToLine(bpt.tokenPos); | 330 var line = script.tokenToLine(bpt.tokenPos); |
338 if (line == loc.line) { | 331 if (line == loc.line) { |
339 return debugger.isolate.removeBreakpoint(bpt).then((result) { | 332 return debugger.isolate.removeBreakpoint(bpt).then((result) { |
340 if (result is DartError) { | 333 if (result is DartError) { |
341 debugger.console.print( | 334 debugger.console.print( |
342 'Unable to clear breakpoint at ${loc}: ${result.message}')
; | 335 'Unable to clear breakpoint at ${loc}: ${result.message}')
; |
343 return; | 336 return; |
344 } else { | |
345 // TODO(turnidge): Add a BreakpointRemoved event to | |
346 // the service instead of printing here. | |
347 var bpId = bpt.number; | |
348 debugger.console.print('Breakpoint ${bpId} removed at ${loc}')
; | |
349 return; | |
350 } | 337 } |
351 }); | 338 }); |
352 } | 339 } |
353 } | 340 } |
354 } | 341 } |
355 debugger.console.print('No breakpoint found at ${loc}'); | 342 debugger.console.print('No breakpoint found at ${loc}'); |
356 } else { | 343 } else { |
357 debugger.console.print(loc.errorMessage); | 344 debugger.console.print(loc.errorMessage); |
358 } | 345 } |
359 }); | 346 }); |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
401 | 388 |
402 Future run(List<String> args) { | 389 Future run(List<String> args) { |
403 if (args.length < 1) { | 390 if (args.length < 1) { |
404 debugger.console.print('delete expects one or more arguments'); | 391 debugger.console.print('delete expects one or more arguments'); |
405 return new Future.value(null); | 392 return new Future.value(null); |
406 } | 393 } |
407 List toRemove = []; | 394 List toRemove = []; |
408 for (var arg in args) { | 395 for (var arg in args) { |
409 int id = int.parse(arg); | 396 int id = int.parse(arg); |
410 var bptToRemove = null; | 397 var bptToRemove = null; |
411 for (var bpt in debugger.isolate.breakpoints) { | 398 for (var bpt in debugger.isolate.breakpoints.values) { |
412 if (bpt.number == id) { | 399 if (bpt.number == id) { |
413 bptToRemove = bpt; | 400 bptToRemove = bpt; |
414 break; | 401 break; |
415 } | 402 } |
416 } | 403 } |
417 if (bptToRemove == null) { | 404 if (bptToRemove == null) { |
418 debugger.console.print("Invalid breakpoint id '${id}'"); | 405 debugger.console.print("Invalid breakpoint id '${id}'"); |
419 return new Future.value(null); | 406 return new Future.value(null); |
420 } | 407 } |
421 toRemove.add(bptToRemove); | 408 toRemove.add(bptToRemove); |
422 } | 409 } |
423 List pending = []; | 410 List pending = []; |
424 for (var bpt in toRemove) { | 411 for (var bpt in toRemove) { |
425 pending.add(debugger.isolate.removeBreakpoint(bpt).then((_) { | 412 pending.add(debugger.isolate.removeBreakpoint(bpt)); |
426 var id = bpt.number; | |
427 debugger.console.print("Removed breakpoint $id"); | |
428 })); | |
429 } | 413 } |
430 return Future.wait(pending); | 414 return Future.wait(pending); |
431 } | 415 } |
432 | 416 |
433 String helpShort = 'Remove a breakpoint by breakpoint id'; | 417 String helpShort = 'Remove a breakpoint by breakpoint id'; |
434 | 418 |
435 String helpLong = | 419 String helpLong = |
436 'Remove a breakpoint by breakpoint id.\n' | 420 'Remove a breakpoint by breakpoint id.\n' |
437 '\n' | 421 '\n' |
438 'Syntax: delete <bp-id>\n' | 422 'Syntax: delete <bp-id>\n' |
439 ' delete <bp-id> <bp-id> ...\n'; | 423 ' delete <bp-id> <bp-id> ...\n'; |
440 } | 424 } |
441 | 425 |
442 class InfoBreakpointsCommand extends DebuggerCommand { | 426 class InfoBreakpointsCommand extends DebuggerCommand { |
443 InfoBreakpointsCommand(Debugger debugger) | 427 InfoBreakpointsCommand(Debugger debugger) |
444 : super(debugger, 'breakpoints', []); | 428 : super(debugger, 'breakpoints', []); |
445 | 429 |
446 Future run(List<String> args) { | 430 Future run(List<String> args) { |
447 return debugger.isolate.reloadBreakpoints().then((_) { | 431 if (debugger.isolate.breakpoints.isEmpty) { |
448 if (debugger.isolate.breakpoints.isEmpty) { | 432 debugger.console.print('No breakpoints'); |
449 debugger.console.print('No breakpoints'); | 433 } |
| 434 List bpts = debugger.isolate.breakpoints.values.toList(); |
| 435 bpts.sort((a, b) => a.number - b.number); |
| 436 for (var bpt in bpts) { |
| 437 var bpId = bpt.number; |
| 438 var script = bpt.script; |
| 439 var tokenPos = bpt.tokenPos; |
| 440 var line = script.tokenToLine(tokenPos); |
| 441 var col = script.tokenToCol(tokenPos); |
| 442 if (!bpt.resolved) { |
| 443 debugger.console.print( |
| 444 'Future breakpoint ${bpId} at ${script.name}:${line}:${col}'); |
| 445 } else { |
| 446 debugger.console.print( |
| 447 'Breakpoint ${bpId} at ${script.name}:${line}:${col}'); |
450 } | 448 } |
451 for (var bpt in debugger.isolate.breakpoints) { | 449 } |
452 var bpId = bpt.number; | 450 return new Future.value(null); |
453 var script = bpt.script; | |
454 var tokenPos = bpt.tokenPos; | |
455 var line = script.tokenToLine(tokenPos); | |
456 var col = script.tokenToCol(tokenPos); | |
457 var extras = new StringBuffer(); | |
458 if (!bpt.resolved) { | |
459 extras.write(' unresolved'); | |
460 } | |
461 if (!bpt.enabled) { | |
462 extras.write(' disabled'); | |
463 } | |
464 debugger.console.print( | |
465 'Breakpoint ${bpId} at ${script.name}:${line}:${col}${extras}'); | |
466 } | |
467 }); | |
468 } | 451 } |
469 | 452 |
470 String helpShort = 'List all breakpoints'; | 453 String helpShort = 'List all breakpoints'; |
471 | 454 |
472 String helpLong = | 455 String helpLong = |
473 'List all breakpoints.\n' | 456 'List all breakpoints.\n' |
474 '\n' | 457 '\n' |
475 'Syntax: info breakpoints\n'; | 458 'Syntax: info breakpoints\n'; |
476 } | 459 } |
477 | 460 |
(...skipping 150 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
628 Future refreshStack() { | 611 Future refreshStack() { |
629 return _refreshStack(isolate.pauseEvent).then((_) { | 612 return _refreshStack(isolate.pauseEvent).then((_) { |
630 reportStatus(); | 613 reportStatus(); |
631 }); | 614 }); |
632 } | 615 } |
633 | 616 |
634 bool isolatePaused() { | 617 bool isolatePaused() { |
635 // TODO(turnidge): Stop relying on the isolate to track the last | 618 // TODO(turnidge): Stop relying on the isolate to track the last |
636 // pause event. Since we listen to events directly in the | 619 // pause event. Since we listen to events directly in the |
637 // debugger, this could introduce a race. | 620 // debugger, this could introduce a race. |
638 return isolate.pauseEvent != null; | 621 return (isolate.pauseEvent != null && |
| 622 isolate.pauseEvent.eventType != ServiceEvent.kResume); |
639 } | 623 } |
640 | 624 |
641 void warnOutOfDate() { | 625 void warnOutOfDate() { |
642 // Wait a bit, then tell the user that the stack may be out of date. | 626 // Wait a bit, then tell the user that the stack may be out of date. |
643 new Timer(const Duration(seconds:2), () { | 627 new Timer(const Duration(seconds:2), () { |
644 if (!isolatePaused()) { | 628 if (!isolatePaused()) { |
645 stackElement.isSampled = true; | 629 stackElement.isSampled = true; |
646 } | 630 } |
647 }); | 631 }); |
648 } | 632 } |
(...skipping 13 matching lines...) Expand all Loading... |
662 } else if (_isolate.running) { | 646 } else if (_isolate.running) { |
663 console.print("Isolate is running (type 'pause' to interrupt)"); | 647 console.print("Isolate is running (type 'pause' to interrupt)"); |
664 } else if (_isolate.pauseEvent != null) { | 648 } else if (_isolate.pauseEvent != null) { |
665 _reportPause(_isolate.pauseEvent); | 649 _reportPause(_isolate.pauseEvent); |
666 } else { | 650 } else { |
667 console.print('Isolate is in unknown state'); | 651 console.print('Isolate is in unknown state'); |
668 } | 652 } |
669 } | 653 } |
670 | 654 |
671 void _reportPause(ServiceEvent event) { | 655 void _reportPause(ServiceEvent event) { |
672 if (event.eventType == 'IsolateCreated') { | 656 if (event.eventType == ServiceEvent.kPauseStart) { |
673 console.print( | 657 console.print( |
674 "Paused at isolate start (type 'continue' to start the isolate')"); | 658 "Paused at isolate start (type 'continue' to start the isolate')"); |
675 } else if (event.eventType == 'IsolateShutdown') { | 659 } else if (event.eventType == ServiceEvent.kPauseExit) { |
676 console.print( | 660 console.print( |
677 "Paused at isolate exit (type 'continue' to exit the isolate')"); | 661 "Paused at isolate exit (type 'continue' to exit the isolate')"); |
678 } | 662 } |
679 if (stack['frames'].length > 0) { | 663 if (stack['frames'].length > 0) { |
680 var frame = stack['frames'][0]; | 664 var frame = stack['frames'][0]; |
681 var script = frame['script']; | 665 var script = frame['script']; |
682 script.load().then((_) { | 666 script.load().then((_) { |
683 var line = script.tokenToLine(frame['tokenPos']); | 667 var line = script.tokenToLine(frame['tokenPos']); |
684 var col = script.tokenToCol(frame['tokenPos']); | 668 var col = script.tokenToCol(frame['tokenPos']); |
685 if (event.breakpoint != null) { | 669 if (event.breakpoint != null) { |
686 var bpId = event.breakpoint.number; | 670 var bpId = event.breakpoint.number; |
687 console.print('Breakpoint ${bpId} at ${script.name}:${line}:${col}'); | 671 console.print('Breakpoint ${bpId} at ${script.name}:${line}:${col}'); |
688 } else if (event.exception != null) { | 672 } else if (event.exception != null) { |
689 // TODO(turnidge): Test this. | 673 // TODO(turnidge): Test this. |
690 console.print( | 674 console.print( |
691 'Exception ${event.exception} at ${script.name}:${line}:${col}'); | 675 'Exception ${event.exception} at ${script.name}:${line}:${col}'); |
692 } else { | 676 } else { |
693 console.print('Paused at ${script.name}:${line}:${col}'); | 677 console.print('Paused at ${script.name}:${line}:${col}'); |
694 } | 678 } |
695 }); | 679 }); |
696 } | 680 } |
697 } | 681 } |
698 | 682 |
699 Future _reportBreakpointAdded(Breakpoint bpt) { | 683 Future _reportBreakpointEvent(ServiceEvent event) { |
| 684 var bpt = event.breakpoint; |
| 685 var verb = null; |
| 686 switch (event.eventType) { |
| 687 case ServiceEvent.kBreakpointAdded: |
| 688 verb = 'added'; |
| 689 break; |
| 690 case ServiceEvent.kBreakpointResolved: |
| 691 verb = 'resolved'; |
| 692 break; |
| 693 case ServiceEvent.kBreakpointRemoved: |
| 694 verb = 'removed'; |
| 695 break; |
| 696 default: |
| 697 break; |
| 698 } |
700 var script = bpt.script; | 699 var script = bpt.script; |
701 return script.load().then((_) { | 700 return script.load().then((_) { |
702 var bpId = bpt.number; | 701 var bpId = bpt.number; |
703 var tokenPos = bpt.tokenPos; | 702 var tokenPos = bpt.tokenPos; |
704 var line = script.tokenToLine(tokenPos); | 703 var line = script.tokenToLine(tokenPos); |
705 var col = script.tokenToCol(tokenPos); | 704 var col = script.tokenToCol(tokenPos); |
706 if (bpt.resolved) { | 705 if (bpt.resolved) { |
707 // TODO(turnidge): If this was a future breakpoint before, we | |
708 // should change the message to say that the breakpoint was 'resolved', | |
709 // rather than 'added'. | |
710 console.print( | 706 console.print( |
711 'Breakpoint ${bpId} added at ${script.name}:${line}:${col}'); | 707 'Breakpoint ${bpId} ${verb} at ${script.name}:${line}:${col}'); |
712 } else { | 708 } else { |
713 console.print( | 709 console.print( |
714 'Future breakpoint ${bpId} added at ${script.name}:${line}:${col}'); | 710 'Future breakpoint ${bpId} ${verb} at ${script.name}:${line}:${col}'
); |
715 } | 711 } |
716 }); | 712 }); |
717 } | 713 } |
718 | 714 |
719 void _onEvent(ServiceEvent event) { | 715 void _onEvent(ServiceEvent event) { |
720 if (event.owner != isolate) { | 716 if (event.owner != isolate) { |
721 return; | 717 return; |
722 } | 718 } |
723 switch(event.eventType) { | 719 switch(event.eventType) { |
724 case 'IsolateShutdown': | 720 case ServiceEvent.kIsolateExit: |
725 console.print('Isolate shutdown'); | 721 console.print('Isolate shutdown'); |
726 isolate = null; | 722 isolate = null; |
727 break; | 723 break; |
728 | 724 |
729 case 'BreakpointReached': | 725 case ServiceEvent.kPauseStart: |
730 case 'IsolateInterrupted': | 726 case ServiceEvent.kPauseExit: |
731 case 'ExceptionThrown': | 727 case ServiceEvent.kPauseBreakpoint: |
| 728 case ServiceEvent.kPauseInterrupted: |
| 729 case ServiceEvent.kPauseException: |
732 _refreshStack(event).then((_) { | 730 _refreshStack(event).then((_) { |
733 _reportPause(event); | 731 _reportPause(event); |
734 }); | 732 }); |
735 break; | 733 break; |
736 | 734 |
737 case 'IsolateResumed': | 735 case ServiceEvent.kResume: |
738 console.print('Continuing...'); | 736 console.print('Continuing...'); |
739 break; | 737 break; |
740 | 738 |
741 case 'BreakpointResolved': | 739 case ServiceEvent.kBreakpointAdded: |
742 _reportBreakpointAdded(event.breakpoint); | 740 case ServiceEvent.kBreakpointResolved: |
| 741 case ServiceEvent.kBreakpointRemoved: |
| 742 _reportBreakpointEvent(event); |
743 break; | 743 break; |
744 | 744 |
745 case '_Graph': | 745 case ServiceEvent.kIsolateStart: |
746 case 'IsolateCreated': | 746 case ServiceEvent.kGraph: |
747 case 'GC': | 747 case ServiceEvent.kGC: |
748 // Ignore these events for now. | 748 // Ignore these events for now. |
749 break; | 749 break; |
750 | 750 |
751 default: | 751 default: |
752 console.print('Unrecognized event: $event'); | 752 console.print('Unrecognized event: $event'); |
753 break; | 753 break; |
754 } | 754 } |
755 } | 755 } |
756 | 756 |
757 static String _commonPrefix(String a, String b) { | 757 static String _commonPrefix(String a, String b) { |
(...skipping 346 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1104 default: | 1104 default: |
1105 busy = false; | 1105 busy = false; |
1106 break; | 1106 break; |
1107 } | 1107 } |
1108 }); | 1108 }); |
1109 } | 1109 } |
1110 | 1110 |
1111 DebuggerInputElement.created() : super.created(); | 1111 DebuggerInputElement.created() : super.created(); |
1112 } | 1112 } |
1113 | 1113 |
OLD | NEW |