Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(753)

Side by Side Diff: runtime/observatory/lib/src/elements/debugger.dart

Issue 1371193005: VM restart + shutdown fixes (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: more code review Created 5 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « runtime/include/dart_api.h ('k') | runtime/observatory/lib/src/elements/debugger.html » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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/app.dart'; 10 import 'package:observatory/app.dart';
(...skipping 1069 matching lines...) Expand 10 before | Expand all | Expand 10 after
1080 } 1080 }
1081 1081
1082 String helpShort = 'Refresh debugging information of various sorts'; 1082 String helpShort = 'Refresh debugging information of various sorts';
1083 1083
1084 String helpLong = 1084 String helpLong =
1085 'Refresh debugging information of various sorts.\n' 1085 'Refresh debugging information of various sorts.\n'
1086 '\n' 1086 '\n'
1087 'Syntax: refresh <subcommand>\n'; 1087 'Syntax: refresh <subcommand>\n';
1088 } 1088 }
1089 1089
1090 class VmRestartCommand extends DebuggerCommand {
1091 VmRestartCommand(Debugger debugger) : super(debugger, 'restart', []);
1092
1093 Future handleModalInput(String line) async {
1094 if (line == 'yes') {
1095 debugger.console.printRed('Restarting VM...');
1096 await debugger.vm.restart();
1097 debugger.input.exitMode();
1098 } else if (line == 'no') {
1099 debugger.console.printRed('VM restart canceled.');
1100 debugger.input.exitMode();
1101 } else {
1102 debugger.console.printRed("Please type 'yes' or 'no'");
1103 }
1104 }
1105
1106 Future run(List<String> args) async {
1107 debugger.input.enterMode('Restart vm? (yes/no)', handleModalInput);
1108 }
1109
1110 String helpShort = 'Restart a Dart virtual machine';
1111
1112 String helpLong =
1113 'Restart a Dart virtual machine.\n'
1114 '\n'
1115 'Syntax: vm restart\n';
1116 }
1117
1118 class VmCommand extends DebuggerCommand {
1119 VmCommand(Debugger debugger) : super(debugger, 'vm', [
1120 new VmRestartCommand(debugger),
1121 ]);
1122
1123 Future run(List<String> args) async {
1124 debugger.console.print("'vm' expects a subcommand (see 'help vm')");
1125 }
1126
1127 String helpShort = 'Manage a Dart virtual machine';
1128
1129 String helpLong =
1130 'Manage a Dart virtual machine.\n'
1131 '\n'
1132 'Syntax: vm <subcommand>\n';
1133 }
1134
1090 class _ConsoleStreamPrinter { 1135 class _ConsoleStreamPrinter {
1091 ObservatoryDebugger _debugger; 1136 ObservatoryDebugger _debugger;
1092 1137
1093 _ConsoleStreamPrinter(this._debugger); 1138 _ConsoleStreamPrinter(this._debugger);
1094 Level _minimumLogLevel = Level.OFF; 1139 Level _minimumLogLevel = Level.OFF;
1095 String _savedStream; 1140 String _savedStream;
1096 String _savedIsolate; 1141 String _savedIsolate;
1097 String _savedLine; 1142 String _savedLine;
1098 List<String> _buffer = []; 1143 List<String> _buffer = [];
1099 1144
(...skipping 127 matching lines...) Expand 10 before | Expand all | Expand 10 after
1227 new IsolateCommand(this), 1272 new IsolateCommand(this),
1228 new LogCommand(this), 1273 new LogCommand(this),
1229 new PauseCommand(this), 1274 new PauseCommand(this),
1230 new PrintCommand(this), 1275 new PrintCommand(this),
1231 new RefreshCommand(this), 1276 new RefreshCommand(this),
1232 new SetCommand(this), 1277 new SetCommand(this),
1233 new SmartNextCommand(this), 1278 new SmartNextCommand(this),
1234 new StepCommand(this), 1279 new StepCommand(this),
1235 new SyncNextCommand(this), 1280 new SyncNextCommand(this),
1236 new UpCommand(this), 1281 new UpCommand(this),
1282 new VmCommand(this),
1237 ]); 1283 ]);
1238 _consolePrinter = new _ConsoleStreamPrinter(this); 1284 _consolePrinter = new _ConsoleStreamPrinter(this);
1239 } 1285 }
1240 1286
1241 void _loadSettings() { 1287 void _loadSettings() {
1242 _upIsDown = settings.get('up-is-down'); 1288 _upIsDown = settings.get('up-is-down');
1243 } 1289 }
1244 1290
1245 VM get vm => page.app.vm; 1291 VM get vm => page.app.vm;
1246 1292
1247 void updateIsolate(Isolate iso) { 1293 void updateIsolate(Isolate iso) {
1248 _isolate = iso; 1294 _isolate = iso;
1249 if (_isolate != null) { 1295 if (_isolate != null) {
1250 if ((breakOnException != iso.exceptionsPauseInfo) && 1296 if ((breakOnException != iso.exceptionsPauseInfo) &&
1251 (iso.exceptionsPauseInfo != null)) { 1297 (iso.exceptionsPauseInfo != null)) {
1252 breakOnException = iso.exceptionsPauseInfo; 1298 breakOnException = iso.exceptionsPauseInfo;
1253 console.print("Now pausing for exceptions: $breakOnException"); 1299 console.print("Now pausing for exceptions: $breakOnException");
1254 } 1300 }
1255 1301
1256 _isolate.reload().then((response) { 1302 _isolate.reload().then((response) {
1303 if (response.isSentinel) {
1304 // The isolate has gone away. The IsolateExit event will
1305 // clear the isolate for the debugger page.
1306 return;
1307 }
1257 // TODO(turnidge): Currently the debugger relies on all libs 1308 // TODO(turnidge): Currently the debugger relies on all libs
1258 // being loaded. Fix this. 1309 // being loaded. Fix this.
1259 var pending = []; 1310 var pending = [];
1260 for (var lib in _isolate.libraries) { 1311 for (var lib in response.libraries) {
1261 if (!lib.loaded) { 1312 if (!lib.loaded) {
1262 pending.add(lib.load()); 1313 pending.add(lib.load());
1263 } 1314 }
1264 } 1315 }
1265 Future.wait(pending).then((_) { 1316 Future.wait(pending).then((_) {
1266 _refreshStack(isolate.pauseEvent).then((_) { 1317 refreshStack();
1267 reportStatus(); 1318 }).catchError((e) {
1268 }); 1319 print("UNEXPECTED ERROR $e");
1269 }).catchError((_) { 1320 reportStatus();
1270 // Error loading libraries, try and display stack.
1271 _refreshStack(isolate.pauseEvent).then((_) {
1272 reportStatus();
1273 });
1274 }); 1321 });
1275 }); 1322 });
1276 } else { 1323 } else {
1277 reportStatus(); 1324 reportStatus();
1278 } 1325 }
1279 } 1326 }
1280 1327
1281 set isolate(Isolate iso) { 1328 set isolate(Isolate iso) {
1282 // Setting the page's isolate will trigger updateIsolate to be called. 1329 // Setting the page's isolate will trigger updateIsolate to be called.
1283 // 1330 //
1284 // TODO(turnidge): Rework ownership of the ObservatoryDebugger in another 1331 // TODO(turnidge): Rework ownership of the ObservatoryDebugger in another
1285 // change. 1332 // change.
1286 page.isolate = iso; 1333 page.isolate = iso;
1287 } 1334 }
1288 Isolate get isolate => _isolate; 1335 Isolate get isolate => _isolate;
1289 Isolate _isolate; 1336 Isolate _isolate;
1290 1337
1291 void init() { 1338 void init() {
1292 console.newline(); 1339 console.newline();
1293 console.printBold("Type 'h' for help"); 1340 console.printBold("Type 'h' for help");
1294 // Wait a bit and if polymer still hasn't set up the isolate, 1341 // Wait a bit and if polymer still hasn't set up the isolate,
1295 // report this to the user. 1342 // report this to the user.
1296 new Timer(const Duration(seconds:1), () { 1343 new Timer(const Duration(seconds:1), () {
1297 if (isolate == null) { 1344 if (isolate == null) {
1298 reportStatus(); 1345 reportStatus();
1299 } 1346 }
1300 }); 1347 });
1301 } 1348 }
1302 1349
1303 Future refreshStack() { 1350 Future refreshStack() async {
1304 return _refreshStack(isolate.pauseEvent).then((_) { 1351 try {
1352 if (_isolate != null) {
1353 await _refreshStack(_isolate.pauseEvent);
1354 }
1355 flushStdio();
1305 reportStatus(); 1356 reportStatus();
1306 }); 1357 } catch (e, st) {
1358 console.printRed("Unexpected error in refreshStack: $e\n$st");
1359 }
1307 } 1360 }
1308 1361
1309 bool isolatePaused() { 1362 bool isolatePaused() {
1310 // TODO(turnidge): Stop relying on the isolate to track the last 1363 // TODO(turnidge): Stop relying on the isolate to track the last
1311 // pause event. Since we listen to events directly in the 1364 // pause event. Since we listen to events directly in the
1312 // debugger, this could introduce a race. 1365 // debugger, this could introduce a race.
1313 return (isolate != null && 1366 return (isolate != null &&
1314 isolate.pauseEvent != null && 1367 isolate.pauseEvent != null &&
1315 isolate.pauseEvent.kind != ServiceEvent.kResume); 1368 isolate.pauseEvent.kind != ServiceEvent.kResume);
1316 } 1369 }
1317 1370
1318 void warnOutOfDate() { 1371 void warnOutOfDate() {
1319 // Wait a bit, then tell the user that the stack may be out of date. 1372 // Wait a bit, then tell the user that the stack may be out of date.
1320 new Timer(const Duration(seconds:2), () { 1373 new Timer(const Duration(seconds:2), () {
1321 if (!isolatePaused()) { 1374 if (!isolatePaused()) {
1322 stackElement.isSampled = true; 1375 stackElement.isSampled = true;
1323 } 1376 }
1324 }); 1377 });
1325 } 1378 }
1326 1379
1327 Future<ServiceMap> _refreshStack(ServiceEvent pauseEvent) { 1380 Future<ServiceMap> _refreshStack(ServiceEvent pauseEvent) {
1328 return isolate.getStack().then((result) { 1381 return isolate.getStack().then((result) {
1382 if (result.isSentinel) {
1383 // The isolate has gone away. The IsolateExit event will
1384 // clear the isolate for the debugger page.
1385 return;
1386 }
1329 stack = result; 1387 stack = result;
1330 // TODO(turnidge): Replace only the changed part of the stack to
1331 // reduce flicker.
1332 stackElement.updateStack(stack, pauseEvent); 1388 stackElement.updateStack(stack, pauseEvent);
1333 if (stack['frames'].length > 0) { 1389 if (stack['frames'].length > 0) {
1334 currentFrame = 0; 1390 currentFrame = 0;
1335 } else { 1391 } else {
1336 currentFrame = null; 1392 currentFrame = null;
1337 } 1393 }
1338 input.focus(); 1394 input.focus();
1339 }); 1395 });
1340 } 1396 }
1341 1397
(...skipping 15 matching lines...) Expand all
1357 1413
1358 void _reportPause(ServiceEvent event) { 1414 void _reportPause(ServiceEvent event) {
1359 if (event.kind == ServiceEvent.kPauseStart) { 1415 if (event.kind == ServiceEvent.kPauseStart) {
1360 console.print( 1416 console.print(
1361 "Paused at isolate start " 1417 "Paused at isolate start "
1362 "(type 'continue' [F7] or 'step' [F10] to start the isolate')"); 1418 "(type 'continue' [F7] or 'step' [F10] to start the isolate')");
1363 } else if (event.kind == ServiceEvent.kPauseExit) { 1419 } else if (event.kind == ServiceEvent.kPauseExit) {
1364 console.print( 1420 console.print(
1365 "Paused at isolate exit " 1421 "Paused at isolate exit "
1366 "(type 'continue' or [F7] to exit the isolate')"); 1422 "(type 'continue' or [F7] to exit the isolate')");
1367 } 1423 } else if (stack['frames'].length > 0) {
1368 if (stack['frames'].length > 0) {
1369 Frame frame = stack['frames'][0]; 1424 Frame frame = stack['frames'][0];
1370 var script = frame.location.script; 1425 var script = frame.location.script;
1371 script.load().then((_) { 1426 script.load().then((_) {
1372 var line = script.tokenToLine(frame.location.tokenPos); 1427 var line = script.tokenToLine(frame.location.tokenPos);
1373 var col = script.tokenToCol(frame.location.tokenPos); 1428 var col = script.tokenToCol(frame.location.tokenPos);
1374 if (event.breakpoint != null) { 1429 if (event.breakpoint != null) {
1375 var bpId = event.breakpoint.number; 1430 var bpId = event.breakpoint.number;
1376 console.print('Paused at breakpoint ${bpId} at ' 1431 console.print('Paused at breakpoint ${bpId} at '
1377 '${script.name}:${line}:${col}'); 1432 '${script.name}:${line}:${col}');
1378 } else if (event.exception != null) { 1433 } else if (event.exception != null) {
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
1422 } 1477 }
1423 } 1478 }
1424 1479
1425 void onEvent(ServiceEvent event) { 1480 void onEvent(ServiceEvent event) {
1426 switch(event.kind) { 1481 switch(event.kind) {
1427 case ServiceEvent.kIsolateStart: 1482 case ServiceEvent.kIsolateStart:
1428 { 1483 {
1429 var iso = event.owner; 1484 var iso = event.owner;
1430 console.print( 1485 console.print(
1431 "Isolate ${iso.number} '${iso.name}' has been created"); 1486 "Isolate ${iso.number} '${iso.name}' has been created");
1487 if (isolate == null) {
1488 console.print("Switching to isolate ${iso.number} '${iso.name}'");
1489 isolate = iso;
1490 }
1432 } 1491 }
1433 break; 1492 break;
1434 1493
1435 case ServiceEvent.kIsolateExit: 1494 case ServiceEvent.kIsolateExit:
1436 { 1495 {
1437 var iso = event.owner; 1496 var iso = event.owner;
1438 if (iso == isolate) { 1497 if (iso == isolate) {
1439 console.print("The current isolate has exited"); 1498 console.print("The current isolate ${iso.number} '${iso.name}' "
1499 "has exited");
1500 var isolates = vm.isolates;
1501 if (isolates.length > 0) {
1502 var newIsolate = isolates.first;
1503 console.print("Switching to isolate "
1504 "${newIsolate.number} '${newIsolate.name}'");
1505 isolate = newIsolate;
1506 } else {
1507 isolate = null;
1508 }
1440 } else { 1509 } else {
1441 console.print( 1510 console.print(
1442 "Isolate ${iso.number} '${iso.name}' has exited"); 1511 "Isolate ${iso.number} '${iso.name}' has exited");
1443 } 1512 }
1444 } 1513 }
1445 break; 1514 break;
1446 1515
1447 case ServiceEvent.kDebuggerSettingsUpdate: 1516 case ServiceEvent.kDebuggerSettingsUpdate:
1448 if (breakOnException != event.exceptions) { 1517 if (breakOnException != event.exceptions) {
1449 breakOnException = event.exceptions; 1518 breakOnException = event.exceptions;
(...skipping 236 matching lines...) Expand 10 before | Expand all | Expand 10 after
1686 return new Future.value(null); 1755 return new Future.value(null);
1687 } 1756 }
1688 } 1757 }
1689 } 1758 }
1690 1759
1691 @CustomTag('debugger-page') 1760 @CustomTag('debugger-page')
1692 class DebuggerPageElement extends ObservatoryElement { 1761 class DebuggerPageElement extends ObservatoryElement {
1693 @published Isolate isolate; 1762 @published Isolate isolate;
1694 1763
1695 isolateChanged(oldValue) { 1764 isolateChanged(oldValue) {
1696 if (isolate != null) { 1765 debugger.updateIsolate(isolate);
1697 debugger.updateIsolate(isolate);
1698 }
1699 } 1766 }
1700 ObservatoryDebugger debugger = new ObservatoryDebugger(); 1767 ObservatoryDebugger debugger = new ObservatoryDebugger();
1701 1768
1702 DebuggerPageElement.created() : super.created() { 1769 DebuggerPageElement.created() : super.created() {
1703 debugger.page = this; 1770 debugger.page = this;
1704 } 1771 }
1705 1772
1706 StreamSubscription _resizeSubscription; 1773 StreamSubscription _resizeSubscription;
1707 Future<StreamSubscription> _isolateSubscriptionFuture; 1774 Future<StreamSubscription> _isolateSubscriptionFuture;
1708 Future<StreamSubscription> _debugSubscriptionFuture; 1775 Future<StreamSubscription> _debugSubscriptionFuture;
(...skipping 534 matching lines...) Expand 10 before | Expand all | Expand 10 after
2243 consoleTextElement.children.clear(); 2310 consoleTextElement.children.clear();
2244 } 2311 }
2245 } 2312 }
2246 2313
2247 @CustomTag('debugger-input') 2314 @CustomTag('debugger-input')
2248 class DebuggerInputElement extends ObservatoryElement { 2315 class DebuggerInputElement extends ObservatoryElement {
2249 @published Isolate isolate; 2316 @published Isolate isolate;
2250 @published String text = ''; 2317 @published String text = '';
2251 @observable ObservatoryDebugger debugger; 2318 @observable ObservatoryDebugger debugger;
2252 @observable bool busy = false; 2319 @observable bool busy = false;
2320 @observable String modalPrompt = null;
2321 var modalCallback = null;
2322
2323 void enterMode(String prompt, callback) {
2324 assert(prompt == null);
2325 modalPrompt = prompt;
2326 modalCallback = callback;
2327 }
2328
2329 void exitMode() {
2330 assert(prompt != null);
2331 modalPrompt = null;
2332 modalCallback = null;
2333 }
2253 2334
2254 @override 2335 @override
2255 void ready() { 2336 void ready() {
2256 super.ready(); 2337 super.ready();
2257 var textBox = $['textBox']; 2338 var textBox = $['textBox'];
2258 textBox.select(); 2339 textBox.select();
2259 textBox.onKeyDown.listen((KeyboardEvent e) { 2340 textBox.onKeyDown.listen((KeyboardEvent e) {
2260 if (busy) { 2341 if (busy) {
2261 e.preventDefault(); 2342 e.preventDefault();
2262 return; 2343 return;
2263 } 2344 }
2264 busy = true; 2345 busy = true;
2265 » switch (e.keyCode) { 2346 if (modalCallback != null) {
2347 if (e.keyCode == KeyCode.ENTER) {
2348 var response = text;
2349 modalCallback(response).whenComplete(() {
2350 text = '';
2351 busy = false;
2352 });
2353 } else {
2354 busy = false;
2355 }
2356 return;
2357 }
2358 switch (e.keyCode) {
2266 case KeyCode.TAB: 2359 case KeyCode.TAB:
2267 e.preventDefault(); 2360 e.preventDefault();
2268 int cursorPos = textBox.selectionStart; 2361 int cursorPos = textBox.selectionStart;
2269 debugger.complete(text.substring(0, cursorPos)).then((completion) { 2362 debugger.complete(text.substring(0, cursorPos)).then((completion) {
2270 text = completion + text.substring(cursorPos); 2363 text = completion + text.substring(cursorPos);
2271 // TODO(turnidge): Move the cursor to the end of the 2364 // TODO(turnidge): Move the cursor to the end of the
2272 // completion, rather than the end of the string. 2365 // completion, rather than the end of the string.
2273 }).whenComplete(() { 2366 }).whenComplete(() {
2274 busy = false; 2367 busy = false;
2275 }); 2368 });
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after
2351 busy = false; 2444 busy = false;
2352 }); 2445 });
2353 } else { 2446 } else {
2354 busy = false; 2447 busy = false;
2355 } 2448 }
2356 break; 2449 break;
2357 2450
2358 default: 2451 default:
2359 busy = false; 2452 busy = false;
2360 break; 2453 break;
2361 » } 2454 }
2362 }); 2455 });
2363 } 2456 }
2364 2457
2365 void focus() { 2458 void focus() {
2366 $['textBox'].focus(); 2459 $['textBox'].focus();
2367 } 2460 }
2368 2461
2369 DebuggerInputElement.created() : super.created(); 2462 DebuggerInputElement.created() : super.created();
2370 } 2463 }
OLDNEW
« no previous file with comments | « runtime/include/dart_api.h ('k') | runtime/observatory/lib/src/elements/debugger.html » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698