| 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 366 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 377 // TODO(koda): Do we care about GC events in VM isolate? | 377 // TODO(koda): Do we care about GC events in VM isolate? |
| 378 Logger.root.severe( | 378 Logger.root.severe( |
| 379 'Ignoring event with unknown isolate id: $owningIsolateId'); | 379 'Ignoring event with unknown isolate id: $owningIsolateId'); |
| 380 } else { | 380 } else { |
| 381 var event = new ServiceObject._fromMap(owningIsolate, map); | 381 var event = new ServiceObject._fromMap(owningIsolate, map); |
| 382 events.add(event); | 382 events.add(event); |
| 383 } | 383 } |
| 384 }); | 384 }); |
| 385 } | 385 } |
| 386 | 386 |
| 387 static final RegExp _currentIsolateMatcher = new RegExp(r'isolates/\d+'); | |
| 388 static final RegExp _currentObjectMatcher = new RegExp(r'isolates/\d+/'); | |
| 389 static final String _isolatesPrefix = 'isolates/'; | |
| 390 | |
| 391 String _parseObjectId(String id) { | |
| 392 Match m = _currentObjectMatcher.matchAsPrefix(id); | |
| 393 if (m == null) { | |
| 394 return null; | |
| 395 } | |
| 396 return m.input.substring(m.end); | |
| 397 } | |
| 398 | |
| 399 String _parseIsolateId(String id) { | |
| 400 Match m = _currentIsolateMatcher.matchAsPrefix(id); | |
| 401 if (m == null) { | |
| 402 return ''; | |
| 403 } | |
| 404 return id.substring(0, m.end); | |
| 405 } | |
| 406 | |
| 407 Map<String,ServiceObject> _cache = new Map<String,ServiceObject>(); | 387 Map<String,ServiceObject> _cache = new Map<String,ServiceObject>(); |
| 408 Map<String,Isolate> _isolateCache = new Map<String,Isolate>(); | 388 Map<String,Isolate> _isolateCache = new Map<String,Isolate>(); |
| 409 | 389 |
| 410 ServiceObject getFromMap(ObservableMap map) { | 390 ServiceObject getFromMap(ObservableMap map) { |
| 411 throw new UnimplementedError(); | 391 throw new UnimplementedError(); |
| 412 } | 392 } |
| 413 | 393 |
| 414 // Note that this function does not reload the isolate if it found | 394 // Note that this function does not reload the isolate if it found |
| 415 // in the cache. | 395 // in the cache. |
| 416 Future<ServiceObject> getIsolate(String isolateId) { | 396 Future<ServiceObject> getIsolate(String isolateId) { |
| (...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 497 }, test: (e) => e is ServiceError).catchError((exception) { | 477 }, test: (e) => e is ServiceError).catchError((exception) { |
| 498 | 478 |
| 499 // ServiceException, forward to VM's ServiceException stream. | 479 // ServiceException, forward to VM's ServiceException stream. |
| 500 exceptions.add(exception); | 480 exceptions.add(exception); |
| 501 return new Future.error(exception); | 481 return new Future.error(exception); |
| 502 }, test: (e) => e is ServiceException); | 482 }, test: (e) => e is ServiceException); |
| 503 } | 483 } |
| 504 | 484 |
| 505 Future<ServiceObject> invokeRpc(String method, Map params) { | 485 Future<ServiceObject> invokeRpc(String method, Map params) { |
| 506 return invokeRpcNoUpgrade(method, params).then((ObservableMap response) { | 486 return invokeRpcNoUpgrade(method, params).then((ObservableMap response) { |
| 507 » var obj = new ServiceObject._fromMap(this, response); | 487 var obj = new ServiceObject._fromMap(this, response); |
| 508 if (obj.canCache) { | 488 if ((obj != null) && obj.canCache) { |
| 509 _cache.putIfAbsent(id, () => obj); | 489 String objId = obj.id; |
| 510 } | 490 _cache.putIfAbsent(objId, () => obj); |
| 511 return obj; | 491 } |
| 492 return obj; |
| 512 }); | 493 }); |
| 513 } | 494 } |
| 514 | 495 |
| 515 Future<ObservableMap> _fetchDirect() { | 496 Future<ObservableMap> _fetchDirect() { |
| 516 return invokeRpcNoUpgrade('getVM', {}); | 497 return invokeRpcNoUpgrade('getVM', {}); |
| 517 } | 498 } |
| 518 | 499 |
| 519 Future<ServiceObject> getFlagList() { | 500 Future<ServiceObject> getFlagList() { |
| 520 return invokeRpc('getFlagList', {}); | 501 return invokeRpc('getFlagList', {}); |
| 521 } | 502 } |
| (...skipping 185 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 707 @observable bool loading = true; | 688 @observable bool loading = true; |
| 708 @observable bool ioEnabled = false; | 689 @observable bool ioEnabled = false; |
| 709 | 690 |
| 710 Map<String,ServiceObject> _cache = new Map<String,ServiceObject>(); | 691 Map<String,ServiceObject> _cache = new Map<String,ServiceObject>(); |
| 711 final TagProfile tagProfile = new TagProfile(20); | 692 final TagProfile tagProfile = new TagProfile(20); |
| 712 | 693 |
| 713 Isolate._empty(ServiceObjectOwner owner) : super._empty(owner) { | 694 Isolate._empty(ServiceObjectOwner owner) : super._empty(owner) { |
| 714 assert(owner is VM); | 695 assert(owner is VM); |
| 715 } | 696 } |
| 716 | 697 |
| 717 static const TAG_ROOT_ID = 'code/tag-0'; | 698 void resetCachedProfileData() { |
| 718 | |
| 719 /// Returns the Code object for the root tag. | |
| 720 Code tagRoot() { | |
| 721 // TODO(turnidge): Use get() here instead? | |
| 722 return _cache[TAG_ROOT_ID]; | |
| 723 } | |
| 724 | |
| 725 void processProfile(ServiceMap profile) { | |
| 726 assert(profile.type == 'CpuProfile'); | |
| 727 var codeTable = new List<Code>(); | |
| 728 var codeRegions = profile['codes']; | |
| 729 for (var codeRegion in codeRegions) { | |
| 730 Code code = codeRegion['code']; | |
| 731 assert(code != null); | |
| 732 codeTable.add(code); | |
| 733 } | |
| 734 _resetProfileData(); | |
| 735 _updateProfileData(profile, codeTable); | |
| 736 var exclusiveTrie = profile['exclusive_trie']; | |
| 737 if (exclusiveTrie != null) { | |
| 738 profileTrieRoot = _processProfileTrie(exclusiveTrie, codeTable); | |
| 739 } | |
| 740 } | |
| 741 | |
| 742 void _resetProfileData() { | |
| 743 _cache.values.forEach((value) { | 699 _cache.values.forEach((value) { |
| 744 if (value is Code) { | 700 if (value is Code) { |
| 745 Code code = value; | 701 Code code = value; |
| 746 code.resetProfileData(); | 702 code.profile = null; |
| 747 } | 703 } else if (value is ServiceFunction) { |
| 748 }); | 704 ServiceFunction function = value; |
| 749 } | 705 function.profile = null; |
| 750 | 706 } |
| 751 void _updateProfileData(ServiceMap profile, List<Code> codeTable) { | 707 }); |
| 752 var codeRegions = profile['codes']; | |
| 753 var sampleCount = profile['samples']; | |
| 754 for (var codeRegion in codeRegions) { | |
| 755 Code code = codeRegion['code']; | |
| 756 code.updateProfileData(codeRegion, codeTable, sampleCount); | |
| 757 } | |
| 758 } | 708 } |
| 759 | 709 |
| 760 /// Fetches and builds the class hierarchy for this isolate. Returns the | 710 /// Fetches and builds the class hierarchy for this isolate. Returns the |
| 761 /// Object class object. | 711 /// Object class object. |
| 762 Future<Class> getClassHierarchy() { | 712 Future<Class> getClassHierarchy() { |
| 763 return invokeRpc('getClassList', {}) | 713 return invokeRpc('getClassList', {}) |
| 764 .then(_loadClasses) | 714 .then(_loadClasses) |
| 765 .then(_buildClassHierarchy); | 715 .then(_buildClassHierarchy); |
| 766 } | 716 } |
| 767 | 717 |
| (...skipping 23 matching lines...) Expand all Loading... |
| 791 } | 741 } |
| 792 } | 742 } |
| 793 assert(objectClass != null); | 743 assert(objectClass != null); |
| 794 return new Future.value(objectClass); | 744 return new Future.value(objectClass); |
| 795 } | 745 } |
| 796 | 746 |
| 797 ServiceObject getFromMap(ObservableMap map) { | 747 ServiceObject getFromMap(ObservableMap map) { |
| 798 if (map == null) { | 748 if (map == null) { |
| 799 return null; | 749 return null; |
| 800 } | 750 } |
| 801 String id = map['id']; | 751 String mapId = map['id']; |
| 802 var obj = _cache[id]; | 752 var obj = (mapId != null) ? _cache[mapId] : null; |
| 803 if (obj != null) { | 753 if (obj != null) { |
| 804 // Consider calling update when map is not a reference. | 754 // Consider calling update when map is not a reference. |
| 805 return obj; | 755 return obj; |
| 806 } | 756 } |
| 807 // Build the object from the map directly. | 757 // Build the object from the map directly. |
| 808 obj = new ServiceObject._fromMap(this, map); | 758 obj = new ServiceObject._fromMap(this, map); |
| 809 if (obj != null && obj.canCache) { | 759 if ((obj != null) && obj.canCache) { |
| 810 _cache[id] = obj; | 760 _cache[mapId] = obj; |
| 811 } | 761 } |
| 812 return obj; | 762 return obj; |
| 813 } | 763 } |
| 814 | 764 |
| 815 Future<ObservableMap> invokeRpcNoUpgrade(String method, Map params) { | 765 Future<ObservableMap> invokeRpcNoUpgrade(String method, Map params) { |
| 816 params['isolateId'] = id; | 766 params['isolateId'] = id; |
| 817 return vm.invokeRpcNoUpgrade(method, params); | 767 return vm.invokeRpcNoUpgrade(method, params); |
| 818 } | 768 } |
| 819 | 769 |
| 820 Future<ServiceObject> invokeRpc(String method, Map params) { | 770 Future<ServiceObject> invokeRpc(String method, Map params) { |
| 821 return invokeRpcNoUpgrade(method, params).then((ObservableMap response) { | 771 return invokeRpcNoUpgrade(method, params).then((ObservableMap response) { |
| 822 var obj = new ServiceObject._fromMap(this, response); | 772 var obj = new ServiceObject._fromMap(this, response); |
| 823 if (obj.canCache) { | 773 if ((obj != null) && obj.canCache) { |
| 824 _cache.putIfAbsent(id, () => obj); | 774 String objId = obj.id; |
| 825 } | 775 _cache.putIfAbsent(objId, () => obj); |
| 826 » return obj; | 776 } |
| 777 return obj; |
| 827 }); | 778 }); |
| 828 } | 779 } |
| 829 | 780 |
| 830 Future<ServiceObject> getObject(String objectId) { | 781 Future<ServiceObject> getObject(String objectId) { |
| 831 assert(objectId != null && objectId != ''); | 782 assert(objectId != null && objectId != ''); |
| 832 var obj = _cache[objectId]; | 783 var obj = _cache[objectId]; |
| 833 if (obj != null) { | 784 if (obj != null) { |
| 834 return obj.reload(); | 785 return obj.reload(); |
| 835 } | 786 } |
| 836 Map params = { | 787 Map params = { |
| (...skipping 135 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 972 | 923 |
| 973 Future<TagProfile> updateTagProfile() { | 924 Future<TagProfile> updateTagProfile() { |
| 974 return isolate.invokeRpcNoUpgrade('getTagProfile', {}).then( | 925 return isolate.invokeRpcNoUpgrade('getTagProfile', {}).then( |
| 975 (ObservableMap map) { | 926 (ObservableMap map) { |
| 976 var seconds = new DateTime.now().millisecondsSinceEpoch / 1000.0; | 927 var seconds = new DateTime.now().millisecondsSinceEpoch / 1000.0; |
| 977 tagProfile._processTagProfile(seconds, map); | 928 tagProfile._processTagProfile(seconds, map); |
| 978 return tagProfile; | 929 return tagProfile; |
| 979 }); | 930 }); |
| 980 } | 931 } |
| 981 | 932 |
| 982 @reflectable CodeTrieNode profileTrieRoot; | |
| 983 // The profile trie is serialized as a list of integers. Each node | |
| 984 // is recreated by consuming some portion of the list. The format is as | |
| 985 // follows: | |
| 986 // [0] index into codeTable of code object. | |
| 987 // [1] tick count (number of times this stack frame occured). | |
| 988 // [2] child node count | |
| 989 // Reading the trie is done by recursively reading the tree depth-first | |
| 990 // pre-order. | |
| 991 CodeTrieNode _processProfileTrie(List<int> data, List<Code> codeTable) { | |
| 992 // Setup state shared across calls to _readTrieNode. | |
| 993 _trieDataCursor = 0; | |
| 994 _trieData = data; | |
| 995 if (_trieData == null) { | |
| 996 return null; | |
| 997 } | |
| 998 if (_trieData.length < 3) { | |
| 999 // Not enough integers for 1 node. | |
| 1000 return null; | |
| 1001 } | |
| 1002 // Read the tree, returns the root node. | |
| 1003 return _readTrieNode(codeTable); | |
| 1004 } | |
| 1005 int _trieDataCursor; | |
| 1006 List<int> _trieData; | |
| 1007 CodeTrieNode _readTrieNode(List<Code> codeTable) { | |
| 1008 // Read index into code table. | |
| 1009 var index = _trieData[_trieDataCursor++]; | |
| 1010 // Lookup code object. | |
| 1011 var code = codeTable[index]; | |
| 1012 // Frame counter. | |
| 1013 var count = _trieData[_trieDataCursor++]; | |
| 1014 // Create node. | |
| 1015 var node = new CodeTrieNode(code, count); | |
| 1016 // Number of children. | |
| 1017 var children = _trieData[_trieDataCursor++]; | |
| 1018 // Recursively read child nodes. | |
| 1019 for (var i = 0; i < children; i++) { | |
| 1020 var child = _readTrieNode(codeTable); | |
| 1021 node.children.add(child); | |
| 1022 node.summedChildCount += child.count; | |
| 1023 } | |
| 1024 return node; | |
| 1025 } | |
| 1026 | |
| 1027 ObservableList<Breakpoint> breakpoints = new ObservableList(); | 933 ObservableList<Breakpoint> breakpoints = new ObservableList(); |
| 1028 | 934 |
| 1029 void _removeBreakpoint(Breakpoint bpt) { | 935 void _removeBreakpoint(Breakpoint bpt) { |
| 1030 var script = bpt.script; | 936 var script = bpt.script; |
| 1031 var tokenPos = bpt.tokenPos; | 937 var tokenPos = bpt.tokenPos; |
| 1032 assert(tokenPos != null); | 938 assert(tokenPos != null); |
| 1033 if (script.loaded) { | 939 if (script.loaded) { |
| 1034 var line = script.tokenToLine(tokenPos); | 940 var line = script.tokenToLine(tokenPos); |
| 1035 assert(line != null); | 941 assert(line != null); |
| 1036 if (script.lines[line - 1] != null) { | 942 if (script.lines[line - 1] != null) { |
| (...skipping 761 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1798 | 1704 |
| 1799 String toString() => 'Context($length)'; | 1705 String toString() => 'Context($length)'; |
| 1800 } | 1706 } |
| 1801 | 1707 |
| 1802 | 1708 |
| 1803 // TODO(koda): Sync this with VM. | 1709 // TODO(koda): Sync this with VM. |
| 1804 class FunctionKind { | 1710 class FunctionKind { |
| 1805 final String _strValue; | 1711 final String _strValue; |
| 1806 FunctionKind._internal(this._strValue); | 1712 FunctionKind._internal(this._strValue); |
| 1807 toString() => _strValue; | 1713 toString() => _strValue; |
| 1808 bool isFake() => [kCollected, kNative, kTag, kReused].contains(this); | 1714 bool isSynthetic() => [kCollected, kNative, kTag, kReused].contains(this); |
| 1809 | 1715 |
| 1810 static FunctionKind fromJSON(String value) { | 1716 static FunctionKind fromJSON(String value) { |
| 1811 switch(value) { | 1717 switch(value) { |
| 1812 case 'kRegularFunction': return kRegularFunction; | 1718 case 'kRegularFunction': return kRegularFunction; |
| 1813 case 'kClosureFunction': return kClosureFunction; | 1719 case 'kClosureFunction': return kClosureFunction; |
| 1814 case 'kGetterFunction': return kGetterFunction; | 1720 case 'kGetterFunction': return kGetterFunction; |
| 1815 case 'kSetterFunction': return kSetterFunction; | 1721 case 'kSetterFunction': return kSetterFunction; |
| 1816 case 'kConstructor': return kConstructor; | 1722 case 'kConstructor': return kConstructor; |
| 1817 case 'kImplicitGetter': return kImplicitGetterFunction; | 1723 case 'kImplicitGetter': return kImplicitGetterFunction; |
| 1818 case 'kImplicitSetter': return kImplicitSetterFunction; | 1724 case 'kImplicitSetter': return kImplicitSetterFunction; |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1857 @observable int endTokenPos; | 1763 @observable int endTokenPos; |
| 1858 @observable Code code; | 1764 @observable Code code; |
| 1859 @observable Code unoptimizedCode; | 1765 @observable Code unoptimizedCode; |
| 1860 @observable bool isOptimizable; | 1766 @observable bool isOptimizable; |
| 1861 @observable bool isInlinable; | 1767 @observable bool isInlinable; |
| 1862 @observable FunctionKind kind; | 1768 @observable FunctionKind kind; |
| 1863 @observable int deoptimizations; | 1769 @observable int deoptimizations; |
| 1864 @observable String qualifiedName; | 1770 @observable String qualifiedName; |
| 1865 @observable int usageCounter; | 1771 @observable int usageCounter; |
| 1866 @observable bool isDart; | 1772 @observable bool isDart; |
| 1773 @observable ProfileFunction profile; |
| 1867 | 1774 |
| 1868 ServiceFunction._empty(ServiceObject owner) : super._empty(owner); | 1775 ServiceFunction._empty(ServiceObject owner) : super._empty(owner); |
| 1869 | 1776 |
| 1870 void _update(ObservableMap map, bool mapIsRef) { | 1777 void _update(ObservableMap map, bool mapIsRef) { |
| 1871 name = map['name']; | 1778 name = map['name']; |
| 1872 vmName = (map.containsKey('vmName') ? map['vmName'] : name); | 1779 vmName = (map.containsKey('vmName') ? map['vmName'] : name); |
| 1873 | 1780 |
| 1874 _upgradeCollection(map, isolate); | 1781 _upgradeCollection(map, isolate); |
| 1875 | 1782 |
| 1876 owningClass = map.containsKey('owningClass') ? map['owningClass'] : null; | 1783 owningClass = map.containsKey('owningClass') ? map['owningClass'] : null; |
| 1877 owningLibrary = map.containsKey('owningLibrary') ? map['owningLibrary'] : nu
ll; | 1784 owningLibrary = map.containsKey('owningLibrary') ? map['owningLibrary'] : nu
ll; |
| 1878 kind = FunctionKind.fromJSON(map['kind']); | 1785 kind = FunctionKind.fromJSON(map['kind']); |
| 1879 isDart = !kind.isFake(); | 1786 isDart = !kind.isSynthetic(); |
| 1880 | 1787 |
| 1881 if (parent == null) { | 1788 if (parent == null) { |
| 1882 qualifiedName = (owningClass != null) ? | 1789 qualifiedName = (owningClass != null) ? |
| 1883 "${owningClass.name}.${name}" : | 1790 "${owningClass.name}.${name}" : |
| 1884 name; | 1791 name; |
| 1885 } else { | 1792 } else { |
| 1886 qualifiedName = "${parent.qualifiedName}.${name}"; | 1793 qualifiedName = "${parent.qualifiedName}.${name}"; |
| 1887 } | 1794 } |
| 1888 | 1795 |
| 1889 if (mapIsRef) { return; } | 1796 if (mapIsRef) { |
| 1797 return; |
| 1798 } |
| 1890 | 1799 |
| 1891 isStatic = map['static']; | 1800 isStatic = map['static']; |
| 1892 isConst = map['const']; | 1801 isConst = map['const']; |
| 1893 parent = map['parent']; | 1802 parent = map['parent']; |
| 1894 script = map['script']; | 1803 script = map['script']; |
| 1895 tokenPos = map['tokenPos']; | 1804 tokenPos = map['tokenPos']; |
| 1896 endTokenPos = map['endTokenPos']; | 1805 endTokenPos = map['endTokenPos']; |
| 1897 code = _convertNull(map['code']); | 1806 code = _convertNull(map['code']); |
| 1898 unoptimizedCode = _convertNull(map['unoptimizedCode']); | 1807 unoptimizedCode = _convertNull(map['unoptimizedCode']); |
| 1899 isOptimizable = map['optimizable']; | 1808 isOptimizable = map['optimizable']; |
| 1900 isInlinable = map['inlinable']; | 1809 isInlinable = map['inlinable']; |
| 1901 deoptimizations = map['deoptimizations']; | 1810 deoptimizations = map['deoptimizations']; |
| 1902 usageCounter = map['usageCounter']; | 1811 usageCounter = map['usageCounter']; |
| 1903 | |
| 1904 } | 1812 } |
| 1905 } | 1813 } |
| 1906 | 1814 |
| 1907 | 1815 |
| 1908 class Field extends ServiceObject { | 1816 class Field extends ServiceObject { |
| 1909 @observable var /* Library or Class */ owner; | 1817 @observable var /* Library or Class */ owner; |
| 1910 @observable Instance declaredType; | 1818 @observable Instance declaredType; |
| 1911 @observable bool isStatic; | 1819 @observable bool isStatic; |
| 1912 @observable bool isFinal; | 1820 @observable bool isFinal; |
| 1913 @observable bool isConst; | 1821 @observable bool isConst; |
| (...skipping 222 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2136 } | 2044 } |
| 2137 | 2045 |
| 2138 void _applyHitsToLines() { | 2046 void _applyHitsToLines() { |
| 2139 for (var line in lines) { | 2047 for (var line in lines) { |
| 2140 var hits = _hits[line.line]; | 2048 var hits = _hits[line.line]; |
| 2141 line.hits = hits; | 2049 line.hits = hits; |
| 2142 } | 2050 } |
| 2143 } | 2051 } |
| 2144 } | 2052 } |
| 2145 | 2053 |
| 2146 class CodeTick { | |
| 2147 final int address; | |
| 2148 final int exclusiveTicks; | |
| 2149 final int inclusiveTicks; | |
| 2150 CodeTick(this.address, this.exclusiveTicks, this.inclusiveTicks); | |
| 2151 } | |
| 2152 | |
| 2153 class PcDescriptor extends Observable { | 2054 class PcDescriptor extends Observable { |
| 2154 final int pcOffset; | 2055 final int pcOffset; |
| 2155 @reflectable final int deoptId; | 2056 @reflectable final int deoptId; |
| 2156 @reflectable final int tokenPos; | 2057 @reflectable final int tokenPos; |
| 2157 @reflectable final int tryIndex; | 2058 @reflectable final int tryIndex; |
| 2158 @reflectable final String kind; | 2059 @reflectable final String kind; |
| 2159 @observable Script script; | 2060 @observable Script script; |
| 2160 @observable String formattedLine; | 2061 @observable String formattedLine; |
| 2161 PcDescriptor(this.pcOffset, this.deoptId, this.tokenPos, this.tryIndex, | 2062 PcDescriptor(this.pcOffset, this.deoptId, this.tokenPos, this.tryIndex, |
| 2162 this.kind); | 2063 this.kind); |
| (...skipping 123 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2286 | 2187 |
| 2287 class CodeInstruction extends Observable { | 2188 class CodeInstruction extends Observable { |
| 2288 @observable final int address; | 2189 @observable final int address; |
| 2289 @observable final int pcOffset; | 2190 @observable final int pcOffset; |
| 2290 @observable final String machine; | 2191 @observable final String machine; |
| 2291 @observable final String human; | 2192 @observable final String human; |
| 2292 @observable CodeInstruction jumpTarget; | 2193 @observable CodeInstruction jumpTarget; |
| 2293 @reflectable List<PcDescriptor> descriptors = | 2194 @reflectable List<PcDescriptor> descriptors = |
| 2294 new ObservableList<PcDescriptor>(); | 2195 new ObservableList<PcDescriptor>(); |
| 2295 | 2196 |
| 2296 static String formatPercent(num a, num total) { | |
| 2297 var percent = 100.0 * (a / total); | |
| 2298 return '${percent.toStringAsFixed(2)}%'; | |
| 2299 } | |
| 2300 | |
| 2301 CodeInstruction(this.address, this.pcOffset, this.machine, this.human); | 2197 CodeInstruction(this.address, this.pcOffset, this.machine, this.human); |
| 2302 | 2198 |
| 2303 @reflectable bool get isComment => address == 0; | 2199 @reflectable bool get isComment => address == 0; |
| 2304 @reflectable bool get hasDescriptors => descriptors.length > 0; | 2200 @reflectable bool get hasDescriptors => descriptors.length > 0; |
| 2305 | 2201 |
| 2306 @reflectable String formattedAddress() { | |
| 2307 if (address == 0) { | |
| 2308 return ''; | |
| 2309 } | |
| 2310 return '0x${address.toRadixString(16)}'; | |
| 2311 } | |
| 2312 | |
| 2313 @reflectable String formattedInclusive(Code code) { | |
| 2314 if (code == null) { | |
| 2315 return ''; | |
| 2316 } | |
| 2317 var tick = code.addressTicks[address]; | |
| 2318 if (tick == null) { | |
| 2319 return ''; | |
| 2320 } | |
| 2321 // Don't show inclusive ticks if they are the same as exclusive ticks. | |
| 2322 if (tick.inclusiveTicks == tick.exclusiveTicks) { | |
| 2323 return ''; | |
| 2324 } | |
| 2325 var pcent = formatPercent(tick.inclusiveTicks, code.totalSamplesInProfile); | |
| 2326 return '$pcent (${tick.inclusiveTicks})'; | |
| 2327 } | |
| 2328 | |
| 2329 @reflectable String formattedExclusive(Code code) { | |
| 2330 if (code == null) { | |
| 2331 return ''; | |
| 2332 } | |
| 2333 var tick = code.addressTicks[address]; | |
| 2334 if (tick == null) { | |
| 2335 return ''; | |
| 2336 } | |
| 2337 var pcent = formatPercent(tick.exclusiveTicks, code.totalSamplesInProfile); | |
| 2338 return '$pcent (${tick.exclusiveTicks})'; | |
| 2339 } | |
| 2340 | |
| 2341 bool _isJumpInstruction() { | 2202 bool _isJumpInstruction() { |
| 2342 return human.startsWith('j'); | 2203 return human.startsWith('j'); |
| 2343 } | 2204 } |
| 2344 | 2205 |
| 2345 int _getJumpAddress() { | 2206 int _getJumpAddress() { |
| 2346 assert(_isJumpInstruction()); | 2207 assert(_isJumpInstruction()); |
| 2347 var chunks = human.split(' '); | 2208 var chunks = human.split(' '); |
| 2348 if (chunks.length != 2) { | 2209 if (chunks.length != 2) { |
| 2349 // We expect jump instructions to be of the form 'j.. address'. | 2210 // We expect jump instructions to be of the form 'j.. address'. |
| 2350 return 0; | 2211 return 0; |
| 2351 } | 2212 } |
| 2352 var address = chunks[1]; | 2213 var address = chunks[1]; |
| 2353 if (address.startsWith('0x')) { | 2214 if (address.startsWith('0x')) { |
| 2354 // Chop off the 0x. | 2215 // Chop off the 0x. |
| 2355 address = address.substring(2); | 2216 address = address.substring(2); |
| 2356 } | 2217 } |
| 2357 try { | 2218 try { |
| 2358 return int.parse(address, radix:16); | 2219 return int.parse(address, radix:16); |
| 2359 } catch (_) { | 2220 } catch (_) { |
| 2360 return 0; | 2221 return 0; |
| 2361 } | 2222 } |
| 2362 } | 2223 } |
| 2363 | 2224 |
| 2364 void _resolveJumpTarget(List<CodeInstruction> instructions) { | 2225 void _resolveJumpTarget(List<CodeInstruction> instructions) { |
| 2365 if (!_isJumpInstruction()) { | 2226 if (!_isJumpInstruction()) { |
| 2366 return; | 2227 return; |
| 2367 } | 2228 } |
| 2368 int address = _getJumpAddress(); | 2229 int address = _getJumpAddress(); |
| 2369 if (address == 0) { | 2230 if (address == 0) { |
| 2370 // Could not determine jump address. | |
| 2371 Logger.root.severe('Could not determine jump address for $human'); | |
| 2372 return; | 2231 return; |
| 2373 } | 2232 } |
| 2374 for (var i = 0; i < instructions.length; i++) { | 2233 for (var i = 0; i < instructions.length; i++) { |
| 2375 var instruction = instructions[i]; | 2234 var instruction = instructions[i]; |
| 2376 if (instruction.address == address) { | 2235 if (instruction.address == address) { |
| 2377 jumpTarget = instruction; | 2236 jumpTarget = instruction; |
| 2378 return; | 2237 return; |
| 2379 } | 2238 } |
| 2380 } | 2239 } |
| 2381 Logger.root.severe( | |
| 2382 'Could not find instruction at ${address.toRadixString(16)}'); | |
| 2383 } | 2240 } |
| 2384 } | 2241 } |
| 2385 | 2242 |
| 2386 class CodeKind { | 2243 class CodeKind { |
| 2387 final _value; | 2244 final _value; |
| 2388 const CodeKind._internal(this._value); | 2245 const CodeKind._internal(this._value); |
| 2389 String toString() => '$_value'; | 2246 String toString() => '$_value'; |
| 2390 | 2247 |
| 2391 static CodeKind fromString(String s) { | 2248 static CodeKind fromString(String s) { |
| 2392 if (s == 'Native') { | 2249 if (s == 'Native') { |
| (...skipping 10 matching lines...) Expand all Loading... |
| 2403 Logger.root.warning('Unknown code kind $s'); | 2260 Logger.root.warning('Unknown code kind $s'); |
| 2404 throw new FallThroughError(); | 2261 throw new FallThroughError(); |
| 2405 } | 2262 } |
| 2406 static const Native = const CodeKind._internal('Native'); | 2263 static const Native = const CodeKind._internal('Native'); |
| 2407 static const Dart = const CodeKind._internal('Dart'); | 2264 static const Dart = const CodeKind._internal('Dart'); |
| 2408 static const Collected = const CodeKind._internal('Collected'); | 2265 static const Collected = const CodeKind._internal('Collected'); |
| 2409 static const Reused = const CodeKind._internal('Reused'); | 2266 static const Reused = const CodeKind._internal('Reused'); |
| 2410 static const Tag = const CodeKind._internal('Tag'); | 2267 static const Tag = const CodeKind._internal('Tag'); |
| 2411 } | 2268 } |
| 2412 | 2269 |
| 2413 class CodeCallCount { | |
| 2414 final Code code; | |
| 2415 final int count; | |
| 2416 CodeCallCount(this.code, this.count); | |
| 2417 } | |
| 2418 | |
| 2419 class CodeTrieNode { | |
| 2420 final Code code; | |
| 2421 final int count; | |
| 2422 final children = new List<CodeTrieNode>(); | |
| 2423 int summedChildCount = 0; | |
| 2424 CodeTrieNode(this.code, this.count); | |
| 2425 } | |
| 2426 | |
| 2427 class Code extends ServiceObject { | 2270 class Code extends ServiceObject { |
| 2428 @observable CodeKind kind; | 2271 @observable CodeKind kind; |
| 2429 @observable int totalSamplesInProfile = 0; | |
| 2430 @reflectable int exclusiveTicks = 0; | |
| 2431 @reflectable int inclusiveTicks = 0; | |
| 2432 @reflectable int startAddress = 0; | |
| 2433 @reflectable int endAddress = 0; | |
| 2434 @reflectable final callers = new List<CodeCallCount>(); | |
| 2435 @reflectable final callees = new List<CodeCallCount>(); | |
| 2436 @reflectable final instructions = new ObservableList<CodeInstruction>(); | |
| 2437 @reflectable final addressTicks = new ObservableMap<int, CodeTick>(); | |
| 2438 @observable String formattedInclusiveTicks = ''; | |
| 2439 @observable String formattedExclusiveTicks = ''; | |
| 2440 @observable Instance objectPool; | 2272 @observable Instance objectPool; |
| 2441 @observable ServiceFunction function; | 2273 @observable ServiceFunction function; |
| 2442 @observable Script script; | 2274 @observable Script script; |
| 2443 @observable bool isOptimized = false; | 2275 @observable bool isOptimized = false; |
| 2276 @reflectable int startAddress = 0; |
| 2277 @reflectable int endAddress = 0; |
| 2278 @reflectable final instructions = new ObservableList<CodeInstruction>(); |
| 2279 @observable ProfileCode profile; |
| 2444 | 2280 |
| 2445 bool get canCache => true; | 2281 bool get canCache => true; |
| 2446 bool get immutable => true; | 2282 bool get immutable => true; |
| 2447 | 2283 |
| 2448 Code._empty(ServiceObjectOwner owner) : super._empty(owner); | 2284 Code._empty(ServiceObjectOwner owner) : super._empty(owner); |
| 2449 | 2285 |
| 2450 // Reset all data associated with a profile. | |
| 2451 void resetProfileData() { | |
| 2452 totalSamplesInProfile = 0; | |
| 2453 exclusiveTicks = 0; | |
| 2454 inclusiveTicks = 0; | |
| 2455 formattedInclusiveTicks = ''; | |
| 2456 formattedExclusiveTicks = ''; | |
| 2457 callers.clear(); | |
| 2458 callees.clear(); | |
| 2459 addressTicks.clear(); | |
| 2460 } | |
| 2461 | |
| 2462 void _updateDescriptors(Script script) { | 2286 void _updateDescriptors(Script script) { |
| 2463 this.script = script; | 2287 this.script = script; |
| 2464 for (var instruction in instructions) { | 2288 for (var instruction in instructions) { |
| 2465 for (var descriptor in instruction.descriptors) { | 2289 for (var descriptor in instruction.descriptors) { |
| 2466 descriptor.processScript(script); | 2290 descriptor.processScript(script); |
| 2467 } | 2291 } |
| 2468 } | 2292 } |
| 2469 } | 2293 } |
| 2470 | 2294 |
| 2471 void loadScript() { | 2295 void loadScript() { |
| (...skipping 28 matching lines...) Expand all Loading... |
| 2500 /// a [ServiceError]. | 2324 /// a [ServiceError]. |
| 2501 Future<ServiceObject> reload() { | 2325 Future<ServiceObject> reload() { |
| 2502 assert(kind != null); | 2326 assert(kind != null); |
| 2503 if (kind == CodeKind.Dart) { | 2327 if (kind == CodeKind.Dart) { |
| 2504 // We only reload Dart code. | 2328 // We only reload Dart code. |
| 2505 return super.reload(); | 2329 return super.reload(); |
| 2506 } | 2330 } |
| 2507 return new Future.value(this); | 2331 return new Future.value(this); |
| 2508 } | 2332 } |
| 2509 | 2333 |
| 2510 void _resolveCalls(List<CodeCallCount> calls, List data, List<Code> codes) { | |
| 2511 // Assert that this has been cleared. | |
| 2512 assert(calls.length == 0); | |
| 2513 // Resolve. | |
| 2514 for (var i = 0; i < data.length; i += 2) { | |
| 2515 var index = int.parse(data[i]); | |
| 2516 var count = int.parse(data[i + 1]); | |
| 2517 assert(index >= 0); | |
| 2518 assert(index < codes.length); | |
| 2519 calls.add(new CodeCallCount(codes[index], count)); | |
| 2520 } | |
| 2521 // Sort to descending count order. | |
| 2522 calls.sort((a, b) => b.count - a.count); | |
| 2523 } | |
| 2524 | |
| 2525 | |
| 2526 static String formatPercent(num a, num total) { | |
| 2527 var percent = 100.0 * (a / total); | |
| 2528 return '${percent.toStringAsFixed(2)}%'; | |
| 2529 } | |
| 2530 | |
| 2531 void updateProfileData(Map profileData, | |
| 2532 List<Code> codeTable, | |
| 2533 int sampleCount) { | |
| 2534 // Assert we are handed profile data for this code object. | |
| 2535 assert(profileData['code'] == this); | |
| 2536 totalSamplesInProfile = sampleCount; | |
| 2537 inclusiveTicks = int.parse(profileData['inclusive_ticks']); | |
| 2538 exclusiveTicks = int.parse(profileData['exclusive_ticks']); | |
| 2539 _resolveCalls(callers, profileData['callers'], codeTable); | |
| 2540 _resolveCalls(callees, profileData['callees'], codeTable); | |
| 2541 var ticks = profileData['ticks']; | |
| 2542 if (ticks != null) { | |
| 2543 _processTicks(ticks); | |
| 2544 } | |
| 2545 formattedInclusiveTicks = | |
| 2546 '${formatPercent(inclusiveTicks, totalSamplesInProfile)} ' | |
| 2547 '($inclusiveTicks)'; | |
| 2548 formattedExclusiveTicks = | |
| 2549 '${formatPercent(exclusiveTicks, totalSamplesInProfile)} ' | |
| 2550 '($exclusiveTicks)'; | |
| 2551 } | |
| 2552 | |
| 2553 void _update(ObservableMap m, bool mapIsRef) { | 2334 void _update(ObservableMap m, bool mapIsRef) { |
| 2554 name = m['name']; | 2335 name = m['name']; |
| 2555 vmName = (m.containsKey('vmName') ? m['vmName'] : name); | 2336 vmName = (m.containsKey('vmName') ? m['vmName'] : name); |
| 2556 isOptimized = m['optimized'] != null ? m['optimized'] : false; | 2337 isOptimized = m['optimized'] != null ? m['optimized'] : false; |
| 2557 kind = CodeKind.fromString(m['kind']); | 2338 kind = CodeKind.fromString(m['kind']); |
| 2558 startAddress = int.parse(m['start'], radix:16); | 2339 startAddress = int.parse(m['start'], radix:16); |
| 2559 endAddress = int.parse(m['end'], radix:16); | 2340 endAddress = int.parse(m['end'], radix:16); |
| 2560 function = isolate.getFromMap(m['function']); | 2341 function = isolate.getFromMap(m['function']); |
| 2342 if (mapIsRef) { |
| 2343 return; |
| 2344 } |
| 2561 objectPool = isolate.getFromMap(m['objectPool']); | 2345 objectPool = isolate.getFromMap(m['objectPool']); |
| 2562 var disassembly = m['disassembly']; | 2346 var disassembly = m['disassembly']; |
| 2563 if (disassembly != null) { | 2347 if (disassembly != null) { |
| 2564 _processDisassembly(disassembly); | 2348 _processDisassembly(disassembly); |
| 2565 } | 2349 } |
| 2566 var descriptors = m['descriptors']; | 2350 var descriptors = m['descriptors']; |
| 2567 if (descriptors != null) { | 2351 if (descriptors != null) { |
| 2568 descriptors = descriptors['members']; | 2352 descriptors = descriptors['members']; |
| 2569 _processDescriptors(descriptors); | 2353 _processDescriptors(descriptors); |
| 2570 } | 2354 } |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2617 Logger.root.warning( | 2401 Logger.root.warning( |
| 2618 'Could not find instruction with pc descriptor address: $address'); | 2402 'Could not find instruction with pc descriptor address: $address'); |
| 2619 } | 2403 } |
| 2620 | 2404 |
| 2621 void _processDescriptors(List<Map> descriptors) { | 2405 void _processDescriptors(List<Map> descriptors) { |
| 2622 for (Map descriptor in descriptors) { | 2406 for (Map descriptor in descriptors) { |
| 2623 _processDescriptor(descriptor); | 2407 _processDescriptor(descriptor); |
| 2624 } | 2408 } |
| 2625 } | 2409 } |
| 2626 | 2410 |
| 2627 void _processTicks(List<String> profileTicks) { | |
| 2628 assert(profileTicks != null); | |
| 2629 assert((profileTicks.length % 3) == 0); | |
| 2630 for (var i = 0; i < profileTicks.length; i += 3) { | |
| 2631 var address = int.parse(profileTicks[i], radix:16); | |
| 2632 var exclusive = int.parse(profileTicks[i + 1]); | |
| 2633 var inclusive = int.parse(profileTicks[i + 2]); | |
| 2634 var tick = new CodeTick(address, exclusive, inclusive); | |
| 2635 addressTicks[address] = tick; | |
| 2636 } | |
| 2637 } | |
| 2638 | |
| 2639 /// Returns true if [address] is contained inside [this]. | 2411 /// Returns true if [address] is contained inside [this]. |
| 2640 bool contains(int address) { | 2412 bool contains(int address) { |
| 2641 return (address >= startAddress) && (address < endAddress); | 2413 return (address >= startAddress) && (address < endAddress); |
| 2642 } | 2414 } |
| 2643 | 2415 |
| 2644 /// Sum all caller counts. | |
| 2645 int sumCallersCount() => _sumCallCount(callers); | |
| 2646 /// Specific caller count. | |
| 2647 int callersCount(Code code) => _callCount(callers, code); | |
| 2648 /// Sum of callees count. | |
| 2649 int sumCalleesCount() => _sumCallCount(callees); | |
| 2650 /// Specific callee count. | |
| 2651 int calleesCount(Code code) => _callCount(callees, code); | |
| 2652 | |
| 2653 int _sumCallCount(List<CodeCallCount> calls) { | |
| 2654 var sum = 0; | |
| 2655 for (CodeCallCount caller in calls) { | |
| 2656 sum += caller.count; | |
| 2657 } | |
| 2658 return sum; | |
| 2659 } | |
| 2660 | |
| 2661 int _callCount(List<CodeCallCount> calls, Code code) { | |
| 2662 for (CodeCallCount caller in calls) { | |
| 2663 if (caller.code == code) { | |
| 2664 return caller.count; | |
| 2665 } | |
| 2666 } | |
| 2667 return 0; | |
| 2668 } | |
| 2669 | |
| 2670 @reflectable bool get isDartCode => kind == CodeKind.Dart; | 2416 @reflectable bool get isDartCode => kind == CodeKind.Dart; |
| 2671 } | 2417 } |
| 2672 | 2418 |
| 2673 | 2419 |
| 2674 class SocketKind { | 2420 class SocketKind { |
| 2675 final _value; | 2421 final _value; |
| 2676 const SocketKind._internal(this._value); | 2422 const SocketKind._internal(this._value); |
| 2677 String toString() => '$_value'; | 2423 String toString() => '$_value'; |
| 2678 | 2424 |
| 2679 static SocketKind fromString(String s) { | 2425 static SocketKind fromString(String s) { |
| (...skipping 238 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2918 var v = list[i]; | 2664 var v = list[i]; |
| 2919 if ((v is ObservableMap) && _isServiceMap(v)) { | 2665 if ((v is ObservableMap) && _isServiceMap(v)) { |
| 2920 list[i] = owner.getFromMap(v); | 2666 list[i] = owner.getFromMap(v); |
| 2921 } else if (v is ObservableList) { | 2667 } else if (v is ObservableList) { |
| 2922 _upgradeObservableList(v, owner); | 2668 _upgradeObservableList(v, owner); |
| 2923 } else if (v is ObservableMap) { | 2669 } else if (v is ObservableMap) { |
| 2924 _upgradeObservableMap(v, owner); | 2670 _upgradeObservableMap(v, owner); |
| 2925 } | 2671 } |
| 2926 } | 2672 } |
| 2927 } | 2673 } |
| OLD | NEW |