| 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 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 106 Future<ServiceObject> reload() { | 106 Future<ServiceObject> reload() { |
| 107 if (id == '') { | 107 if (id == '') { |
| 108 // Errors don't have ids. | 108 // Errors don't have ids. |
| 109 assert(serviceType == 'Error'); | 109 assert(serviceType == 'Error'); |
| 110 return new Future.value(this); | 110 return new Future.value(this); |
| 111 } | 111 } |
| 112 if (loaded && immutable) { | 112 if (loaded && immutable) { |
| 113 return new Future.value(this); | 113 return new Future.value(this); |
| 114 } | 114 } |
| 115 if (_inProgressReload == null) { | 115 if (_inProgressReload == null) { |
| 116 _inProgressReload = vm.getAsMap(link).then((ObservableMap map) { | 116 _inProgressReload = vm.getAsMap(link).then((ObservableMap map) { |
| 117 var mapType = _stripRef(map['type']); | 117 var mapType = _stripRef(map['type']); |
| 118 if (mapType != _serviceType) { | 118 if (mapType != _serviceType) { |
| 119 // If the type changes, return a new object instead of | 119 // If the type changes, return a new object instead of |
| 120 // updating the existing one. | 120 // updating the existing one. |
| 121 assert(mapType == 'Error' || mapType == 'Null'); | 121 assert(mapType == 'Error' || mapType == 'Null'); |
| 122 return new ServiceObject._fromMap(owner, map); | 122 return new ServiceObject._fromMap(owner, map); |
| 123 } | 123 } |
| 124 update(map); | 124 update(map); |
| 125 return this; | 125 return this; |
| 126 }).whenComplete(() { | 126 }).whenComplete(() { |
| (...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 230 return reload().then((result) { | 230 return reload().then((result) { |
| 231 if (result is! VM) { | 231 if (result is! VM) { |
| 232 return null; | 232 return null; |
| 233 } | 233 } |
| 234 assert(result == this); | 234 assert(result == this); |
| 235 return _isolateCache[isolateId]; | 235 return _isolateCache[isolateId]; |
| 236 }); | 236 }); |
| 237 } | 237 } |
| 238 | 238 |
| 239 Future<ServiceObject> get(String id) { | 239 Future<ServiceObject> get(String id) { |
| 240 var parts = id.split('#'); |
| 241 assert(parts.length >= 1); |
| 242 // We should never see more than two hashes. |
| 243 assert(parts.length <= 2); |
| 244 // The ID does not include anything after the # (or the # itself). |
| 245 id = parts[0]; |
| 246 // I'm serious. |
| 247 assert(!id.contains('#')); |
| 240 // Isolates are handled specially, since they can cache sub-objects. | 248 // Isolates are handled specially, since they can cache sub-objects. |
| 241 if (id.startsWith(_isolatesPrefix)) { | 249 if (id.startsWith(_isolatesPrefix)) { |
| 242 String isolateId = _parseIsolateId(id); | 250 String isolateId = _parseIsolateId(id); |
| 243 String objectId = _parseObjectId(id); | 251 String objectId = _parseObjectId(id); |
| 244 return _getIsolate(isolateId).then((isolate) { | 252 return _getIsolate(isolateId).then((isolate) { |
| 245 if (isolate == null) { | 253 if (isolate == null) { |
| 246 // The isolate does not exist. Return the VM object instead. | 254 // The isolate does not exist. Return the VM object instead. |
| 247 // | 255 // |
| 248 // TODO(turnidge): Generate a service error? | 256 // TODO(turnidge): Generate a service error? |
| 249 return this; | 257 return this; |
| (...skipping 187 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 437 if (snapshots.length > _historySize) { | 445 if (snapshots.length > _historySize) { |
| 438 snapshots.removeAt(0); | 446 snapshots.removeAt(0); |
| 439 } | 447 } |
| 440 } | 448 } |
| 441 } | 449 } |
| 442 | 450 |
| 443 /// State for a running isolate. | 451 /// State for a running isolate. |
| 444 class Isolate extends ServiceObjectOwner { | 452 class Isolate extends ServiceObjectOwner { |
| 445 @reflectable VM get vm => owner; | 453 @reflectable VM get vm => owner; |
| 446 @reflectable Isolate get isolate => this; | 454 @reflectable Isolate get isolate => this; |
| 455 @observable ObservableMap counters = toObservable(new ObservableMap()); |
| 447 | 456 |
| 448 String get link => _id; | 457 String get link => _id; |
| 449 String get hashLink => '#/$_id'; | 458 String get hashLink => '#/$_id'; |
| 450 | 459 |
| 451 @observable bool pausedOnStart = false; | 460 @observable bool pausedOnStart = false; |
| 452 @observable bool pausedOnExit = false; | 461 @observable bool pausedOnExit = false; |
| 453 @observable bool running = false; | 462 @observable bool running = false; |
| 454 @observable bool idle = false; | 463 @observable bool idle = false; |
| 455 | 464 |
| 456 Map<String,ServiceObject> _cache = new Map<String,ServiceObject>(); | 465 Map<String,ServiceObject> _cache = new Map<String,ServiceObject>(); |
| (...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 518 assert(coverageList != null); | 527 assert(coverageList != null); |
| 519 coverageList.forEach((scriptCoverage) { | 528 coverageList.forEach((scriptCoverage) { |
| 520 _processScriptCoverage(scriptCoverage); | 529 _processScriptCoverage(scriptCoverage); |
| 521 }); | 530 }); |
| 522 } | 531 } |
| 523 | 532 |
| 524 void _processScriptCoverage(ObservableMap scriptCoverage) { | 533 void _processScriptCoverage(ObservableMap scriptCoverage) { |
| 525 // Because the coverage data was upgraded into a ServiceObject, | 534 // Because the coverage data was upgraded into a ServiceObject, |
| 526 // the script can be directly accessed. | 535 // the script can be directly accessed. |
| 527 Script script = scriptCoverage['script']; | 536 Script script = scriptCoverage['script']; |
| 537 assert(_cache.containsValue(script)); |
| 528 script._processHits(scriptCoverage['hits']); | 538 script._processHits(scriptCoverage['hits']); |
| 529 } | 539 } |
| 530 | 540 |
| 531 ServiceObject getFromMap(ObservableMap map) { | 541 ServiceObject getFromMap(ObservableMap map) { |
| 532 if (map == null) { | 542 if (map == null) { |
| 533 return null; | 543 return null; |
| 534 } | 544 } |
| 535 String id = map['id']; | 545 String id = map['id']; |
| 536 var obj = _cache[id]; | 546 var obj = _cache[id]; |
| 537 if (obj != null) { | 547 if (obj != null) { |
| (...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 600 rootLib = map['rootLib']; | 610 rootLib = map['rootLib']; |
| 601 if (map['entry'] != null) { | 611 if (map['entry'] != null) { |
| 602 entry = map['entry']; | 612 entry = map['entry']; |
| 603 } | 613 } |
| 604 if (map['topFrame'] != null) { | 614 if (map['topFrame'] != null) { |
| 605 topFrame = map['topFrame']; | 615 topFrame = map['topFrame']; |
| 606 } else { | 616 } else { |
| 607 topFrame = null ; | 617 topFrame = null ; |
| 608 } | 618 } |
| 609 | 619 |
| 620 var countersMap = map['tagCounters']; |
| 621 if (countersMap != null) { |
| 622 var names = countersMap['names']; |
| 623 var counts = countersMap['counters']; |
| 624 assert(names.length == counts.length); |
| 625 var sum = 0; |
| 626 for (var i = 0; i < counts.length; i++) { |
| 627 sum += counts[i]; |
| 628 } |
| 629 // TODO: Why does this not work without this? |
| 630 counters = toObservable({}); |
| 631 if (sum == 0) { |
| 632 for (var i = 0; i < names.length; i++) { |
| 633 counters[names[i]] = '0.0%'; |
| 634 } |
| 635 } else { |
| 636 for (var i = 0; i < names.length; i++) { |
| 637 counters[names[i]] = |
| 638 (counts[i] / sum * 100.0).toStringAsFixed(2) + '%'; |
| 639 } |
| 640 } |
| 641 } |
| 610 var timerMap = {}; | 642 var timerMap = {}; |
| 611 map['timers'].forEach((timer) { | 643 map['timers'].forEach((timer) { |
| 612 timerMap[timer['name']] = timer['time']; | 644 timerMap[timer['name']] = timer['time']; |
| 613 }); | 645 }); |
| 614 timers['total'] = timerMap['time_total_runtime']; | 646 timers['total'] = timerMap['time_total_runtime']; |
| 615 timers['compile'] = timerMap['time_compilation']; | 647 timers['compile'] = timerMap['time_compilation']; |
| 616 timers['gc'] = 0.0; // TODO(turnidge): Export this from VM. | 648 timers['gc'] = 0.0; // TODO(turnidge): Export this from VM. |
| 617 timers['init'] = (timerMap['time_script_loading'] + | 649 timers['init'] = (timerMap['time_script_loading'] + |
| 618 timerMap['time_creating_snapshot'] + | 650 timerMap['time_creating_snapshot'] + |
| 619 timerMap['time_isolate_initialization'] + | 651 timerMap['time_isolate_initialization'] + |
| (...skipping 191 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 811 @reflectable final int line; | 843 @reflectable final int line; |
| 812 @reflectable final String text; | 844 @reflectable final String text; |
| 813 ScriptLine(this.line, this.text); | 845 ScriptLine(this.line, this.text); |
| 814 } | 846 } |
| 815 | 847 |
| 816 class Script extends ServiceObject { | 848 class Script extends ServiceObject { |
| 817 @reflectable final lines = new ObservableList<ScriptLine>(); | 849 @reflectable final lines = new ObservableList<ScriptLine>(); |
| 818 @reflectable final hits = new ObservableMap<int, int>(); | 850 @reflectable final hits = new ObservableMap<int, int>(); |
| 819 @observable ServiceObject library; | 851 @observable ServiceObject library; |
| 820 @observable String kind; | 852 @observable String kind; |
| 821 | 853 @observable int firstTokenPos; |
| 854 @observable int lastTokenPos; |
| 822 bool get canCache => true; | 855 bool get canCache => true; |
| 823 bool get immutable => true; | 856 bool get immutable => true; |
| 824 | 857 |
| 825 String _shortUrl; | 858 String _shortUrl; |
| 826 String _url; | 859 String _url; |
| 827 | 860 |
| 828 Script._empty(ServiceObjectOwner owner) : super._empty(owner); | 861 Script._empty(ServiceObjectOwner owner) : super._empty(owner); |
| 829 | 862 |
| 830 /// This function maps a token position to a line number. | 863 /// This function maps a token position to a line number. |
| 831 int tokenToLine(int token) => _tokenToLine[token]; | 864 int tokenToLine(int token) => _tokenToLine[token]; |
| (...skipping 12 matching lines...) Expand all Loading... |
| 844 _processSource(map['source']); | 877 _processSource(map['source']); |
| 845 _parseTokenPosTable(map['tokenPosTable']); | 878 _parseTokenPosTable(map['tokenPosTable']); |
| 846 } | 879 } |
| 847 | 880 |
| 848 void _parseTokenPosTable(List<List<int>> table) { | 881 void _parseTokenPosTable(List<List<int>> table) { |
| 849 if (table == null) { | 882 if (table == null) { |
| 850 return; | 883 return; |
| 851 } | 884 } |
| 852 _tokenToLine = {}; | 885 _tokenToLine = {}; |
| 853 _tokenToCol = {}; | 886 _tokenToCol = {}; |
| 887 firstTokenPos = null; |
| 888 lastTokenPos = null; |
| 854 for (var line in table) { | 889 for (var line in table) { |
| 855 // Each entry begins with a line number... | 890 // Each entry begins with a line number... |
| 856 var lineNumber = line[0]; | 891 var lineNumber = line[0]; |
| 857 for (var pos = 1; pos < line.length; pos += 2) { | 892 for (var pos = 1; pos < line.length; pos += 2) { |
| 858 // ...and is followed by (token offset, col number) pairs. | 893 // ...and is followed by (token offset, col number) pairs. |
| 859 var tokenOffset = line[pos]; | 894 var tokenOffset = line[pos]; |
| 860 var colNumber = line[pos+1]; | 895 var colNumber = line[pos+1]; |
| 896 if (firstTokenPos == null) { |
| 897 // Mark first token position. |
| 898 firstTokenPos = tokenOffset; |
| 899 lastTokenPos = tokenOffset; |
| 900 } else { |
| 901 // Keep track of max and min token positions. |
| 902 firstTokenPos = (firstTokenPos <= tokenOffset) ? |
| 903 firstTokenPos : tokenOffset; |
| 904 lastTokenPos = (lastTokenPos >= tokenOffset) ? |
| 905 lastTokenPos : tokenOffset; |
| 906 } |
| 861 _tokenToLine[tokenOffset] = lineNumber; | 907 _tokenToLine[tokenOffset] = lineNumber; |
| 862 _tokenToCol[tokenOffset] = colNumber; | 908 _tokenToCol[tokenOffset] = colNumber; |
| 863 } | 909 } |
| 864 } | 910 } |
| 865 } | 911 } |
| 866 | 912 |
| 867 void _processHits(List scriptHits) { | 913 void _processHits(List scriptHits) { |
| 868 if (!_loaded) { | |
| 869 // Eagerly grab script source. | |
| 870 load(); | |
| 871 } | |
| 872 // Update hits table. | 914 // Update hits table. |
| 873 for (var i = 0; i < scriptHits.length; i += 2) { | 915 for (var i = 0; i < scriptHits.length; i += 2) { |
| 874 var line = scriptHits[i]; | 916 var line = scriptHits[i]; |
| 875 var hit = scriptHits[i + 1]; // hit status. | 917 var hit = scriptHits[i + 1]; // hit status. |
| 876 assert(line >= 1); // Lines start at 1. | 918 assert(line >= 1); // Lines start at 1. |
| 877 hits[line] = hit; | 919 hits[line] = hit; |
| 878 } | 920 } |
| 879 } | 921 } |
| 880 | 922 |
| 881 void _processSource(String source) { | 923 void _processSource(String source) { |
| 882 // Preemptyively mark that this is not loaded. | 924 // Preemptyively mark that this is not loaded. |
| 883 _loaded = false; | 925 _loaded = false; |
| 884 if (source == null) { | 926 if (source == null) { |
| 885 return; | 927 return; |
| 886 } | 928 } |
| 887 var sourceLines = source.split('\n'); | 929 var sourceLines = source.split('\n'); |
| 888 if (sourceLines.length == 0) { | 930 if (sourceLines.length == 0) { |
| 889 return; | 931 return; |
| 890 } | 932 } |
| 891 // We have the source to the script. This is now loaded. | 933 // We have the source to the script. This is now loaded. |
| 892 _loaded = true; | 934 _loaded = true; |
| 893 lines.clear(); | 935 lines.clear(); |
| 894 Logger.root.info('Adding ${sourceLines.length} source lines for ${_url}'); | 936 Logger.root.info('Adding ${sourceLines.length} source lines for ${_url}'); |
| 895 for (var i = 0; i < sourceLines.length; i++) { | 937 for (var i = 0; i < sourceLines.length; i++) { |
| 896 lines.add(new ScriptLine(i + 1, sourceLines[i])); | 938 lines.add(new ScriptLine(i + 1, sourceLines[i])); |
| 897 } | 939 } |
| 898 } | 940 } |
| 899 | |
| 900 | |
| 901 } | 941 } |
| 902 | 942 |
| 903 class CodeTick { | 943 class CodeTick { |
| 904 final int address; | 944 final int address; |
| 905 final int exclusiveTicks; | 945 final int exclusiveTicks; |
| 906 final int inclusiveTicks; | 946 final int inclusiveTicks; |
| 907 CodeTick(this.address, this.exclusiveTicks, this.inclusiveTicks); | 947 CodeTick(this.address, this.exclusiveTicks, this.inclusiveTicks); |
| 908 } | 948 } |
| 909 | 949 |
| 910 | 950 |
| (...skipping 248 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1159 } | 1199 } |
| 1160 | 1200 |
| 1161 int _callCount(List<CodeCallCount> calls, Code code) { | 1201 int _callCount(List<CodeCallCount> calls, Code code) { |
| 1162 for (CodeCallCount caller in calls) { | 1202 for (CodeCallCount caller in calls) { |
| 1163 if (caller.code == code) { | 1203 if (caller.code == code) { |
| 1164 return caller.count; | 1204 return caller.count; |
| 1165 } | 1205 } |
| 1166 } | 1206 } |
| 1167 return 0; | 1207 return 0; |
| 1168 } | 1208 } |
| 1209 |
| 1210 @reflectable bool get isDartCode => kind == CodeKind.Dart; |
| 1169 } | 1211 } |
| 1170 | 1212 |
| 1171 // Returns true if [map] is a service map. i.e. it has the following keys: | 1213 // Returns true if [map] is a service map. i.e. it has the following keys: |
| 1172 // 'id' and a 'type'. | 1214 // 'id' and a 'type'. |
| 1173 bool _isServiceMap(ObservableMap m) { | 1215 bool _isServiceMap(ObservableMap m) { |
| 1174 return (m != null) && (m['id'] != null) && (m['type'] != null); | 1216 return (m != null) && (m['id'] != null) && (m['type'] != null); |
| 1175 } | 1217 } |
| 1176 | 1218 |
| 1177 bool _hasRef(String type) => type.startsWith('@'); | 1219 bool _hasRef(String type) => type.startsWith('@'); |
| 1178 String _stripRef(String type) => (_hasRef(type) ? type.substring(1) : type); | 1220 String _stripRef(String type) => (_hasRef(type) ? type.substring(1) : type); |
| (...skipping 29 matching lines...) Expand all Loading... |
| 1208 var v = list[i]; | 1250 var v = list[i]; |
| 1209 if ((v is ObservableMap) && _isServiceMap(v)) { | 1251 if ((v is ObservableMap) && _isServiceMap(v)) { |
| 1210 list[i] = owner.getFromMap(v); | 1252 list[i] = owner.getFromMap(v); |
| 1211 } else if (v is ObservableList) { | 1253 } else if (v is ObservableList) { |
| 1212 _upgradeObservableList(v, owner); | 1254 _upgradeObservableList(v, owner); |
| 1213 } else if (v is ObservableMap) { | 1255 } else if (v is ObservableMap) { |
| 1214 _upgradeObservableMap(v, owner); | 1256 _upgradeObservableMap(v, owner); |
| 1215 } | 1257 } |
| 1216 } | 1258 } |
| 1217 } | 1259 } |
| OLD | NEW |