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 559 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
570 }, test: (e) => e is ServiceError).catchError((exception) { | 570 }, test: (e) => e is ServiceError).catchError((exception) { |
571 | 571 |
572 // ServiceException, forward to VM's ServiceException stream. | 572 // ServiceException, forward to VM's ServiceException stream. |
573 exceptions.add(exception); | 573 exceptions.add(exception); |
574 return new Future.error(exception); | 574 return new Future.error(exception); |
575 }, test: (e) => e is ServiceException); | 575 }, test: (e) => e is ServiceException); |
576 } | 576 } |
577 | 577 |
578 Future<ServiceObject> invokeRpc(String method, Map params) { | 578 Future<ServiceObject> invokeRpc(String method, Map params) { |
579 return invokeRpcNoUpgrade(method, params).then((ObservableMap response) { | 579 return invokeRpcNoUpgrade(method, params).then((ObservableMap response) { |
580 » var obj = new ServiceObject._fromMap(this, response); | 580 var obj = new ServiceObject._fromMap(this, response); |
581 if (obj.canCache) { | 581 if ((obj != null) && obj.canCache) { |
582 _cache.putIfAbsent(id, () => obj); | 582 String objId = obj.id; |
583 } | 583 _cache.putIfAbsent(objId, () => obj); |
584 return obj; | 584 } |
| 585 return obj; |
585 }); | 586 }); |
586 } | 587 } |
587 | 588 |
588 Future<ObservableMap> _fetchDirect() { | 589 Future<ObservableMap> _fetchDirect() { |
589 return invokeRpcNoUpgrade('getVM', {}); | 590 return invokeRpcNoUpgrade('getVM', {}); |
590 } | 591 } |
591 | 592 |
592 Future<ServiceObject> getFlagList() { | 593 Future<ServiceObject> getFlagList() { |
593 return invokeRpc('getFlagList', {}); | 594 return invokeRpc('getFlagList', {}); |
594 } | 595 } |
(...skipping 175 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
770 @observable bool loading = true; | 771 @observable bool loading = true; |
771 @observable bool ioEnabled = false; | 772 @observable bool ioEnabled = false; |
772 | 773 |
773 Map<String,ServiceObject> _cache = new Map<String,ServiceObject>(); | 774 Map<String,ServiceObject> _cache = new Map<String,ServiceObject>(); |
774 final TagProfile tagProfile = new TagProfile(20); | 775 final TagProfile tagProfile = new TagProfile(20); |
775 | 776 |
776 Isolate._empty(ServiceObjectOwner owner) : super._empty(owner) { | 777 Isolate._empty(ServiceObjectOwner owner) : super._empty(owner) { |
777 assert(owner is VM); | 778 assert(owner is VM); |
778 } | 779 } |
779 | 780 |
780 static const TAG_ROOT_ID = 'code/tag-0'; | 781 void resetCachedProfileData() { |
781 | |
782 /// Returns the Code object for the root tag. | |
783 Code tagRoot() { | |
784 // TODO(turnidge): Use get() here instead? | |
785 return _cache[TAG_ROOT_ID]; | |
786 } | |
787 | |
788 void processProfile(ServiceMap profile) { | |
789 assert(profile.type == 'CpuProfile'); | |
790 var codeTable = new List<Code>(); | |
791 var codeRegions = profile['codes']; | |
792 for (var codeRegion in codeRegions) { | |
793 Code code = codeRegion['code']; | |
794 assert(code != null); | |
795 codeTable.add(code); | |
796 } | |
797 _resetProfileData(); | |
798 _updateProfileData(profile, codeTable); | |
799 var exclusiveTrie = profile['exclusive_trie']; | |
800 if (exclusiveTrie != null) { | |
801 profileTrieRoot = _processProfileTrie(exclusiveTrie, codeTable); | |
802 } | |
803 } | |
804 | |
805 void _resetProfileData() { | |
806 _cache.values.forEach((value) { | 782 _cache.values.forEach((value) { |
807 if (value is Code) { | 783 if (value is Code) { |
808 Code code = value; | 784 Code code = value; |
809 code.resetProfileData(); | 785 code.profile = null; |
810 } | 786 } else if (value is ServiceFunction) { |
811 }); | 787 ServiceFunction function = value; |
812 } | 788 function.profile = null; |
813 | 789 } |
814 void _updateProfileData(ServiceMap profile, List<Code> codeTable) { | 790 }); |
815 var codeRegions = profile['codes']; | |
816 var sampleCount = profile['samples']; | |
817 for (var codeRegion in codeRegions) { | |
818 Code code = codeRegion['code']; | |
819 code.updateProfileData(codeRegion, codeTable, sampleCount); | |
820 } | |
821 } | 791 } |
822 | 792 |
823 /// Fetches and builds the class hierarchy for this isolate. Returns the | 793 /// Fetches and builds the class hierarchy for this isolate. Returns the |
824 /// Object class object. | 794 /// Object class object. |
825 Future<Class> getClassHierarchy() { | 795 Future<Class> getClassHierarchy() { |
826 return invokeRpc('getClassList', {}) | 796 return invokeRpc('getClassList', {}) |
827 .then(_loadClasses) | 797 .then(_loadClasses) |
828 .then(_buildClassHierarchy); | 798 .then(_buildClassHierarchy); |
829 } | 799 } |
830 | 800 |
(...skipping 23 matching lines...) Expand all Loading... |
854 } | 824 } |
855 } | 825 } |
856 assert(objectClass != null); | 826 assert(objectClass != null); |
857 return new Future.value(objectClass); | 827 return new Future.value(objectClass); |
858 } | 828 } |
859 | 829 |
860 ServiceObject getFromMap(ObservableMap map) { | 830 ServiceObject getFromMap(ObservableMap map) { |
861 if (map == null) { | 831 if (map == null) { |
862 return null; | 832 return null; |
863 } | 833 } |
864 String id = map['id']; | 834 String mapId = map['id']; |
865 var obj = _cache[id]; | 835 var obj = (mapId != null) ? _cache[mapId] : null; |
866 if (obj != null) { | 836 if (obj != null) { |
867 // Consider calling update when map is not a reference. | 837 // Consider calling update when map is not a reference. |
868 return obj; | 838 return obj; |
869 } | 839 } |
870 // Build the object from the map directly. | 840 // Build the object from the map directly. |
871 obj = new ServiceObject._fromMap(this, map); | 841 obj = new ServiceObject._fromMap(this, map); |
872 if (obj != null && obj.canCache) { | 842 if ((obj != null) && obj.canCache) { |
873 _cache[id] = obj; | 843 _cache[mapId] = obj; |
874 } | 844 } |
875 return obj; | 845 return obj; |
876 } | 846 } |
877 | 847 |
878 Future<ObservableMap> invokeRpcNoUpgrade(String method, Map params) { | 848 Future<ObservableMap> invokeRpcNoUpgrade(String method, Map params) { |
879 params['isolateId'] = id; | 849 params['isolateId'] = id; |
880 return vm.invokeRpcNoUpgrade(method, params); | 850 return vm.invokeRpcNoUpgrade(method, params); |
881 } | 851 } |
882 | 852 |
883 Future<ServiceObject> invokeRpc(String method, Map params) { | 853 Future<ServiceObject> invokeRpc(String method, Map params) { |
884 return invokeRpcNoUpgrade(method, params).then((ObservableMap response) { | 854 return invokeRpcNoUpgrade(method, params).then((ObservableMap response) { |
885 var obj = new ServiceObject._fromMap(this, response); | 855 var obj = new ServiceObject._fromMap(this, response); |
886 if (obj.canCache) { | 856 if ((obj != null) && obj.canCache) { |
887 _cache.putIfAbsent(id, () => obj); | 857 String objId = obj.id; |
888 } | 858 _cache.putIfAbsent(objId, () => obj); |
889 » return obj; | 859 } |
| 860 return obj; |
890 }); | 861 }); |
891 } | 862 } |
892 | 863 |
893 Future<ServiceObject> getObject(String objectId) { | 864 Future<ServiceObject> getObject(String objectId) { |
894 assert(objectId != null && objectId != ''); | 865 assert(objectId != null && objectId != ''); |
895 var obj = _cache[objectId]; | 866 var obj = _cache[objectId]; |
896 if (obj != null) { | 867 if (obj != null) { |
897 return obj.reload(); | 868 return obj.reload(); |
898 } | 869 } |
899 Map params = { | 870 Map params = { |
(...skipping 135 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1035 | 1006 |
1036 Future<TagProfile> updateTagProfile() { | 1007 Future<TagProfile> updateTagProfile() { |
1037 return isolate.invokeRpcNoUpgrade('getTagProfile', {}).then( | 1008 return isolate.invokeRpcNoUpgrade('getTagProfile', {}).then( |
1038 (ObservableMap map) { | 1009 (ObservableMap map) { |
1039 var seconds = new DateTime.now().millisecondsSinceEpoch / 1000.0; | 1010 var seconds = new DateTime.now().millisecondsSinceEpoch / 1000.0; |
1040 tagProfile._processTagProfile(seconds, map); | 1011 tagProfile._processTagProfile(seconds, map); |
1041 return tagProfile; | 1012 return tagProfile; |
1042 }); | 1013 }); |
1043 } | 1014 } |
1044 | 1015 |
1045 @reflectable CodeTrieNode profileTrieRoot; | |
1046 // The profile trie is serialized as a list of integers. Each node | |
1047 // is recreated by consuming some portion of the list. The format is as | |
1048 // follows: | |
1049 // [0] index into codeTable of code object. | |
1050 // [1] tick count (number of times this stack frame occured). | |
1051 // [2] child node count | |
1052 // Reading the trie is done by recursively reading the tree depth-first | |
1053 // pre-order. | |
1054 CodeTrieNode _processProfileTrie(List<int> data, List<Code> codeTable) { | |
1055 // Setup state shared across calls to _readTrieNode. | |
1056 _trieDataCursor = 0; | |
1057 _trieData = data; | |
1058 if (_trieData == null) { | |
1059 return null; | |
1060 } | |
1061 if (_trieData.length < 3) { | |
1062 // Not enough integers for 1 node. | |
1063 return null; | |
1064 } | |
1065 // Read the tree, returns the root node. | |
1066 return _readTrieNode(codeTable); | |
1067 } | |
1068 int _trieDataCursor; | |
1069 List<int> _trieData; | |
1070 CodeTrieNode _readTrieNode(List<Code> codeTable) { | |
1071 // Read index into code table. | |
1072 var index = _trieData[_trieDataCursor++]; | |
1073 // Lookup code object. | |
1074 var code = codeTable[index]; | |
1075 // Frame counter. | |
1076 var count = _trieData[_trieDataCursor++]; | |
1077 // Create node. | |
1078 var node = new CodeTrieNode(code, count); | |
1079 // Number of children. | |
1080 var children = _trieData[_trieDataCursor++]; | |
1081 // Recursively read child nodes. | |
1082 for (var i = 0; i < children; i++) { | |
1083 var child = _readTrieNode(codeTable); | |
1084 node.children.add(child); | |
1085 node.summedChildCount += child.count; | |
1086 } | |
1087 return node; | |
1088 } | |
1089 | |
1090 ObservableList<Breakpoint> breakpoints = new ObservableList(); | 1016 ObservableList<Breakpoint> breakpoints = new ObservableList(); |
1091 | 1017 |
1092 void _removeBreakpoint(Breakpoint bpt) { | 1018 void _removeBreakpoint(Breakpoint bpt) { |
1093 var script = bpt.script; | 1019 var script = bpt.script; |
1094 var tokenPos = bpt.tokenPos; | 1020 var tokenPos = bpt.tokenPos; |
1095 assert(tokenPos != null); | 1021 assert(tokenPos != null); |
1096 if (script.loaded) { | 1022 if (script.loaded) { |
1097 var line = script.tokenToLine(tokenPos); | 1023 var line = script.tokenToLine(tokenPos); |
1098 assert(line != null); | 1024 assert(line != null); |
1099 if (script.lines[line - 1] != null) { | 1025 if (script.lines[line - 1] != null) { |
(...skipping 761 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1861 | 1787 |
1862 String toString() => 'Context($length)'; | 1788 String toString() => 'Context($length)'; |
1863 } | 1789 } |
1864 | 1790 |
1865 | 1791 |
1866 // TODO(koda): Sync this with VM. | 1792 // TODO(koda): Sync this with VM. |
1867 class FunctionKind { | 1793 class FunctionKind { |
1868 final String _strValue; | 1794 final String _strValue; |
1869 FunctionKind._internal(this._strValue); | 1795 FunctionKind._internal(this._strValue); |
1870 toString() => _strValue; | 1796 toString() => _strValue; |
1871 bool isFake() => [kCollected, kNative, kTag, kReused].contains(this); | 1797 bool isSynthetic() => [kCollected, kNative, kTag, kReused].contains(this); |
1872 | 1798 |
1873 static FunctionKind fromJSON(String value) { | 1799 static FunctionKind fromJSON(String value) { |
1874 switch(value) { | 1800 switch(value) { |
1875 case 'kRegularFunction': return kRegularFunction; | 1801 case 'kRegularFunction': return kRegularFunction; |
1876 case 'kClosureFunction': return kClosureFunction; | 1802 case 'kClosureFunction': return kClosureFunction; |
1877 case 'kGetterFunction': return kGetterFunction; | 1803 case 'kGetterFunction': return kGetterFunction; |
1878 case 'kSetterFunction': return kSetterFunction; | 1804 case 'kSetterFunction': return kSetterFunction; |
1879 case 'kConstructor': return kConstructor; | 1805 case 'kConstructor': return kConstructor; |
1880 case 'kImplicitGetter': return kImplicitGetterFunction; | 1806 case 'kImplicitGetter': return kImplicitGetterFunction; |
1881 case 'kImplicitSetter': return kImplicitSetterFunction; | 1807 case 'kImplicitSetter': return kImplicitSetterFunction; |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1920 @observable int endTokenPos; | 1846 @observable int endTokenPos; |
1921 @observable Code code; | 1847 @observable Code code; |
1922 @observable Code unoptimizedCode; | 1848 @observable Code unoptimizedCode; |
1923 @observable bool isOptimizable; | 1849 @observable bool isOptimizable; |
1924 @observable bool isInlinable; | 1850 @observable bool isInlinable; |
1925 @observable FunctionKind kind; | 1851 @observable FunctionKind kind; |
1926 @observable int deoptimizations; | 1852 @observable int deoptimizations; |
1927 @observable String qualifiedName; | 1853 @observable String qualifiedName; |
1928 @observable int usageCounter; | 1854 @observable int usageCounter; |
1929 @observable bool isDart; | 1855 @observable bool isDart; |
| 1856 @observable ProfileFunction profile; |
| 1857 |
| 1858 bool get canCache => true; |
| 1859 bool get immutable => false; |
1930 | 1860 |
1931 ServiceFunction._empty(ServiceObject owner) : super._empty(owner); | 1861 ServiceFunction._empty(ServiceObject owner) : super._empty(owner); |
1932 | 1862 |
1933 void _update(ObservableMap map, bool mapIsRef) { | 1863 void _update(ObservableMap map, bool mapIsRef) { |
1934 name = map['name']; | 1864 name = map['name']; |
1935 vmName = (map.containsKey('vmName') ? map['vmName'] : name); | 1865 vmName = (map.containsKey('vmName') ? map['vmName'] : name); |
1936 | 1866 |
1937 _upgradeCollection(map, isolate); | 1867 _upgradeCollection(map, isolate); |
1938 | 1868 |
1939 owningClass = map.containsKey('owningClass') ? map['owningClass'] : null; | 1869 owningClass = map.containsKey('owningClass') ? map['owningClass'] : null; |
1940 owningLibrary = map.containsKey('owningLibrary') ? map['owningLibrary'] : nu
ll; | 1870 owningLibrary = map.containsKey('owningLibrary') ? map['owningLibrary'] : nu
ll; |
1941 kind = FunctionKind.fromJSON(map['kind']); | 1871 kind = FunctionKind.fromJSON(map['kind']); |
1942 isDart = !kind.isFake(); | 1872 isDart = !kind.isSynthetic(); |
1943 | 1873 |
1944 if (parent == null) { | 1874 if (parent == null) { |
1945 qualifiedName = (owningClass != null) ? | 1875 qualifiedName = (owningClass != null) ? |
1946 "${owningClass.name}.${name}" : | 1876 "${owningClass.name}.${name}" : |
1947 name; | 1877 name; |
1948 } else { | 1878 } else { |
1949 qualifiedName = "${parent.qualifiedName}.${name}"; | 1879 qualifiedName = "${parent.qualifiedName}.${name}"; |
1950 } | 1880 } |
1951 | 1881 |
1952 if (mapIsRef) { return; } | 1882 if (mapIsRef) { |
| 1883 return; |
| 1884 } |
1953 | 1885 |
1954 isStatic = map['static']; | 1886 isStatic = map['static']; |
1955 isConst = map['const']; | 1887 isConst = map['const']; |
1956 parent = map['parent']; | 1888 parent = map['parent']; |
1957 script = map['script']; | 1889 script = map['script']; |
1958 tokenPos = map['tokenPos']; | 1890 tokenPos = map['tokenPos']; |
1959 endTokenPos = map['endTokenPos']; | 1891 endTokenPos = map['endTokenPos']; |
1960 code = _convertNull(map['code']); | 1892 code = _convertNull(map['code']); |
1961 unoptimizedCode = _convertNull(map['unoptimizedCode']); | 1893 unoptimizedCode = _convertNull(map['unoptimizedCode']); |
1962 isOptimizable = map['optimizable']; | 1894 isOptimizable = map['optimizable']; |
1963 isInlinable = map['inlinable']; | 1895 isInlinable = map['inlinable']; |
1964 deoptimizations = map['deoptimizations']; | 1896 deoptimizations = map['deoptimizations']; |
1965 usageCounter = map['usageCounter']; | 1897 usageCounter = map['usageCounter']; |
1966 | |
1967 } | 1898 } |
1968 } | 1899 } |
1969 | 1900 |
1970 | 1901 |
1971 class Field extends ServiceObject { | 1902 class Field extends ServiceObject { |
1972 @observable var /* Library or Class */ owner; | 1903 @observable var /* Library or Class */ owner; |
1973 @observable Instance declaredType; | 1904 @observable Instance declaredType; |
1974 @observable bool isStatic; | 1905 @observable bool isStatic; |
1975 @observable bool isFinal; | 1906 @observable bool isFinal; |
1976 @observable bool isConst; | 1907 @observable bool isConst; |
(...skipping 222 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2199 } | 2130 } |
2200 | 2131 |
2201 void _applyHitsToLines() { | 2132 void _applyHitsToLines() { |
2202 for (var line in lines) { | 2133 for (var line in lines) { |
2203 var hits = _hits[line.line]; | 2134 var hits = _hits[line.line]; |
2204 line.hits = hits; | 2135 line.hits = hits; |
2205 } | 2136 } |
2206 } | 2137 } |
2207 } | 2138 } |
2208 | 2139 |
2209 class CodeTick { | |
2210 final int address; | |
2211 final int exclusiveTicks; | |
2212 final int inclusiveTicks; | |
2213 CodeTick(this.address, this.exclusiveTicks, this.inclusiveTicks); | |
2214 } | |
2215 | |
2216 class PcDescriptor extends Observable { | 2140 class PcDescriptor extends Observable { |
2217 final int pcOffset; | 2141 final int pcOffset; |
2218 @reflectable final int deoptId; | 2142 @reflectable final int deoptId; |
2219 @reflectable final int tokenPos; | 2143 @reflectable final int tokenPos; |
2220 @reflectable final int tryIndex; | 2144 @reflectable final int tryIndex; |
2221 @reflectable final String kind; | 2145 @reflectable final String kind; |
2222 @observable Script script; | 2146 @observable Script script; |
2223 @observable String formattedLine; | 2147 @observable String formattedLine; |
2224 PcDescriptor(this.pcOffset, this.deoptId, this.tokenPos, this.tryIndex, | 2148 PcDescriptor(this.pcOffset, this.deoptId, this.tokenPos, this.tryIndex, |
2225 this.kind); | 2149 this.kind); |
(...skipping 123 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2349 | 2273 |
2350 class CodeInstruction extends Observable { | 2274 class CodeInstruction extends Observable { |
2351 @observable final int address; | 2275 @observable final int address; |
2352 @observable final int pcOffset; | 2276 @observable final int pcOffset; |
2353 @observable final String machine; | 2277 @observable final String machine; |
2354 @observable final String human; | 2278 @observable final String human; |
2355 @observable CodeInstruction jumpTarget; | 2279 @observable CodeInstruction jumpTarget; |
2356 @reflectable List<PcDescriptor> descriptors = | 2280 @reflectable List<PcDescriptor> descriptors = |
2357 new ObservableList<PcDescriptor>(); | 2281 new ObservableList<PcDescriptor>(); |
2358 | 2282 |
2359 static String formatPercent(num a, num total) { | |
2360 var percent = 100.0 * (a / total); | |
2361 return '${percent.toStringAsFixed(2)}%'; | |
2362 } | |
2363 | |
2364 CodeInstruction(this.address, this.pcOffset, this.machine, this.human); | 2283 CodeInstruction(this.address, this.pcOffset, this.machine, this.human); |
2365 | 2284 |
2366 @reflectable bool get isComment => address == 0; | 2285 @reflectable bool get isComment => address == 0; |
2367 @reflectable bool get hasDescriptors => descriptors.length > 0; | 2286 @reflectable bool get hasDescriptors => descriptors.length > 0; |
2368 | 2287 |
2369 @reflectable String formattedAddress() { | |
2370 if (address == 0) { | |
2371 return ''; | |
2372 } | |
2373 return '0x${address.toRadixString(16)}'; | |
2374 } | |
2375 | |
2376 @reflectable String formattedInclusive(Code code) { | |
2377 if (code == null) { | |
2378 return ''; | |
2379 } | |
2380 var tick = code.addressTicks[address]; | |
2381 if (tick == null) { | |
2382 return ''; | |
2383 } | |
2384 // Don't show inclusive ticks if they are the same as exclusive ticks. | |
2385 if (tick.inclusiveTicks == tick.exclusiveTicks) { | |
2386 return ''; | |
2387 } | |
2388 var pcent = formatPercent(tick.inclusiveTicks, code.totalSamplesInProfile); | |
2389 return '$pcent (${tick.inclusiveTicks})'; | |
2390 } | |
2391 | |
2392 @reflectable String formattedExclusive(Code code) { | |
2393 if (code == null) { | |
2394 return ''; | |
2395 } | |
2396 var tick = code.addressTicks[address]; | |
2397 if (tick == null) { | |
2398 return ''; | |
2399 } | |
2400 var pcent = formatPercent(tick.exclusiveTicks, code.totalSamplesInProfile); | |
2401 return '$pcent (${tick.exclusiveTicks})'; | |
2402 } | |
2403 | |
2404 bool _isJumpInstruction() { | 2288 bool _isJumpInstruction() { |
2405 return human.startsWith('j'); | 2289 return human.startsWith('j'); |
2406 } | 2290 } |
2407 | 2291 |
2408 int _getJumpAddress() { | 2292 int _getJumpAddress() { |
2409 assert(_isJumpInstruction()); | 2293 assert(_isJumpInstruction()); |
2410 var chunks = human.split(' '); | 2294 var chunks = human.split(' '); |
2411 if (chunks.length != 2) { | 2295 if (chunks.length != 2) { |
2412 // We expect jump instructions to be of the form 'j.. address'. | 2296 // We expect jump instructions to be of the form 'j.. address'. |
2413 return 0; | 2297 return 0; |
2414 } | 2298 } |
2415 var address = chunks[1]; | 2299 var address = chunks[1]; |
2416 if (address.startsWith('0x')) { | 2300 if (address.startsWith('0x')) { |
2417 // Chop off the 0x. | 2301 // Chop off the 0x. |
2418 address = address.substring(2); | 2302 address = address.substring(2); |
2419 } | 2303 } |
2420 try { | 2304 try { |
2421 return int.parse(address, radix:16); | 2305 return int.parse(address, radix:16); |
2422 } catch (_) { | 2306 } catch (_) { |
2423 return 0; | 2307 return 0; |
2424 } | 2308 } |
2425 } | 2309 } |
2426 | 2310 |
2427 void _resolveJumpTarget(List<CodeInstruction> instructions) { | 2311 void _resolveJumpTarget(List<CodeInstruction> instructions) { |
2428 if (!_isJumpInstruction()) { | 2312 if (!_isJumpInstruction()) { |
2429 return; | 2313 return; |
2430 } | 2314 } |
2431 int address = _getJumpAddress(); | 2315 int address = _getJumpAddress(); |
2432 if (address == 0) { | 2316 if (address == 0) { |
2433 // Could not determine jump address. | |
2434 Logger.root.severe('Could not determine jump address for $human'); | |
2435 return; | 2317 return; |
2436 } | 2318 } |
2437 for (var i = 0; i < instructions.length; i++) { | 2319 for (var i = 0; i < instructions.length; i++) { |
2438 var instruction = instructions[i]; | 2320 var instruction = instructions[i]; |
2439 if (instruction.address == address) { | 2321 if (instruction.address == address) { |
2440 jumpTarget = instruction; | 2322 jumpTarget = instruction; |
2441 return; | 2323 return; |
2442 } | 2324 } |
2443 } | 2325 } |
2444 Logger.root.severe( | |
2445 'Could not find instruction at ${address.toRadixString(16)}'); | |
2446 } | 2326 } |
2447 } | 2327 } |
2448 | 2328 |
2449 class CodeKind { | 2329 class CodeKind { |
2450 final _value; | 2330 final _value; |
2451 const CodeKind._internal(this._value); | 2331 const CodeKind._internal(this._value); |
2452 String toString() => '$_value'; | 2332 String toString() => '$_value'; |
2453 | 2333 |
2454 static CodeKind fromString(String s) { | 2334 static CodeKind fromString(String s) { |
2455 if (s == 'Native') { | 2335 if (s == 'Native') { |
(...skipping 10 matching lines...) Expand all Loading... |
2466 Logger.root.warning('Unknown code kind $s'); | 2346 Logger.root.warning('Unknown code kind $s'); |
2467 throw new FallThroughError(); | 2347 throw new FallThroughError(); |
2468 } | 2348 } |
2469 static const Native = const CodeKind._internal('Native'); | 2349 static const Native = const CodeKind._internal('Native'); |
2470 static const Dart = const CodeKind._internal('Dart'); | 2350 static const Dart = const CodeKind._internal('Dart'); |
2471 static const Collected = const CodeKind._internal('Collected'); | 2351 static const Collected = const CodeKind._internal('Collected'); |
2472 static const Reused = const CodeKind._internal('Reused'); | 2352 static const Reused = const CodeKind._internal('Reused'); |
2473 static const Tag = const CodeKind._internal('Tag'); | 2353 static const Tag = const CodeKind._internal('Tag'); |
2474 } | 2354 } |
2475 | 2355 |
2476 class CodeCallCount { | 2356 class CodeInlineInterval { |
2477 final Code code; | 2357 final int start; |
2478 final int count; | 2358 final int end; |
2479 CodeCallCount(this.code, this.count); | 2359 final List<ServiceFunction> functions = new List<ServiceFunction>(); |
2480 } | 2360 bool contains(int pc) => (pc >= start) && (pc < end); |
2481 | 2361 CodeInlineInterval(this.start, this.end); |
2482 class CodeTrieNode { | |
2483 final Code code; | |
2484 final int count; | |
2485 final children = new List<CodeTrieNode>(); | |
2486 int summedChildCount = 0; | |
2487 CodeTrieNode(this.code, this.count); | |
2488 } | 2362 } |
2489 | 2363 |
2490 class Code extends ServiceObject { | 2364 class Code extends ServiceObject { |
2491 @observable CodeKind kind; | 2365 @observable CodeKind kind; |
2492 @observable int totalSamplesInProfile = 0; | |
2493 @reflectable int exclusiveTicks = 0; | |
2494 @reflectable int inclusiveTicks = 0; | |
2495 @reflectable int startAddress = 0; | |
2496 @reflectable int endAddress = 0; | |
2497 @reflectable final callers = new List<CodeCallCount>(); | |
2498 @reflectable final callees = new List<CodeCallCount>(); | |
2499 @reflectable final instructions = new ObservableList<CodeInstruction>(); | |
2500 @reflectable final addressTicks = new ObservableMap<int, CodeTick>(); | |
2501 @observable String formattedInclusiveTicks = ''; | |
2502 @observable String formattedExclusiveTicks = ''; | |
2503 @observable Instance objectPool; | 2366 @observable Instance objectPool; |
2504 @observable ServiceFunction function; | 2367 @observable ServiceFunction function; |
2505 @observable Script script; | 2368 @observable Script script; |
2506 @observable bool isOptimized = false; | 2369 @observable bool isOptimized = false; |
2507 | 2370 @reflectable int startAddress = 0; |
| 2371 @reflectable int endAddress = 0; |
| 2372 @reflectable final instructions = new ObservableList<CodeInstruction>(); |
| 2373 @observable ProfileCode profile; |
| 2374 final List<CodeInlineInterval> inlineIntervals = |
| 2375 new List<CodeInlineInterval>(); |
| 2376 final ObservableList<ServiceFunction> inlinedFunctions = |
| 2377 new ObservableList<ServiceFunction>(); |
2508 bool get canCache => true; | 2378 bool get canCache => true; |
2509 bool get immutable => true; | 2379 bool get immutable => true; |
2510 | 2380 |
2511 Code._empty(ServiceObjectOwner owner) : super._empty(owner); | 2381 Code._empty(ServiceObjectOwner owner) : super._empty(owner); |
2512 | 2382 |
2513 // Reset all data associated with a profile. | |
2514 void resetProfileData() { | |
2515 totalSamplesInProfile = 0; | |
2516 exclusiveTicks = 0; | |
2517 inclusiveTicks = 0; | |
2518 formattedInclusiveTicks = ''; | |
2519 formattedExclusiveTicks = ''; | |
2520 callers.clear(); | |
2521 callees.clear(); | |
2522 addressTicks.clear(); | |
2523 } | |
2524 | |
2525 void _updateDescriptors(Script script) { | 2383 void _updateDescriptors(Script script) { |
2526 this.script = script; | 2384 this.script = script; |
2527 for (var instruction in instructions) { | 2385 for (var instruction in instructions) { |
2528 for (var descriptor in instruction.descriptors) { | 2386 for (var descriptor in instruction.descriptors) { |
2529 descriptor.processScript(script); | 2387 descriptor.processScript(script); |
2530 } | 2388 } |
2531 } | 2389 } |
2532 } | 2390 } |
2533 | 2391 |
2534 void loadScript() { | 2392 void loadScript() { |
(...skipping 28 matching lines...) Expand all Loading... |
2563 /// a [ServiceError]. | 2421 /// a [ServiceError]. |
2564 Future<ServiceObject> reload() { | 2422 Future<ServiceObject> reload() { |
2565 assert(kind != null); | 2423 assert(kind != null); |
2566 if (kind == CodeKind.Dart) { | 2424 if (kind == CodeKind.Dart) { |
2567 // We only reload Dart code. | 2425 // We only reload Dart code. |
2568 return super.reload(); | 2426 return super.reload(); |
2569 } | 2427 } |
2570 return new Future.value(this); | 2428 return new Future.value(this); |
2571 } | 2429 } |
2572 | 2430 |
2573 void _resolveCalls(List<CodeCallCount> calls, List data, List<Code> codes) { | |
2574 // Assert that this has been cleared. | |
2575 assert(calls.length == 0); | |
2576 // Resolve. | |
2577 for (var i = 0; i < data.length; i += 2) { | |
2578 var index = int.parse(data[i]); | |
2579 var count = int.parse(data[i + 1]); | |
2580 assert(index >= 0); | |
2581 assert(index < codes.length); | |
2582 calls.add(new CodeCallCount(codes[index], count)); | |
2583 } | |
2584 // Sort to descending count order. | |
2585 calls.sort((a, b) => b.count - a.count); | |
2586 } | |
2587 | |
2588 | |
2589 static String formatPercent(num a, num total) { | |
2590 var percent = 100.0 * (a / total); | |
2591 return '${percent.toStringAsFixed(2)}%'; | |
2592 } | |
2593 | |
2594 void updateProfileData(Map profileData, | |
2595 List<Code> codeTable, | |
2596 int sampleCount) { | |
2597 // Assert we are handed profile data for this code object. | |
2598 assert(profileData['code'] == this); | |
2599 totalSamplesInProfile = sampleCount; | |
2600 inclusiveTicks = int.parse(profileData['inclusive_ticks']); | |
2601 exclusiveTicks = int.parse(profileData['exclusive_ticks']); | |
2602 _resolveCalls(callers, profileData['callers'], codeTable); | |
2603 _resolveCalls(callees, profileData['callees'], codeTable); | |
2604 var ticks = profileData['ticks']; | |
2605 if (ticks != null) { | |
2606 _processTicks(ticks); | |
2607 } | |
2608 formattedInclusiveTicks = | |
2609 '${formatPercent(inclusiveTicks, totalSamplesInProfile)} ' | |
2610 '($inclusiveTicks)'; | |
2611 formattedExclusiveTicks = | |
2612 '${formatPercent(exclusiveTicks, totalSamplesInProfile)} ' | |
2613 '($exclusiveTicks)'; | |
2614 } | |
2615 | |
2616 void _update(ObservableMap m, bool mapIsRef) { | 2431 void _update(ObservableMap m, bool mapIsRef) { |
2617 name = m['name']; | 2432 name = m['name']; |
2618 vmName = (m.containsKey('vmName') ? m['vmName'] : name); | 2433 vmName = (m.containsKey('vmName') ? m['vmName'] : name); |
2619 isOptimized = m['optimized'] != null ? m['optimized'] : false; | 2434 isOptimized = m['optimized'] != null ? m['optimized'] : false; |
2620 kind = CodeKind.fromString(m['kind']); | 2435 kind = CodeKind.fromString(m['kind']); |
2621 startAddress = int.parse(m['start'], radix:16); | 2436 startAddress = int.parse(m['start'], radix:16); |
2622 endAddress = int.parse(m['end'], radix:16); | 2437 endAddress = int.parse(m['end'], radix:16); |
2623 function = isolate.getFromMap(m['function']); | 2438 function = isolate.getFromMap(m['function']); |
| 2439 if (mapIsRef) { |
| 2440 return; |
| 2441 } |
| 2442 _loaded = true; |
2624 objectPool = isolate.getFromMap(m['objectPool']); | 2443 objectPool = isolate.getFromMap(m['objectPool']); |
2625 var disassembly = m['disassembly']; | 2444 var disassembly = m['disassembly']; |
2626 if (disassembly != null) { | 2445 if (disassembly != null) { |
2627 _processDisassembly(disassembly); | 2446 _processDisassembly(disassembly); |
2628 } | 2447 } |
2629 var descriptors = m['descriptors']; | 2448 var descriptors = m['descriptors']; |
2630 if (descriptors != null) { | 2449 if (descriptors != null) { |
2631 descriptors = descriptors['members']; | 2450 descriptors = descriptors['members']; |
2632 _processDescriptors(descriptors); | 2451 _processDescriptors(descriptors); |
2633 } | 2452 } |
2634 // We are loaded if we have instructions or are not Dart code. | |
2635 _loaded = (instructions.length != 0) || (kind != CodeKind.Dart); | |
2636 hasDisassembly = (instructions.length != 0) && (kind == CodeKind.Dart); | 2453 hasDisassembly = (instructions.length != 0) && (kind == CodeKind.Dart); |
| 2454 inlinedFunctions.clear(); |
| 2455 var inlinedFunctionsTable = m['inlinedFunctions']; |
| 2456 var inlinedIntervals = m['inlinedIntervals']; |
| 2457 if (inlinedFunctionsTable != null) { |
| 2458 // Iterate and upgrade each ServiceFunction. |
| 2459 for (var i = 0; i < inlinedFunctionsTable.length; i++) { |
| 2460 // Upgrade each function and set it back in the list. |
| 2461 var func = isolate.getFromMap(inlinedFunctionsTable[i]); |
| 2462 inlinedFunctionsTable[i] = func; |
| 2463 if (!inlinedFunctions.contains(func)) { |
| 2464 inlinedFunctions.add(func); |
| 2465 } |
| 2466 } |
| 2467 } |
| 2468 if ((inlinedIntervals == null) || (inlinedFunctionsTable == null)) { |
| 2469 // No inline information. |
| 2470 inlineIntervals.clear(); |
| 2471 return; |
| 2472 } |
| 2473 _processInline(inlinedFunctionsTable, inlinedIntervals); |
| 2474 } |
| 2475 |
| 2476 CodeInlineInterval findInterval(int pc) { |
| 2477 for (var i = 0; i < inlineIntervals.length; i++) { |
| 2478 var interval = inlineIntervals[i]; |
| 2479 if (interval.contains(pc)) { |
| 2480 return interval; |
| 2481 } |
| 2482 } |
| 2483 return null; |
| 2484 } |
| 2485 |
| 2486 void _processInline(List<ServiceFunction> inlinedFunctionsTable, |
| 2487 List<List<int>> inlinedIntervals) { |
| 2488 for (var i = 0; i < inlinedIntervals.length; i++) { |
| 2489 var inlinedInterval = inlinedIntervals[i]; |
| 2490 var start = inlinedInterval[0] + startAddress; |
| 2491 var end = inlinedInterval[1] + startAddress; |
| 2492 var codeInlineInterval = new CodeInlineInterval(start, end); |
| 2493 for (var i = 2; i < inlinedInterval.length - 1; i++) { |
| 2494 var inline_id = inlinedInterval[i]; |
| 2495 if (inline_id < 0) { |
| 2496 continue; |
| 2497 } |
| 2498 var function = inlinedFunctionsTable[inline_id]; |
| 2499 codeInlineInterval.functions.add(function); |
| 2500 } |
| 2501 inlineIntervals.add(codeInlineInterval); |
| 2502 } |
2637 } | 2503 } |
2638 | 2504 |
2639 @observable bool hasDisassembly = false; | 2505 @observable bool hasDisassembly = false; |
2640 | 2506 |
2641 void _processDisassembly(List<String> disassembly){ | 2507 void _processDisassembly(List<String> disassembly){ |
2642 assert(disassembly != null); | 2508 assert(disassembly != null); |
2643 instructions.clear(); | 2509 instructions.clear(); |
2644 assert((disassembly.length % 3) == 0); | 2510 assert((disassembly.length % 3) == 0); |
2645 for (var i = 0; i < disassembly.length; i += 3) { | 2511 for (var i = 0; i < disassembly.length; i += 3) { |
2646 var address = 0; // Assume code comment. | 2512 var address = 0; // Assume code comment. |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2680 Logger.root.warning( | 2546 Logger.root.warning( |
2681 'Could not find instruction with pc descriptor address: $address'); | 2547 'Could not find instruction with pc descriptor address: $address'); |
2682 } | 2548 } |
2683 | 2549 |
2684 void _processDescriptors(List<Map> descriptors) { | 2550 void _processDescriptors(List<Map> descriptors) { |
2685 for (Map descriptor in descriptors) { | 2551 for (Map descriptor in descriptors) { |
2686 _processDescriptor(descriptor); | 2552 _processDescriptor(descriptor); |
2687 } | 2553 } |
2688 } | 2554 } |
2689 | 2555 |
2690 void _processTicks(List<String> profileTicks) { | |
2691 assert(profileTicks != null); | |
2692 assert((profileTicks.length % 3) == 0); | |
2693 for (var i = 0; i < profileTicks.length; i += 3) { | |
2694 var address = int.parse(profileTicks[i], radix:16); | |
2695 var exclusive = int.parse(profileTicks[i + 1]); | |
2696 var inclusive = int.parse(profileTicks[i + 2]); | |
2697 var tick = new CodeTick(address, exclusive, inclusive); | |
2698 addressTicks[address] = tick; | |
2699 } | |
2700 } | |
2701 | |
2702 /// Returns true if [address] is contained inside [this]. | 2556 /// Returns true if [address] is contained inside [this]. |
2703 bool contains(int address) { | 2557 bool contains(int address) { |
2704 return (address >= startAddress) && (address < endAddress); | 2558 return (address >= startAddress) && (address < endAddress); |
2705 } | 2559 } |
2706 | 2560 |
2707 /// Sum all caller counts. | |
2708 int sumCallersCount() => _sumCallCount(callers); | |
2709 /// Specific caller count. | |
2710 int callersCount(Code code) => _callCount(callers, code); | |
2711 /// Sum of callees count. | |
2712 int sumCalleesCount() => _sumCallCount(callees); | |
2713 /// Specific callee count. | |
2714 int calleesCount(Code code) => _callCount(callees, code); | |
2715 | |
2716 int _sumCallCount(List<CodeCallCount> calls) { | |
2717 var sum = 0; | |
2718 for (CodeCallCount caller in calls) { | |
2719 sum += caller.count; | |
2720 } | |
2721 return sum; | |
2722 } | |
2723 | |
2724 int _callCount(List<CodeCallCount> calls, Code code) { | |
2725 for (CodeCallCount caller in calls) { | |
2726 if (caller.code == code) { | |
2727 return caller.count; | |
2728 } | |
2729 } | |
2730 return 0; | |
2731 } | |
2732 | |
2733 @reflectable bool get isDartCode => kind == CodeKind.Dart; | 2561 @reflectable bool get isDartCode => kind == CodeKind.Dart; |
2734 } | 2562 } |
2735 | 2563 |
2736 | 2564 |
2737 class SocketKind { | 2565 class SocketKind { |
2738 final _value; | 2566 final _value; |
2739 const SocketKind._internal(this._value); | 2567 const SocketKind._internal(this._value); |
2740 String toString() => '$_value'; | 2568 String toString() => '$_value'; |
2741 | 2569 |
2742 static SocketKind fromString(String s) { | 2570 static SocketKind fromString(String s) { |
(...skipping 238 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2981 var v = list[i]; | 2809 var v = list[i]; |
2982 if ((v is ObservableMap) && _isServiceMap(v)) { | 2810 if ((v is ObservableMap) && _isServiceMap(v)) { |
2983 list[i] = owner.getFromMap(v); | 2811 list[i] = owner.getFromMap(v); |
2984 } else if (v is ObservableList) { | 2812 } else if (v is ObservableList) { |
2985 _upgradeObservableList(v, owner); | 2813 _upgradeObservableList(v, owner); |
2986 } else if (v is ObservableMap) { | 2814 } else if (v is ObservableMap) { |
2987 _upgradeObservableMap(v, owner); | 2815 _upgradeObservableMap(v, owner); |
2988 } | 2816 } |
2989 } | 2817 } |
2990 } | 2818 } |
OLD | NEW |