| 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 'dart:math'; | 9 import 'dart:math'; |
| 10 import 'observatory_element.dart'; | 10 import 'observatory_element.dart'; |
| 11 import 'package:observatory/event.dart'; |
| 12 import 'package:observatory/models.dart' as M; |
| 11 import 'package:observatory/app.dart'; | 13 import 'package:observatory/app.dart'; |
| 12 import 'package:observatory/cli.dart'; | 14 import 'package:observatory/cli.dart'; |
| 13 import 'package:observatory/debugger.dart'; | 15 import 'package:observatory/debugger.dart'; |
| 14 import 'package:observatory/service.dart'; | 16 import 'package:observatory/service.dart'; |
| 15 import 'package:logging/logging.dart'; | 17 import 'package:logging/logging.dart'; |
| 16 import 'package:polymer/polymer.dart'; | 18 import 'package:polymer/polymer.dart'; |
| 17 | 19 |
| 18 // TODO(turnidge): Move Debugger, DebuggerCommand to debugger library. | 20 // TODO(turnidge): Move Debugger, DebuggerCommand to debugger library. |
| 19 abstract class DebuggerCommand extends Command { | 21 abstract class DebuggerCommand extends Command { |
| 20 ObservatoryDebugger debugger; | 22 ObservatoryDebugger debugger; |
| (...skipping 460 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 481 ' log ALL ' | 483 ' log ALL ' |
| 482 '# Display all log messages.\n'; | 484 '# Display all log messages.\n'; |
| 483 } | 485 } |
| 484 | 486 |
| 485 class FinishCommand extends DebuggerCommand { | 487 class FinishCommand extends DebuggerCommand { |
| 486 FinishCommand(Debugger debugger) : super(debugger, 'finish', []); | 488 FinishCommand(Debugger debugger) : super(debugger, 'finish', []); |
| 487 | 489 |
| 488 Future run(List<String> args) { | 490 Future run(List<String> args) { |
| 489 if (debugger.isolatePaused()) { | 491 if (debugger.isolatePaused()) { |
| 490 var event = debugger.isolate.pauseEvent; | 492 var event = debugger.isolate.pauseEvent; |
| 491 if (event.kind == ServiceEvent.kPauseStart) { | 493 if (event is M.PauseStartEvent) { |
| 492 debugger.console.print( | 494 debugger.console.print( |
| 493 "Type 'continue' [F7] or 'step' [F10] to start the isolate"); | 495 "Type 'continue' [F7] or 'step' [F10] to start the isolate"); |
| 494 return new Future.value(null); | 496 return new Future.value(null); |
| 495 } | 497 } |
| 496 if (event.kind == ServiceEvent.kPauseExit) { | 498 if (event is M.PauseExitEvent) { |
| 497 debugger.console.print("Type 'continue' [F7] to exit the isolate"); | 499 debugger.console.print("Type 'continue' [F7] to exit the isolate"); |
| 498 return new Future.value(null); | 500 return new Future.value(null); |
| 499 } | 501 } |
| 500 return debugger.isolate.stepOut(); | 502 return debugger.isolate.stepOut(); |
| 501 } else { | 503 } else { |
| 502 debugger.console.print('The program is already running'); | 504 debugger.console.print('The program is already running'); |
| 503 return new Future.value(null); | 505 return new Future.value(null); |
| 504 } | 506 } |
| 505 } | 507 } |
| 506 | 508 |
| (...skipping 954 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1461 console.printRed("Unexpected error in refreshStack: $e\n$st"); | 1463 console.printRed("Unexpected error in refreshStack: $e\n$st"); |
| 1462 } | 1464 } |
| 1463 } | 1465 } |
| 1464 | 1466 |
| 1465 bool isolatePaused() { | 1467 bool isolatePaused() { |
| 1466 // TODO(turnidge): Stop relying on the isolate to track the last | 1468 // TODO(turnidge): Stop relying on the isolate to track the last |
| 1467 // pause event. Since we listen to events directly in the | 1469 // pause event. Since we listen to events directly in the |
| 1468 // debugger, this could introduce a race. | 1470 // debugger, this could introduce a race. |
| 1469 return (isolate != null && | 1471 return (isolate != null && |
| 1470 isolate.pauseEvent != null && | 1472 isolate.pauseEvent != null && |
| 1471 isolate.pauseEvent.kind != ServiceEvent.kResume); | 1473 isolate.pauseEvent is M.ResumeEvent); |
| 1472 } | 1474 } |
| 1473 | 1475 |
| 1474 void warnOutOfDate() { | 1476 void warnOutOfDate() { |
| 1475 // Wait a bit, then tell the user that the stack may be out of date. | 1477 // Wait a bit, then tell the user that the stack may be out of date. |
| 1476 new Timer(const Duration(seconds:2), () { | 1478 new Timer(const Duration(seconds:2), () { |
| 1477 if (!isolatePaused()) { | 1479 if (!isolatePaused()) { |
| 1478 stackElement.isSampled = true; | 1480 stackElement.isSampled = true; |
| 1479 } | 1481 } |
| 1480 }); | 1482 }); |
| 1481 } | 1483 } |
| 1482 | 1484 |
| 1483 Future<ServiceMap> _refreshStack(ServiceEvent pauseEvent) { | 1485 Future<ServiceMap> _refreshStack(M.DebugEvent pauseEvent) { |
| 1484 return isolate.getStack().then((result) { | 1486 return isolate.getStack().then((result) { |
| 1485 if (result.isSentinel) { | 1487 if (result.isSentinel) { |
| 1486 // The isolate has gone away. The IsolateExit event will | 1488 // The isolate has gone away. The IsolateExit event will |
| 1487 // clear the isolate for the debugger page. | 1489 // clear the isolate for the debugger page. |
| 1488 return; | 1490 return; |
| 1489 } | 1491 } |
| 1490 stack = result; | 1492 stack = result; |
| 1491 stackElement.updateStack(stack, pauseEvent); | 1493 stackElement.updateStack(stack, pauseEvent); |
| 1492 if (stack['frames'].length > 0) { | 1494 if (stack['frames'].length > 0) { |
| 1493 currentFrame = 0; | 1495 currentFrame = 0; |
| (...skipping 13 matching lines...) Expand all Loading... |
| 1507 } else if (_isolate.running) { | 1509 } else if (_isolate.running) { |
| 1508 console.print("Isolate is running (type 'pause' to interrupt)"); | 1510 console.print("Isolate is running (type 'pause' to interrupt)"); |
| 1509 } else if (_isolate.pauseEvent != null) { | 1511 } else if (_isolate.pauseEvent != null) { |
| 1510 _reportPause(_isolate.pauseEvent); | 1512 _reportPause(_isolate.pauseEvent); |
| 1511 } else { | 1513 } else { |
| 1512 console.print('Isolate is in unknown state'); | 1514 console.print('Isolate is in unknown state'); |
| 1513 } | 1515 } |
| 1514 warnOutOfDate(); | 1516 warnOutOfDate(); |
| 1515 } | 1517 } |
| 1516 | 1518 |
| 1517 void _reportIsolateError(Isolate isolate, String eventKind) { | 1519 void _reportIsolateError(Isolate isolate, M.DebugEvent event) { |
| 1518 if (isolate == null) { | 1520 if (isolate == null) { |
| 1519 return; | 1521 return; |
| 1520 } | 1522 } |
| 1521 DartError error = isolate.error; | 1523 DartError error = isolate.error; |
| 1522 if (error == null) { | 1524 if (error == null) { |
| 1523 return; | 1525 return; |
| 1524 } | 1526 } |
| 1525 console.newline(); | 1527 console.newline(); |
| 1526 if (eventKind == ServiceEvent.kPauseException) { | 1528 if (event is M.PauseExceptionEvent) { |
| 1527 console.printBold('Isolate will exit due to an unhandled exception:'); | 1529 console.printBold('Isolate will exit due to an unhandled exception:'); |
| 1528 } else { | 1530 } else { |
| 1529 console.printBold('Isolate has exited due to an unhandled exception:'); | 1531 console.printBold('Isolate has exited due to an unhandled exception:'); |
| 1530 } | 1532 } |
| 1531 console.print(error.message); | 1533 console.print(error.message); |
| 1532 console.newline(); | 1534 console.newline(); |
| 1533 if (eventKind == ServiceEvent.kPauseException && | 1535 if (event is M.PauseExceptionEvent && |
| 1534 (error.exception.isStackOverflowError || | 1536 (error.exception.isStackOverflowError || |
| 1535 error.exception.isOutOfMemoryError)) { | 1537 error.exception.isOutOfMemoryError)) { |
| 1536 console.printBold( | 1538 console.printBold( |
| 1537 'When an unhandled stack overflow or OOM exception occurs, the VM ' | 1539 'When an unhandled stack overflow or OOM exception occurs, the VM ' |
| 1538 'has run out of memory and cannot keep the stack alive while ' | 1540 'has run out of memory and cannot keep the stack alive while ' |
| 1539 'paused.'); | 1541 'paused.'); |
| 1540 } else { | 1542 } else { |
| 1541 console.printBold("Type 'set break-on-exception Unhandled' to pause the" | 1543 console.printBold("Type 'set break-on-exception Unhandled' to pause the" |
| 1542 " isolate when an unhandled exception occurs."); | 1544 " isolate when an unhandled exception occurs."); |
| 1543 console.printBold("You can make this the default by running with " | 1545 console.printBold("You can make this the default by running with " |
| 1544 "--pause-isolates-on-unhandled-exceptions"); | 1546 "--pause-isolates-on-unhandled-exceptions"); |
| 1545 } | 1547 } |
| 1546 } | 1548 } |
| 1547 | 1549 |
| 1548 void _reportPause(ServiceEvent event) { | 1550 void _reportPause(M.DebugEvent event) { |
| 1549 if (event.kind == ServiceEvent.kNone) { | 1551 if (event is M.NoneEvent) { |
| 1550 console.print("Paused until embedder makes the isolate runnable."); | 1552 console.print("Paused until embedder makes the isolate runnable."); |
| 1551 } else if (event.kind == ServiceEvent.kPauseStart) { | 1553 } else if (event is M.PauseStartEvent) { |
| 1552 console.print( | 1554 console.print( |
| 1553 "Paused at isolate start " | 1555 "Paused at isolate start " |
| 1554 "(type 'continue' [F7] or 'step' [F10] to start the isolate')"); | 1556 "(type 'continue' [F7] or 'step' [F10] to start the isolate')"); |
| 1555 } else if (event.kind == ServiceEvent.kPauseExit) { | 1557 } else if (event is M.PauseExitEvent) { |
| 1556 console.print( | 1558 console.print( |
| 1557 "Paused at isolate exit " | 1559 "Paused at isolate exit " |
| 1558 "(type 'continue' or [F7] to exit the isolate')"); | 1560 "(type 'continue' or [F7] to exit the isolate')"); |
| 1559 _reportIsolateError(isolate, event.kind); | 1561 _reportIsolateError(isolate, event); |
| 1560 } else if (event.kind == ServiceEvent.kPauseException) { | 1562 } else if (event is M.PauseExceptionEvent) { |
| 1561 console.print( | 1563 console.print( |
| 1562 "Paused at an unhandled exception " | 1564 "Paused at an unhandled exception " |
| 1563 "(type 'continue' or [F7] to exit the isolate')"); | 1565 "(type 'continue' or [F7] to exit the isolate')"); |
| 1564 _reportIsolateError(isolate, event.kind); | 1566 _reportIsolateError(isolate, event); |
| 1565 } else if (stack['frames'].length > 0) { | 1567 } else if (stack['frames'].length > 0) { |
| 1566 Frame frame = stack['frames'][0]; | 1568 Frame frame = stack['frames'][0]; |
| 1567 var script = frame.location.script; | 1569 var script = frame.location.script; |
| 1568 script.load().then((_) { | 1570 script.load().then((_) { |
| 1569 var line = script.tokenToLine(frame.location.tokenPos); | 1571 var line = script.tokenToLine(frame.location.tokenPos); |
| 1570 var col = script.tokenToCol(frame.location.tokenPos); | 1572 var col = script.tokenToCol(frame.location.tokenPos); |
| 1571 if (event.breakpoint != null) { | 1573 if ((event is M.PauseBreakpointEvent) && |
| 1572 var bpId = event.breakpoint.number; | 1574 (event.breakpoint != null)) { |
| 1573 console.print('Paused at breakpoint ${bpId} at ' | 1575 var bpId = event.breakpoint.number; |
| 1574 '${script.name}:${line}:${col}'); | 1576 console.print('Paused at breakpoint ${bpId} at ' |
| 1575 } else if (event.exception != null) { | 1577 '${script.name}:${line}:${col}'); |
| 1578 } else if ((event is M.PauseExceptionEvent) && |
| 1579 (event.exception != null)) { |
| 1576 console.print('Paused due to exception at ' | 1580 console.print('Paused due to exception at ' |
| 1577 '${script.name}:${line}:${col}'); | 1581 '${script.name}:${line}:${col}'); |
| 1578 // This seems to be missing if we are paused-at-exception after | 1582 // This seems to be missing if we are paused-at-exception after |
| 1579 // paused-at-isolate-exit. Maybe we shutdown part of the debugger too | 1583 // paused-at-isolate-exit. Maybe we shutdown part of the debugger too |
| 1580 // soon? | 1584 // soon? |
| 1581 console.printRef(event.exception); | 1585 console.printRef(event.exception); |
| 1582 } else { | 1586 } else { |
| 1583 console.print('Paused at ${script.name}:${line}:${col}'); | 1587 console.print('Paused at ${script.name}:${line}:${col}'); |
| 1584 } | 1588 } |
| 1585 }); | 1589 }); |
| (...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1680 console.print('Isolate reloaded.'); | 1684 console.print('Isolate reloaded.'); |
| 1681 } | 1685 } |
| 1682 break; | 1686 break; |
| 1683 | 1687 |
| 1684 case ServiceEvent.kPauseStart: | 1688 case ServiceEvent.kPauseStart: |
| 1685 case ServiceEvent.kPauseExit: | 1689 case ServiceEvent.kPauseExit: |
| 1686 case ServiceEvent.kPauseBreakpoint: | 1690 case ServiceEvent.kPauseBreakpoint: |
| 1687 case ServiceEvent.kPauseInterrupted: | 1691 case ServiceEvent.kPauseInterrupted: |
| 1688 case ServiceEvent.kPauseException: | 1692 case ServiceEvent.kPauseException: |
| 1689 if (event.owner == isolate) { | 1693 if (event.owner == isolate) { |
| 1690 _refreshStack(event).then((_) async { | 1694 var e = createEventFromServiceEvent(event); |
| 1695 _refreshStack(e).then((_) async { |
| 1691 flushStdio(); | 1696 flushStdio(); |
| 1692 if (isolate != null) { | 1697 if (isolate != null) { |
| 1693 await isolate.reload(); | 1698 await isolate.reload(); |
| 1694 } | 1699 } |
| 1695 _reportPause(event); | 1700 _reportPause(e); |
| 1696 }); | 1701 }); |
| 1697 } | 1702 } |
| 1698 break; | 1703 break; |
| 1699 | 1704 |
| 1700 case ServiceEvent.kResume: | 1705 case ServiceEvent.kResume: |
| 1701 if (event.owner == isolate) { | 1706 if (event.owner == isolate) { |
| 1702 flushStdio(); | 1707 flushStdio(); |
| 1703 console.print('Continuing...'); | 1708 console.print('Continuing...'); |
| 1704 } | 1709 } |
| 1705 break; | 1710 break; |
| (...skipping 173 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1879 return isolate.stepOverAsyncSuspension(); | 1884 return isolate.stepOverAsyncSuspension(); |
| 1880 } | 1885 } |
| 1881 } else { | 1886 } else { |
| 1882 console.print('The program is already running'); | 1887 console.print('The program is already running'); |
| 1883 } | 1888 } |
| 1884 } | 1889 } |
| 1885 | 1890 |
| 1886 Future syncNext() async { | 1891 Future syncNext() async { |
| 1887 if (isolatePaused()) { | 1892 if (isolatePaused()) { |
| 1888 var event = isolate.pauseEvent; | 1893 var event = isolate.pauseEvent; |
| 1889 if (event.kind == ServiceEvent.kPauseStart) { | 1894 if (event is M.PauseStartEvent) { |
| 1890 console.print("Type 'continue' [F7] or 'step' [F10] to start the isolate
"); | 1895 console.print("Type 'continue' [F7] or 'step' [F10] to start the isolate
"); |
| 1891 return null; | 1896 return null; |
| 1892 } | 1897 } |
| 1893 if (event.kind == ServiceEvent.kPauseExit) { | 1898 if (event is M.PauseExitEvent) { |
| 1894 console.print("Type 'continue' [F7] to exit the isolate"); | 1899 console.print("Type 'continue' [F7] to exit the isolate"); |
| 1895 return null; | 1900 return null; |
| 1896 } | 1901 } |
| 1897 return isolate.stepOver(); | 1902 return isolate.stepOver(); |
| 1898 } else { | 1903 } else { |
| 1899 console.print('The program is already running'); | 1904 console.print('The program is already running'); |
| 1900 return null; | 1905 return null; |
| 1901 } | 1906 } |
| 1902 } | 1907 } |
| 1903 | 1908 |
| 1904 Future step() { | 1909 Future step() { |
| 1905 if (isolatePaused()) { | 1910 if (isolatePaused()) { |
| 1906 var event = isolate.pauseEvent; | 1911 var event = isolate.pauseEvent; |
| 1907 if (event.kind == ServiceEvent.kPauseExit) { | 1912 if (event is M.PauseExitEvent) { |
| 1908 console.print("Type 'continue' [F7] to exit the isolate"); | 1913 console.print("Type 'continue' [F7] to exit the isolate"); |
| 1909 return new Future.value(null); | 1914 return new Future.value(null); |
| 1910 } | 1915 } |
| 1911 return isolate.stepInto(); | 1916 return isolate.stepInto(); |
| 1912 } else { | 1917 } else { |
| 1913 console.print('The program is already running'); | 1918 console.print('The program is already running'); |
| 1914 return new Future.value(null); | 1919 return new Future.value(null); |
| 1915 } | 1920 } |
| 1916 } | 1921 } |
| 1917 } | 1922 } |
| (...skipping 234 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2152 if (messageElements.isNotEmpty) { | 2157 if (messageElements.isNotEmpty) { |
| 2153 // Update old messages. | 2158 // Update old messages. |
| 2154 for (int i = 0; i < newStartingIndex; i++) { | 2159 for (int i = 0; i < newStartingIndex; i++) { |
| 2155 messageElements[i].children[0].updateMessage(newMessages[i]); | 2160 messageElements[i].children[0].updateMessage(newMessages[i]); |
| 2156 } | 2161 } |
| 2157 } | 2162 } |
| 2158 | 2163 |
| 2159 hasMessages = messageElements.isNotEmpty; | 2164 hasMessages = messageElements.isNotEmpty; |
| 2160 } | 2165 } |
| 2161 | 2166 |
| 2162 void updateStack(ServiceMap newStack, ServiceEvent pauseEvent) { | 2167 void updateStack(ServiceMap newStack, M.DebugEvent pauseEvent) { |
| 2163 updateStackFrames(newStack); | 2168 updateStackFrames(newStack); |
| 2164 updateStackMessages(newStack); | 2169 updateStackMessages(newStack); |
| 2165 isSampled = pauseEvent == null; | 2170 isSampled = pauseEvent == null; |
| 2166 } | 2171 } |
| 2167 | 2172 |
| 2168 void setCurrentFrame(int value) { | 2173 void setCurrentFrame(int value) { |
| 2169 currentFrame = value; | 2174 currentFrame = value; |
| 2170 List frameElements = $['frameList'].children; | 2175 List frameElements = $['frameList'].children; |
| 2171 for (var frameElement in frameElements) { | 2176 for (var frameElement in frameElements) { |
| 2172 var dbgFrameElement = frameElement.children[0]; | 2177 var dbgFrameElement = frameElement.children[0]; |
| (...skipping 532 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2705 } | 2710 } |
| 2706 }); | 2711 }); |
| 2707 } | 2712 } |
| 2708 | 2713 |
| 2709 void focus() { | 2714 void focus() { |
| 2710 $['textBox'].focus(); | 2715 $['textBox'].focus(); |
| 2711 } | 2716 } |
| 2712 | 2717 |
| 2713 DebuggerInputElement.created() : super.created(); | 2718 DebuggerInputElement.created() : super.created(); |
| 2714 } | 2719 } |
| OLD | NEW |