| 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] is an object known to the VM service and is tied | 7 /// A [ServiceObject] is an object known to the VM service and is tied |
| 8 /// to an owning [Isolate]. | 8 /// to an owning [Isolate]. |
| 9 abstract class ServiceObject extends Observable { | 9 abstract class ServiceObject extends Observable { |
| 10 /// The owner of this [ServiceObject]. This can be an [Isolate], a | 10 /// The owner of this [ServiceObject]. This can be an [Isolate], a |
| (...skipping 846 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 857 @observable int firstTokenPos; | 857 @observable int firstTokenPos; |
| 858 @observable int lastTokenPos; | 858 @observable int lastTokenPos; |
| 859 bool get canCache => true; | 859 bool get canCache => true; |
| 860 bool get immutable => true; | 860 bool get immutable => true; |
| 861 | 861 |
| 862 String _shortUrl; | 862 String _shortUrl; |
| 863 String _url; | 863 String _url; |
| 864 | 864 |
| 865 Script._empty(ServiceObjectOwner owner) : super._empty(owner); | 865 Script._empty(ServiceObjectOwner owner) : super._empty(owner); |
| 866 | 866 |
| 867 ScriptLine getLine(int line) { |
| 868 assert(line >= 1); |
| 869 return lines[line - 1]; |
| 870 } |
| 871 |
| 867 /// This function maps a token position to a line number. | 872 /// This function maps a token position to a line number. |
| 868 int tokenToLine(int token) => _tokenToLine[token]; | 873 int tokenToLine(int token) => _tokenToLine[token]; |
| 869 Map _tokenToLine; | 874 Map _tokenToLine; |
| 870 | 875 |
| 871 /// This function maps a token position to a column number. | 876 /// This function maps a token position to a column number. |
| 872 int tokenToCol(int token) => _tokenToCol[token]; | 877 int tokenToCol(int token) => _tokenToCol[token]; |
| 873 Map _tokenToCol; | 878 Map _tokenToCol; |
| 874 | 879 |
| 875 void _update(ObservableMap map, bool mapIsRef) { | 880 void _update(ObservableMap map, bool mapIsRef) { |
| 876 kind = map['kind']; | 881 kind = map['kind']; |
| (...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 945 } | 950 } |
| 946 | 951 |
| 947 class CodeTick { | 952 class CodeTick { |
| 948 final int address; | 953 final int address; |
| 949 final int exclusiveTicks; | 954 final int exclusiveTicks; |
| 950 final int inclusiveTicks; | 955 final int inclusiveTicks; |
| 951 CodeTick(this.address, this.exclusiveTicks, this.inclusiveTicks); | 956 CodeTick(this.address, this.exclusiveTicks, this.inclusiveTicks); |
| 952 } | 957 } |
| 953 | 958 |
| 954 | 959 |
| 960 class PcDescriptor extends Observable { |
| 961 final int address; |
| 962 @reflectable final int deoptId; |
| 963 @reflectable final int tokenPos; |
| 964 @reflectable final int tryIndex; |
| 965 @reflectable final String kind; |
| 966 @observable Script script; |
| 967 @observable String formattedLine; |
| 968 PcDescriptor(this.address, this.deoptId, this.tokenPos, this.tryIndex, |
| 969 this.kind); |
| 970 |
| 971 @reflectable String formattedDeoptId() { |
| 972 if (deoptId == -1) { |
| 973 return 'N/A'; |
| 974 } |
| 975 return deoptId.toString(); |
| 976 } |
| 977 |
| 978 @reflectable String formattedTokenPos() { |
| 979 if (tokenPos == -1) { |
| 980 return ''; |
| 981 } |
| 982 return tokenPos.toString(); |
| 983 } |
| 984 |
| 985 void processScript(Script script) { |
| 986 this.script = null; |
| 987 if (tokenPos == -1) { |
| 988 return; |
| 989 } |
| 990 var line = script.tokenToLine(tokenPos); |
| 991 if (line == null) { |
| 992 return; |
| 993 } |
| 994 this.script = script; |
| 995 var scriptLine = script.getLine(line); |
| 996 formattedLine = scriptLine.text; |
| 997 } |
| 998 } |
| 999 |
| 955 class CodeInstruction extends Observable { | 1000 class CodeInstruction extends Observable { |
| 956 @observable final int address; | 1001 @observable final int address; |
| 957 @observable final String machine; | 1002 @observable final String machine; |
| 958 @observable final String human; | 1003 @observable final String human; |
| 1004 @observable CodeInstruction jumpTarget; |
| 1005 @reflectable List<PcDescriptor> descriptors = |
| 1006 new ObservableList<PcDescriptor>(); |
| 959 | 1007 |
| 960 static String formatPercent(num a, num total) { | 1008 static String formatPercent(num a, num total) { |
| 961 var percent = 100.0 * (a / total); | 1009 var percent = 100.0 * (a / total); |
| 962 return '${percent.toStringAsFixed(2)}%'; | 1010 return '${percent.toStringAsFixed(2)}%'; |
| 963 } | 1011 } |
| 964 | 1012 |
| 965 CodeInstruction(this.address, this.machine, this.human); | 1013 CodeInstruction(this.address, this.machine, this.human); |
| 966 | 1014 |
| 1015 @reflectable bool get isComment => address == 0; |
| 1016 @reflectable bool get hasDescriptors => descriptors.length > 0; |
| 1017 |
| 967 @reflectable String formattedAddress() { | 1018 @reflectable String formattedAddress() { |
| 968 if (address == 0) { | 1019 if (address == 0) { |
| 969 return ''; | 1020 return ''; |
| 970 } | 1021 } |
| 971 return '0x${address.toRadixString(16)}'; | 1022 return '0x${address.toRadixString(16)}'; |
| 972 } | 1023 } |
| 973 | 1024 |
| 974 @reflectable String formattedInclusive(Code code) { | 1025 @reflectable String formattedInclusive(Code code) { |
| 975 if (code == null) { | 1026 if (code == null) { |
| 976 return ''; | 1027 return ''; |
| (...skipping 14 matching lines...) Expand all Loading... |
| 991 if (code == null) { | 1042 if (code == null) { |
| 992 return ''; | 1043 return ''; |
| 993 } | 1044 } |
| 994 var tick = code.addressTicks[address]; | 1045 var tick = code.addressTicks[address]; |
| 995 if (tick == null) { | 1046 if (tick == null) { |
| 996 return ''; | 1047 return ''; |
| 997 } | 1048 } |
| 998 var pcent = formatPercent(tick.exclusiveTicks, code.totalSamplesInProfile); | 1049 var pcent = formatPercent(tick.exclusiveTicks, code.totalSamplesInProfile); |
| 999 return '$pcent (${tick.exclusiveTicks})'; | 1050 return '$pcent (${tick.exclusiveTicks})'; |
| 1000 } | 1051 } |
| 1052 |
| 1053 bool _isJumpInstruction() { |
| 1054 return human.startsWith('j'); |
| 1055 } |
| 1056 |
| 1057 int _getJumpAddress() { |
| 1058 assert(_isJumpInstruction()); |
| 1059 var chunks = human.split(' '); |
| 1060 if (chunks.length != 2) { |
| 1061 // We expect jump instructions to be of the form 'j.. address'. |
| 1062 return 0; |
| 1063 } |
| 1064 var address = chunks[1]; |
| 1065 if (address.startsWith('0x')) { |
| 1066 // Chop off the 0x. |
| 1067 address = address.substring(2); |
| 1068 } |
| 1069 try { |
| 1070 return int.parse(address, radix:16); |
| 1071 } catch (_) { |
| 1072 return 0; |
| 1073 } |
| 1074 } |
| 1075 |
| 1076 void _resolveJumpTarget(List<CodeInstruction> instructions) { |
| 1077 if (!_isJumpInstruction()) { |
| 1078 return; |
| 1079 } |
| 1080 int address = _getJumpAddress(); |
| 1081 if (address == 0) { |
| 1082 // Could not determine jump address. |
| 1083 print('Could not determine jump address for $human'); |
| 1084 return; |
| 1085 } |
| 1086 for (var i = 0; i < instructions.length; i++) { |
| 1087 var instruction = instructions[i]; |
| 1088 if (instruction.address == address) { |
| 1089 jumpTarget = instruction; |
| 1090 return; |
| 1091 } |
| 1092 } |
| 1093 print('Could not find instruction at ${address.toRadixString(16)}'); |
| 1094 } |
| 1001 } | 1095 } |
| 1002 | 1096 |
| 1003 class CodeKind { | 1097 class CodeKind { |
| 1004 final _value; | 1098 final _value; |
| 1005 const CodeKind._internal(this._value); | 1099 const CodeKind._internal(this._value); |
| 1006 String toString() => '$_value'; | 1100 String toString() => '$_value'; |
| 1007 | 1101 |
| 1008 static CodeKind fromString(String s) { | 1102 static CodeKind fromString(String s) { |
| 1009 if (s == 'Native') { | 1103 if (s == 'Native') { |
| 1010 return Native; | 1104 return Native; |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1049 @reflectable int startAddress = 0; | 1143 @reflectable int startAddress = 0; |
| 1050 @reflectable int endAddress = 0; | 1144 @reflectable int endAddress = 0; |
| 1051 @reflectable final callers = new List<CodeCallCount>(); | 1145 @reflectable final callers = new List<CodeCallCount>(); |
| 1052 @reflectable final callees = new List<CodeCallCount>(); | 1146 @reflectable final callees = new List<CodeCallCount>(); |
| 1053 @reflectable final instructions = new ObservableList<CodeInstruction>(); | 1147 @reflectable final instructions = new ObservableList<CodeInstruction>(); |
| 1054 @reflectable final addressTicks = new ObservableMap<int, CodeTick>(); | 1148 @reflectable final addressTicks = new ObservableMap<int, CodeTick>(); |
| 1055 @observable String formattedInclusiveTicks = ''; | 1149 @observable String formattedInclusiveTicks = ''; |
| 1056 @observable String formattedExclusiveTicks = ''; | 1150 @observable String formattedExclusiveTicks = ''; |
| 1057 @observable ServiceMap objectPool; | 1151 @observable ServiceMap objectPool; |
| 1058 @observable ServiceMap function; | 1152 @observable ServiceMap function; |
| 1153 @observable Script script; |
| 1059 String name; | 1154 String name; |
| 1060 String vmName; | 1155 String vmName; |
| 1061 | 1156 |
| 1062 bool get canCache => true; | 1157 bool get canCache => true; |
| 1063 bool get immutable => true; | 1158 bool get immutable => true; |
| 1064 | 1159 |
| 1065 Code._empty(ServiceObjectOwner owner) : super._empty(owner); | 1160 Code._empty(ServiceObjectOwner owner) : super._empty(owner); |
| 1066 | 1161 |
| 1067 // Reset all data associated with a profile. | 1162 // Reset all data associated with a profile. |
| 1068 void resetProfileData() { | 1163 void resetProfileData() { |
| 1069 totalSamplesInProfile = 0; | 1164 totalSamplesInProfile = 0; |
| 1070 exclusiveTicks = 0; | 1165 exclusiveTicks = 0; |
| 1071 inclusiveTicks = 0; | 1166 inclusiveTicks = 0; |
| 1072 formattedInclusiveTicks = ''; | 1167 formattedInclusiveTicks = ''; |
| 1073 formattedExclusiveTicks = ''; | 1168 formattedExclusiveTicks = ''; |
| 1074 callers.clear(); | 1169 callers.clear(); |
| 1075 callees.clear(); | 1170 callees.clear(); |
| 1076 addressTicks.clear(); | 1171 addressTicks.clear(); |
| 1077 } | 1172 } |
| 1078 | 1173 |
| 1174 void _updateDescriptors(Script script) { |
| 1175 this.script = script; |
| 1176 for (var instruction in instructions) { |
| 1177 for (var descriptor in instruction.descriptors) { |
| 1178 descriptor.processScript(script); |
| 1179 } |
| 1180 } |
| 1181 } |
| 1182 |
| 1183 void loadScript() { |
| 1184 if (script != null) { |
| 1185 // Already done. |
| 1186 return; |
| 1187 } |
| 1188 if (kind != CodeKind.Dart){ |
| 1189 return; |
| 1190 } |
| 1191 if (function == null) { |
| 1192 return; |
| 1193 } |
| 1194 if (function['script'] == null) { |
| 1195 // Attempt to load the function. |
| 1196 function.load().then((func) { |
| 1197 var script = function['script']; |
| 1198 if (script == null) { |
| 1199 // Function doesn't have an associated script. |
| 1200 return; |
| 1201 } |
| 1202 // Load the script and then update descriptors. |
| 1203 script.load().then(_updateDescriptors); |
| 1204 }); |
| 1205 return; |
| 1206 } |
| 1207 // Load the script and then update descriptors. |
| 1208 function['script'].load().then(_updateDescriptors); |
| 1209 } |
| 1210 |
| 1079 /// Reload [this]. Returns a future which completes to [this] or | 1211 /// Reload [this]. Returns a future which completes to [this] or |
| 1080 /// a [ServiceError]. | 1212 /// a [ServiceError]. |
| 1081 Future<ServiceObject> reload() { | 1213 Future<ServiceObject> reload() { |
| 1082 assert(kind != null); | 1214 assert(kind != null); |
| 1083 if (kind == CodeKind.Dart) { | 1215 if (kind == CodeKind.Dart) { |
| 1084 // We only reload Dart code. | 1216 // We only reload Dart code. |
| 1085 return super.reload(); | 1217 return super.reload(); |
| 1086 } | 1218 } |
| 1087 return new Future.value(this); | 1219 return new Future.value(this); |
| 1088 } | 1220 } |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1137 vmName = m['name']; | 1269 vmName = m['name']; |
| 1138 kind = CodeKind.fromString(m['kind']); | 1270 kind = CodeKind.fromString(m['kind']); |
| 1139 startAddress = int.parse(m['start'], radix:16); | 1271 startAddress = int.parse(m['start'], radix:16); |
| 1140 endAddress = int.parse(m['end'], radix:16); | 1272 endAddress = int.parse(m['end'], radix:16); |
| 1141 function = isolate.getFromMap(m['function']); | 1273 function = isolate.getFromMap(m['function']); |
| 1142 objectPool = isolate.getFromMap(m['object_pool']); | 1274 objectPool = isolate.getFromMap(m['object_pool']); |
| 1143 var disassembly = m['disassembly']; | 1275 var disassembly = m['disassembly']; |
| 1144 if (disassembly != null) { | 1276 if (disassembly != null) { |
| 1145 _processDisassembly(disassembly); | 1277 _processDisassembly(disassembly); |
| 1146 } | 1278 } |
| 1279 var descriptors = m['descriptors']; |
| 1280 if (descriptors != null) { |
| 1281 descriptors = descriptors['members']; |
| 1282 _processDescriptors(descriptors); |
| 1283 } |
| 1147 // We are loaded if we have instructions or are not Dart code. | 1284 // We are loaded if we have instructions or are not Dart code. |
| 1148 _loaded = (instructions.length != 0) || (kind != CodeKind.Dart); | 1285 _loaded = (instructions.length != 0) || (kind != CodeKind.Dart); |
| 1149 hasDisassembly = (instructions.length != 0) && (kind == CodeKind.Dart); | 1286 hasDisassembly = (instructions.length != 0) && (kind == CodeKind.Dart); |
| 1150 } | 1287 } |
| 1151 | 1288 |
| 1152 @observable bool hasDisassembly = false; | 1289 @observable bool hasDisassembly = false; |
| 1153 | 1290 |
| 1154 void _processDisassembly(List<String> disassembly){ | 1291 void _processDisassembly(List<String> disassembly){ |
| 1155 assert(disassembly != null); | 1292 assert(disassembly != null); |
| 1156 instructions.clear(); | 1293 instructions.clear(); |
| 1157 assert((disassembly.length % 3) == 0); | 1294 assert((disassembly.length % 3) == 0); |
| 1158 for (var i = 0; i < disassembly.length; i += 3) { | 1295 for (var i = 0; i < disassembly.length; i += 3) { |
| 1159 var address = 0; // Assume code comment. | 1296 var address = 0; // Assume code comment. |
| 1160 var machine = disassembly[i + 1]; | 1297 var machine = disassembly[i + 1]; |
| 1161 var human = disassembly[i + 2]; | 1298 var human = disassembly[i + 2]; |
| 1162 if (disassembly[i] != '') { | 1299 if (disassembly[i] != '') { |
| 1163 // Not a code comment, extract address. | 1300 // Not a code comment, extract address. |
| 1164 address = int.parse(disassembly[i]); | 1301 address = int.parse(disassembly[i]); |
| 1165 } | 1302 } |
| 1166 var instruction = new CodeInstruction(address, machine, human); | 1303 var instruction = new CodeInstruction(address, machine, human); |
| 1167 instructions.add(instruction); | 1304 instructions.add(instruction); |
| 1168 } | 1305 } |
| 1306 for (var instruction in instructions) { |
| 1307 instruction._resolveJumpTarget(instructions); |
| 1308 } |
| 1309 } |
| 1310 |
| 1311 void _processDescriptor(Map d) { |
| 1312 var address = int.parse(d['pc'], radix:16); |
| 1313 var deoptId = d['deoptId']; |
| 1314 var tokenPos = d['tokenPos']; |
| 1315 var tryIndex = d['tryIndex']; |
| 1316 var kind = d['kind'].trim(); |
| 1317 for (var instruction in instructions) { |
| 1318 if (instruction.address == address) { |
| 1319 instruction.descriptors.add(new PcDescriptor(address, |
| 1320 deoptId, |
| 1321 tokenPos, |
| 1322 tryIndex, |
| 1323 kind)); |
| 1324 return; |
| 1325 } |
| 1326 } |
| 1327 Logger.root.warning( |
| 1328 'Could not find instruction with pc descriptor address: $address'); |
| 1329 } |
| 1330 |
| 1331 void _processDescriptors(List<Map> descriptors) { |
| 1332 for (Map descriptor in descriptors) { |
| 1333 _processDescriptor(descriptor); |
| 1334 } |
| 1169 } | 1335 } |
| 1170 | 1336 |
| 1171 void _processTicks(List<String> profileTicks) { | 1337 void _processTicks(List<String> profileTicks) { |
| 1172 assert(profileTicks != null); | 1338 assert(profileTicks != null); |
| 1173 assert((profileTicks.length % 3) == 0); | 1339 assert((profileTicks.length % 3) == 0); |
| 1174 for (var i = 0; i < profileTicks.length; i += 3) { | 1340 for (var i = 0; i < profileTicks.length; i += 3) { |
| 1175 var address = int.parse(profileTicks[i], radix:16); | 1341 var address = int.parse(profileTicks[i], radix:16); |
| 1176 var exclusive = int.parse(profileTicks[i + 1]); | 1342 var exclusive = int.parse(profileTicks[i + 1]); |
| 1177 var inclusive = int.parse(profileTicks[i + 2]); | 1343 var inclusive = int.parse(profileTicks[i + 2]); |
| 1178 var tick = new CodeTick(address, exclusive, inclusive); | 1344 var tick = new CodeTick(address, exclusive, inclusive); |
| (...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1254 var v = list[i]; | 1420 var v = list[i]; |
| 1255 if ((v is ObservableMap) && _isServiceMap(v)) { | 1421 if ((v is ObservableMap) && _isServiceMap(v)) { |
| 1256 list[i] = owner.getFromMap(v); | 1422 list[i] = owner.getFromMap(v); |
| 1257 } else if (v is ObservableList) { | 1423 } else if (v is ObservableList) { |
| 1258 _upgradeObservableList(v, owner); | 1424 _upgradeObservableList(v, owner); |
| 1259 } else if (v is ObservableMap) { | 1425 } else if (v is ObservableMap) { |
| 1260 _upgradeObservableMap(v, owner); | 1426 _upgradeObservableMap(v, owner); |
| 1261 } | 1427 } |
| 1262 } | 1428 } |
| 1263 } | 1429 } |
| OLD | NEW |