Chromium Code Reviews| 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 part of service; | 5 part of service; |
| 6 | 6 |
| 7 /// A [ServiceObject] represents a persistent object within the vm. | 7 /// A [ServiceObject] represents a persistent object within the vm. |
| 8 abstract class ServiceObject extends Observable { | 8 abstract class ServiceObject extends Observable { |
| 9 static int LexicalSortName(ServiceObject o1, ServiceObject o2) { | 9 static int LexicalSortName(ServiceObject o1, ServiceObject o2) { |
| 10 return o1.name.compareTo(o2.name); | 10 return o1.name.compareTo(o2.name); |
| (...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 116 } | 116 } |
| 117 if (!_isServiceMap(map)) { | 117 if (!_isServiceMap(map)) { |
| 118 Logger.root.severe('Malformed service object: $map'); | 118 Logger.root.severe('Malformed service object: $map'); |
| 119 } | 119 } |
| 120 assert(_isServiceMap(map)); | 120 assert(_isServiceMap(map)); |
| 121 var type = _stripRef(map['type']); | 121 var type = _stripRef(map['type']); |
| 122 var vmType = map['_vmType'] != null ? _stripRef(map['_vmType']) : type; | 122 var vmType = map['_vmType'] != null ? _stripRef(map['_vmType']) : type; |
| 123 var obj = null; | 123 var obj = null; |
| 124 assert(type != 'VM'); | 124 assert(type != 'VM'); |
| 125 switch (type) { | 125 switch (type) { |
| 126 case 'Breakpoint': | |
| 127 obj = new Breakpoint._empty(owner); | |
| 128 break; | |
| 126 case 'Class': | 129 case 'Class': |
| 127 obj = new Class._empty(owner); | 130 obj = new Class._empty(owner); |
| 128 break; | 131 break; |
| 129 case 'Code': | 132 case 'Code': |
| 130 obj = new Code._empty(owner); | 133 obj = new Code._empty(owner); |
| 131 break; | 134 break; |
| 132 case 'Context': | 135 case 'Context': |
| 133 obj = new Context._empty(owner); | 136 obj = new Context._empty(owner); |
| 134 break; | 137 break; |
| 135 case 'Counter': | 138 case 'Counter': |
| (...skipping 878 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1014 var children = _trieData[_trieDataCursor++]; | 1017 var children = _trieData[_trieDataCursor++]; |
| 1015 // Recursively read child nodes. | 1018 // Recursively read child nodes. |
| 1016 for (var i = 0; i < children; i++) { | 1019 for (var i = 0; i < children; i++) { |
| 1017 var child = _readTrieNode(codeTable); | 1020 var child = _readTrieNode(codeTable); |
| 1018 node.children.add(child); | 1021 node.children.add(child); |
| 1019 node.summedChildCount += child.count; | 1022 node.summedChildCount += child.count; |
| 1020 } | 1023 } |
| 1021 return node; | 1024 return node; |
| 1022 } | 1025 } |
| 1023 | 1026 |
| 1024 ObservableList breakpoints = new ObservableList(); | 1027 ObservableList<Breakpoint> breakpoints = new ObservableList(); |
| 1025 | 1028 |
| 1026 void _removeBreakpoint(ServiceMap bpt) { | 1029 void _removeBreakpoint(Breakpoint bpt) { |
| 1027 var script = bpt['location']['script']; | 1030 var script = bpt.script; |
| 1028 var tokenPos = bpt['location']['tokenPos']; | 1031 var tokenPos = bpt.tokenPos; |
| 1029 assert(tokenPos != null); | 1032 assert(tokenPos != null); |
| 1030 if (script.loaded) { | 1033 if (script.loaded) { |
| 1031 var line = script.tokenToLine(tokenPos); | 1034 var line = script.tokenToLine(tokenPos); |
| 1032 assert(line != null); | 1035 assert(line != null); |
| 1033 if (script.lines[line - 1] != null) { | 1036 if (script.lines[line - 1] != null) { |
| 1034 assert(script.lines[line - 1].bpt == bpt); | 1037 assert(script.lines[line - 1].bpt == bpt); |
| 1035 script.lines[line - 1].bpt = null; | 1038 script.lines[line - 1].bpt = null; |
| 1036 } | 1039 } |
| 1037 } | 1040 } |
| 1038 } | 1041 } |
| 1039 | 1042 |
| 1040 void _addBreakpoint(ServiceMap bpt) { | 1043 void _addBreakpoint(Breakpoint bpt) { |
| 1041 var script = bpt['location']['script']; | 1044 var script = bpt.script; |
| 1042 var tokenPos = bpt['location']['tokenPos']; | 1045 var tokenPos = bpt.tokenPos; |
| 1043 assert(tokenPos != null); | 1046 assert(tokenPos != null); |
| 1044 if (script.loaded) { | 1047 if (script.loaded) { |
| 1045 var line = script.tokenToLine(tokenPos); | 1048 var line = script.tokenToLine(tokenPos); |
| 1046 assert(line != null); | 1049 assert(line != null); |
| 1047 assert(script.lines[line - 1].bpt == null); | 1050 assert(script.lines[line - 1].bpt == null); |
| 1048 script.lines[line - 1].bpt = bpt; | 1051 script.lines[line - 1].bpt = bpt; |
| 1049 } else { | 1052 } else { |
| 1050 // Load the script and then plop in the breakpoint. | 1053 // Load the script and then plop in the breakpoint. |
| 1051 script.load().then((_) { | 1054 script.load().then((_) { |
| 1052 _addBreakpoint(bpt); | 1055 _addBreakpoint(bpt); |
| 1053 }); | 1056 }); |
| 1054 } | 1057 } |
| 1055 } | 1058 } |
| 1056 | 1059 |
| 1057 void _updateBreakpoints(ServiceMap newBreakpoints) { | 1060 void _updateBreakpoints(ServiceMap newBreakpoints) { |
| 1058 // Remove all of the old breakpoints from the Script lines. | 1061 // Remove all of the old breakpoints from the Script lines. |
| 1059 if (breakpoints != null) { | 1062 if (breakpoints != null) { |
| 1060 for (var bpt in breakpoints) { | 1063 for (var bpt in breakpoints) { |
| 1061 _removeBreakpoint(bpt); | 1064 _removeBreakpoint(bpt); |
| 1062 } | 1065 } |
| 1063 } | 1066 } |
| 1064 // Add all of the new breakpoints to the Script lines. | 1067 // Add all of the new breakpoints to the Script lines. |
| 1065 for (var bpt in newBreakpoints['breakpoints']) { | 1068 for (var bpt in newBreakpoints['breakpoints']) { |
| 1066 _addBreakpoint(bpt); | 1069 _addBreakpoint(bpt); |
| 1067 } | 1070 } |
| 1068 breakpoints.clear(); | 1071 breakpoints.clear(); |
| 1069 breakpoints.addAll(newBreakpoints['breakpoints']); | 1072 breakpoints.addAll(newBreakpoints['breakpoints']); |
| 1070 | 1073 |
| 1071 // Sort the breakpoints by breakpointNumber. | 1074 // Sort the breakpoints by breakpointNumber. |
| 1072 breakpoints.sort((a, b) => (a['breakpointNumber'] - b['breakpointNumber'])); | 1075 breakpoints.sort((a, b) => (a.number - b.number)); |
| 1073 } | 1076 } |
| 1074 | 1077 |
| 1075 Future<ServiceObject> _inProgressReloadBpts; | 1078 Future<ServiceObject> _inProgressReloadBpts; |
| 1076 | 1079 |
| 1077 Future reloadBreakpoints() { | 1080 Future reloadBreakpoints() { |
| 1078 // TODO(turnidge): Can reusing the Future here ever cause us to | 1081 // TODO(turnidge): Can reusing the Future here ever cause us to |
| 1079 // get stale breakpoints? | 1082 // get stale breakpoints? |
| 1080 if (_inProgressReloadBpts == null) { | 1083 if (_inProgressReloadBpts == null) { |
| 1081 _inProgressReloadBpts = | 1084 _inProgressReloadBpts = |
| 1082 invokeRpc('getBreakpoints', {}).then((newBpts) { | 1085 invokeRpc('getBreakpoints', {}).then((newBpts) { |
| 1083 _updateBreakpoints(newBpts); | 1086 _updateBreakpoints(newBpts); |
| 1084 }).whenComplete(() { | 1087 }).whenComplete(() { |
| 1085 _inProgressReloadBpts = null; | 1088 _inProgressReloadBpts = null; |
| 1086 }); | 1089 }); |
| 1087 } | 1090 } |
| 1088 return _inProgressReloadBpts; | 1091 return _inProgressReloadBpts; |
| 1089 } | 1092 } |
| 1090 | 1093 |
| 1091 Future<ServiceObject> addBreakpoint(Script script, int line) { | 1094 Future<ServiceObject> addBreakpoint(Script script, int line) { |
| 1092 // TODO(turnidge): Pass line as an int instead of a string. | 1095 // TODO(turnidge): Pass line as an int instead of a string. |
| 1093 return invokeRpc('addBreakpoint', | 1096 Map params = { |
| 1094 { 'script': script.id, 'line': '$line' }).then((result) { | 1097 'script': script.id, |
| 1095 if (result is ServiceMap && | 1098 'line': '$line', |
| 1096 result.type == 'Breakpoint' && | 1099 }; |
| 1097 result['resolved'] && | 1100 return invokeRpc('addBreakpoint', params).then((result) { |
| 1098 script.loaded && | 1101 if (result is DartError) { |
| 1099 script.tokenToLine(result['location']['tokenPos']) != line) { | 1102 return result; |
| 1100 // Unable to set a breakpoint at desired line. | 1103 } |
| 1101 script.lines[line - 1].possibleBpt = false; | 1104 Breakpoint bpt = result; |
| 1102 } | 1105 if (bpt.resolved && |
| 1103 // TODO(turnidge): Instead of reloading all of the breakpoints, | 1106 script.loaded && |
| 1104 // rely on events to update the breakpoint list. | 1107 script.tokenToLine(result.tokenPos) != line) { |
| 1105 return reloadBreakpoints().then((_) { | 1108 // Unable to set a breakpoint at desired line. |
| 1106 return result; | 1109 script.lines[line - 1].possibleBpt = false; |
| 1107 }); | 1110 } |
| 1111 // TODO(turnidge): Instead of reloading all of the breakpoints, | |
| 1112 // rely on events to update the breakpoint list. | |
| 1113 return reloadBreakpoints().then((_) { | |
| 1114 return result; | |
| 1108 }); | 1115 }); |
| 1116 }); | |
| 1109 } | 1117 } |
| 1110 | 1118 |
| 1111 Future removeBreakpoint(ServiceMap bpt) { | 1119 Future removeBreakpoint(Breakpoint bpt) { |
| 1112 return invokeRpc('removeBreakpoint', | 1120 return invokeRpc('removeBreakpoint', |
| 1113 { 'breakpointId': bpt.id }).then((result) { | 1121 { 'breakpointId': bpt.id }).then((result) { |
| 1114 if (result is DartError) { | 1122 if (result is DartError) { |
| 1115 // TODO(turnidge): Handle this more gracefully. | 1123 // TODO(turnidge): Handle this more gracefully. |
| 1116 Logger.root.severe(result.message); | 1124 Logger.root.severe(result.message); |
| 1125 return result; | |
| 1117 } | 1126 } |
| 1118 if (pauseEvent != null && | 1127 if (pauseEvent != null && |
| 1119 pauseEvent.breakpoint != null && | 1128 pauseEvent.breakpoint != null && |
| 1120 (pauseEvent.breakpoint['id'] == bpt['id'])) { | 1129 (pauseEvent.breakpoint.id == bpt.id)) { |
|
rmacnak
2015/02/13 19:00:42
As discussed, just noting id versus number weirdne
| |
| 1121 return isolate.reload(); | 1130 return isolate.reload(); |
| 1122 } else { | 1131 } else { |
| 1123 return reloadBreakpoints(); | 1132 return reloadBreakpoints(); |
| 1124 } | 1133 } |
| 1125 }); | 1134 }); |
| 1126 } | 1135 } |
| 1127 | 1136 |
| 1128 // TODO(turnidge): If the user invokes pause (or other rpcs) twice, | 1137 // TODO(turnidge): If the user invokes pause (or other rpcs) twice, |
| 1129 // they could get a race. Consider returning an "in progress" | 1138 // they could get a race. Consider returning an "in progress" |
| 1130 // future to avoid this. | 1139 // future to avoid this. |
| (...skipping 282 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1413 | 1422 |
| 1414 /// A [ServiceEvent] is an asynchronous event notification from the vm. | 1423 /// A [ServiceEvent] is an asynchronous event notification from the vm. |
| 1415 class ServiceEvent extends ServiceObject { | 1424 class ServiceEvent extends ServiceObject { |
| 1416 ServiceEvent._empty(ServiceObjectOwner owner) : super._empty(owner); | 1425 ServiceEvent._empty(ServiceObjectOwner owner) : super._empty(owner); |
| 1417 | 1426 |
| 1418 ServiceEvent.vmDisconencted() : super._empty(null) { | 1427 ServiceEvent.vmDisconencted() : super._empty(null) { |
| 1419 eventType = 'VMDisconnected'; | 1428 eventType = 'VMDisconnected'; |
| 1420 } | 1429 } |
| 1421 | 1430 |
| 1422 @observable String eventType; | 1431 @observable String eventType; |
| 1423 @observable ServiceMap breakpoint; | 1432 @observable Breakpoint breakpoint; |
| 1424 @observable ServiceMap exception; | 1433 @observable ServiceMap exception; |
| 1425 @observable ByteData data; | 1434 @observable ByteData data; |
| 1426 @observable int count; | 1435 @observable int count; |
| 1427 | 1436 |
| 1428 void _update(ObservableMap map, bool mapIsRef) { | 1437 void _update(ObservableMap map, bool mapIsRef) { |
| 1429 _loaded = true; | 1438 _loaded = true; |
| 1430 _upgradeCollection(map, owner); | 1439 _upgradeCollection(map, owner); |
| 1431 eventType = map['eventType']; | 1440 eventType = map['eventType']; |
| 1432 name = 'ServiceEvent $eventType'; | 1441 name = 'ServiceEvent $eventType'; |
| 1433 vmName = name; | 1442 vmName = name; |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 1444 count = map['count']; | 1453 count = map['count']; |
| 1445 } | 1454 } |
| 1446 } | 1455 } |
| 1447 | 1456 |
| 1448 String toString() { | 1457 String toString() { |
| 1449 return 'ServiceEvent of type $eventType with ' | 1458 return 'ServiceEvent of type $eventType with ' |
| 1450 '${data == null ? 0 : data.lengthInBytes} bytes of binary data'; | 1459 '${data == null ? 0 : data.lengthInBytes} bytes of binary data'; |
| 1451 } | 1460 } |
| 1452 } | 1461 } |
| 1453 | 1462 |
| 1463 class Breakpoint extends ServiceObject { | |
| 1464 Breakpoint._empty(ServiceObjectOwner owner) : super._empty(owner); | |
| 1465 | |
| 1466 // TODO(turnidge): Add state to track if a breakpoint has been | |
| 1467 // removed from the program. Remove from the cache when deleted. | |
| 1468 bool get canCache => true; | |
| 1469 bool get immutable => false; | |
| 1470 | |
| 1471 // A unique integer identifier for this breakpoint. | |
| 1472 @observable int number; | |
| 1473 | |
| 1474 // Source location information. | |
| 1475 @observable Script script; | |
| 1476 @observable int tokenPos; | |
| 1477 | |
| 1478 // The breakpoint has been assigned to a final source location. | |
| 1479 @observable bool resolved; | |
| 1480 | |
| 1481 // The breakpoint is active. | |
| 1482 @observable bool enabled; | |
| 1483 | |
| 1484 void _update(ObservableMap map, bool mapIsRef) { | |
| 1485 _loaded = true; | |
| 1486 _upgradeCollection(map, owner); | |
| 1487 | |
| 1488 number = map['breakpointNumber']; | |
| 1489 script = map['location']['script']; | |
| 1490 tokenPos = map['location']['tokenPos']; | |
| 1491 | |
| 1492 resolved = map['resolved']; | |
| 1493 enabled = map['enabled']; | |
| 1494 } | |
| 1495 | |
| 1496 String toString() { | |
| 1497 if (number != null) { | |
| 1498 return 'Breakpoint ${number} at ${script.name}(token:${tokenPos})'; | |
| 1499 } else { | |
| 1500 return 'Uninitialized breakpoint'; | |
| 1501 } | |
| 1502 } | |
| 1503 } | |
| 1504 | |
| 1454 class Library extends ServiceObject with Coverage { | 1505 class Library extends ServiceObject with Coverage { |
| 1455 @observable String url; | 1506 @observable String url; |
| 1456 @reflectable final imports = new ObservableList<Library>(); | 1507 @reflectable final imports = new ObservableList<Library>(); |
| 1457 @reflectable final scripts = new ObservableList<Script>(); | 1508 @reflectable final scripts = new ObservableList<Script>(); |
| 1458 @reflectable final classes = new ObservableList<Class>(); | 1509 @reflectable final classes = new ObservableList<Class>(); |
| 1459 @reflectable final variables = new ObservableList<Field>(); | 1510 @reflectable final variables = new ObservableList<Field>(); |
| 1460 @reflectable final functions = new ObservableList<ServiceFunction>(); | 1511 @reflectable final functions = new ObservableList<ServiceFunction>(); |
| 1461 | 1512 |
| 1462 bool get canCache => true; | 1513 bool get canCache => true; |
| 1463 bool get immutable => false; | 1514 bool get immutable => false; |
| (...skipping 425 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1889 | 1940 |
| 1890 String toString() => 'Field(${owner.name}.$name)'; | 1941 String toString() => 'Field(${owner.name}.$name)'; |
| 1891 } | 1942 } |
| 1892 | 1943 |
| 1893 | 1944 |
| 1894 class ScriptLine extends Observable { | 1945 class ScriptLine extends Observable { |
| 1895 final Script script; | 1946 final Script script; |
| 1896 final int line; | 1947 final int line; |
| 1897 final String text; | 1948 final String text; |
| 1898 @observable int hits; | 1949 @observable int hits; |
| 1899 @observable ServiceMap bpt; | 1950 @observable Breakpoint bpt; |
| 1900 @observable bool possibleBpt = true; | 1951 @observable bool possibleBpt = true; |
| 1901 | 1952 |
| 1902 bool get isBlank { | 1953 bool get isBlank { |
| 1903 // Compute isBlank on demand. | 1954 // Compute isBlank on demand. |
| 1904 if (_isBlank == null) { | 1955 if (_isBlank == null) { |
| 1905 _isBlank = text.trim().isEmpty; | 1956 _isBlank = text.trim().isEmpty; |
| 1906 } | 1957 } |
| 1907 return _isBlank; | 1958 return _isBlank; |
| 1908 } | 1959 } |
| 1909 bool _isBlank; | 1960 bool _isBlank; |
| (...skipping 28 matching lines...) Expand all Loading... | |
| 1938 } | 1989 } |
| 1939 } | 1990 } |
| 1940 return true; | 1991 return true; |
| 1941 } | 1992 } |
| 1942 | 1993 |
| 1943 ScriptLine(this.script, this.line, this.text) { | 1994 ScriptLine(this.script, this.line, this.text) { |
| 1944 possibleBpt = !_isTrivialLine(text); | 1995 possibleBpt = !_isTrivialLine(text); |
| 1945 | 1996 |
| 1946 // TODO(turnidge): This is not so efficient. Consider improving. | 1997 // TODO(turnidge): This is not so efficient. Consider improving. |
| 1947 for (var bpt in this.script.isolate.breakpoints) { | 1998 for (var bpt in this.script.isolate.breakpoints) { |
| 1948 var bptScript = bpt['location']['script']; | 1999 if (bpt.script == this.script && |
| 1949 var bptTokenPos = bpt['location']['tokenPos']; | 2000 bpt.script.tokenToLine(bpt.tokenPos) == line) { |
| 1950 if (bptScript == this.script && | |
| 1951 bptScript.tokenToLine(bptTokenPos) == line) { | |
| 1952 this.bpt = bpt; | 2001 this.bpt = bpt; |
| 1953 } | 2002 } |
| 1954 } | 2003 } |
| 1955 } | 2004 } |
| 1956 } | 2005 } |
| 1957 | 2006 |
| 1958 class Script extends ServiceObject with Coverage { | 2007 class Script extends ServiceObject with Coverage { |
| 1959 final lines = new ObservableList<ScriptLine>(); | 2008 final lines = new ObservableList<ScriptLine>(); |
| 1960 final _hits = new Map<int, int>(); | 2009 final _hits = new Map<int, int>(); |
| 1961 @observable String kind; | 2010 @observable String kind; |
| (...skipping 896 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2858 var v = list[i]; | 2907 var v = list[i]; |
| 2859 if ((v is ObservableMap) && _isServiceMap(v)) { | 2908 if ((v is ObservableMap) && _isServiceMap(v)) { |
| 2860 list[i] = owner.getFromMap(v); | 2909 list[i] = owner.getFromMap(v); |
| 2861 } else if (v is ObservableList) { | 2910 } else if (v is ObservableList) { |
| 2862 _upgradeObservableList(v, owner); | 2911 _upgradeObservableList(v, owner); |
| 2863 } else if (v is ObservableMap) { | 2912 } else if (v is ObservableMap) { |
| 2864 _upgradeObservableMap(v, owner); | 2913 _upgradeObservableMap(v, owner); |
| 2865 } | 2914 } |
| 2866 } | 2915 } |
| 2867 } | 2916 } |
| OLD | NEW |