| 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 11 matching lines...) Expand all Loading... |
| 22 @reflectable String get id => _id; | 22 @reflectable String get id => _id; |
| 23 String _id; | 23 String _id; |
| 24 | 24 |
| 25 /// The service type of this object. | 25 /// The service type of this object. |
| 26 @reflectable String get serviceType => _serviceType; | 26 @reflectable String get serviceType => _serviceType; |
| 27 String _serviceType; | 27 String _serviceType; |
| 28 | 28 |
| 29 /// The complete service url of this object. | 29 /// The complete service url of this object. |
| 30 @reflectable String get link => _owner.relativeLink(_id); | 30 @reflectable String get link => _owner.relativeLink(_id); |
| 31 | 31 |
| 32 /// The complete service url of this object with a '#/' prefix. | |
| 33 // TODO(turnidge): Figure out why using a getter here messes up polymer. | |
| 34 @reflectable String get hashLink => '#/${link}'; | |
| 35 @reflectable set hashLink(var o) { /* silence polymer */ } | |
| 36 | |
| 37 /// Has this object been fully loaded? | 32 /// Has this object been fully loaded? |
| 38 bool get loaded => _loaded; | 33 bool get loaded => _loaded; |
| 39 bool _loaded = false; | 34 bool _loaded = false; |
| 40 // TODO(turnidge): Make loaded observable and get rid of loading | 35 // TODO(turnidge): Make loaded observable and get rid of loading |
| 41 // from Isolate. | 36 // from Isolate. |
| 42 | 37 |
| 43 /// Is this object cacheable? That is, is it impossible for the [id] | 38 /// Is this object cacheable? That is, is it impossible for the [id] |
| 44 /// of this object to change? | 39 /// of this object to change? |
| 45 bool get canCache => false; | 40 bool get canCache => false; |
| 46 | 41 |
| (...skipping 13 matching lines...) Expand all Loading... |
| 60 return null; | 55 return null; |
| 61 } | 56 } |
| 62 if (!_isServiceMap(map)) { | 57 if (!_isServiceMap(map)) { |
| 63 Logger.root.severe('Malformed service object: $map'); | 58 Logger.root.severe('Malformed service object: $map'); |
| 64 } | 59 } |
| 65 assert(_isServiceMap(map)); | 60 assert(_isServiceMap(map)); |
| 66 var type = _stripRef(map['type']); | 61 var type = _stripRef(map['type']); |
| 67 var obj = null; | 62 var obj = null; |
| 68 assert(type != 'VM'); | 63 assert(type != 'VM'); |
| 69 switch (type) { | 64 switch (type) { |
| 65 case 'Class': |
| 66 obj = new Class._empty(owner); |
| 67 break; |
| 70 case 'Code': | 68 case 'Code': |
| 71 obj = new Code._empty(owner); | 69 obj = new Code._empty(owner); |
| 72 break; | 70 break; |
| 73 case 'Error': | 71 case 'Error': |
| 74 obj = new DartError._empty(owner); | 72 obj = new DartError._empty(owner); |
| 75 break; | 73 break; |
| 76 case 'Isolate': | 74 case 'Isolate': |
| 77 obj = new Isolate._empty(owner); | 75 obj = new Isolate._empty(owner); |
| 78 break; | 76 break; |
| 79 case 'Library': | 77 case 'Library': |
| (...skipping 165 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 245 return reload().then((result) { | 243 return reload().then((result) { |
| 246 if (result is! VM) { | 244 if (result is! VM) { |
| 247 return null; | 245 return null; |
| 248 } | 246 } |
| 249 assert(result == this); | 247 assert(result == this); |
| 250 return _isolateCache[isolateId]; | 248 return _isolateCache[isolateId]; |
| 251 }); | 249 }); |
| 252 } | 250 } |
| 253 | 251 |
| 254 Future<ServiceObject> get(String id) { | 252 Future<ServiceObject> get(String id) { |
| 255 var parts = id.split('#'); | 253 assert(id.startsWith('/') == false); |
| 256 assert(parts.length >= 1); | |
| 257 // We should never see more than two hashes. | |
| 258 assert(parts.length <= 2); | |
| 259 // The ID does not include anything after the # (or the # itself). | |
| 260 id = parts[0]; | |
| 261 // I'm serious. | |
| 262 assert(!id.contains('#')); | |
| 263 // Isolates are handled specially, since they can cache sub-objects. | 254 // Isolates are handled specially, since they can cache sub-objects. |
| 264 if (id.startsWith(_isolatesPrefix)) { | 255 if (id.startsWith(_isolatesPrefix)) { |
| 265 String isolateId = _parseIsolateId(id); | 256 String isolateId = _parseIsolateId(id); |
| 266 String objectId = _parseObjectId(id); | 257 String objectId = _parseObjectId(id); |
| 267 return _getIsolate(isolateId).then((isolate) { | 258 return _getIsolate(isolateId).then((isolate) { |
| 268 if (isolate == null) { | 259 if (isolate == null) { |
| 269 // The isolate does not exist. Return the VM object instead. | 260 // The isolate does not exist. Return the VM object instead. |
| 270 // | 261 // |
| 271 // TODO(turnidge): Generate a service error? | 262 // TODO(turnidge): Generate a service error? |
| 272 return this; | 263 return this; |
| 273 } | 264 } |
| 274 if (objectId == null) { | 265 if (objectId == null) { |
| 275 return isolate.reload(); | 266 return isolate.reload(); |
| 276 } else { | 267 } else { |
| 277 return isolate.get(objectId); | 268 return isolate.get(objectId); |
| 278 } | 269 } |
| 279 }); | 270 }); |
| 280 } | 271 } |
| 281 | 272 |
| 282 var obj = _cache[id]; | 273 var obj = _cache[id]; |
| 283 if (obj != null) { | 274 if (obj != null) { |
| 284 return obj.reload(); | 275 return obj.reload(); |
| 285 } | 276 } |
| 277 |
| 286 // Cache miss. Get the object from the vm directly. | 278 // Cache miss. Get the object from the vm directly. |
| 287 return getAsMap(id).then((ObservableMap map) { | 279 return getAsMap(id).then((ObservableMap map) { |
| 288 var obj = new ServiceObject._fromMap(this, map); | 280 var obj = new ServiceObject._fromMap(this, map); |
| 289 if (obj.canCache) { | 281 if (obj.canCache) { |
| 290 _cache.putIfAbsent(id, () => obj); | 282 _cache.putIfAbsent(id, () => obj); |
| 291 } | 283 } |
| 292 return obj; | 284 return obj; |
| 293 }); | 285 }); |
| 294 } | 286 } |
| 295 | 287 |
| 296 dynamic _reviver(dynamic key, dynamic value) { | 288 dynamic _reviver(dynamic key, dynamic value) { |
| 297 return value; | 289 return value; |
| 298 } | 290 } |
| 299 | 291 |
| 300 ObservableMap _parseJSON(String response) { | 292 ObservableMap _parseJSON(String response) { |
| 301 var map; | 293 var map; |
| 302 try { | 294 try { |
| 303 var decoder = new JsonDecoder(_reviver); | 295 var decoder = new JsonDecoder(_reviver); |
| (...skipping 187 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 491 } | 483 } |
| 492 } | 484 } |
| 493 } | 485 } |
| 494 | 486 |
| 495 /// State for a running isolate. | 487 /// State for a running isolate. |
| 496 class Isolate extends ServiceObjectOwner { | 488 class Isolate extends ServiceObjectOwner { |
| 497 @reflectable VM get vm => owner; | 489 @reflectable VM get vm => owner; |
| 498 @reflectable Isolate get isolate => this; | 490 @reflectable Isolate get isolate => this; |
| 499 @observable ObservableMap counters = new ObservableMap(); | 491 @observable ObservableMap counters = new ObservableMap(); |
| 500 | 492 |
| 501 String get link => _id; | 493 String get link => '/${_id}'; |
| 502 String get hashLink => '#/$_id'; | |
| 503 | 494 |
| 504 @observable ServiceMap pauseEvent = null; | 495 @observable ServiceMap pauseEvent = null; |
| 505 bool get _isPaused => pauseEvent != null; | 496 bool get _isPaused => pauseEvent != null; |
| 506 | 497 |
| 507 @observable bool running = false; | 498 @observable bool running = false; |
| 508 @observable bool idle = false; | 499 @observable bool idle = false; |
| 509 @observable bool loading = true; | 500 @observable bool loading = true; |
| 510 @observable bool ioEnabled = false; | 501 @observable bool ioEnabled = false; |
| 511 | 502 |
| 512 Map<String,ServiceObject> _cache = new Map<String,ServiceObject>(); | 503 Map<String,ServiceObject> _cache = new Map<String,ServiceObject>(); |
| 513 final TagProfile tagProfile = new TagProfile(20); | 504 final TagProfile tagProfile = new TagProfile(20); |
| 514 | 505 |
| 515 Isolate._empty(ServiceObjectOwner owner) : super._empty(owner) { | 506 Isolate._empty(ServiceObjectOwner owner) : super._empty(owner) { |
| 516 assert(owner is VM); | 507 assert(owner is VM); |
| 517 } | 508 } |
| 518 | 509 |
| 519 /// Creates a link to [id] relative to [this]. | 510 /// Creates a link to [id] relative to [this]. |
| 520 @reflectable String relativeLink(String id) => '${this.id}/$id'; | 511 @reflectable String relativeLink(String id) => '/${this.id}/$id'; |
| 521 /// Creates a relative link to [id] with a '#/' prefix. | |
| 522 @reflectable String relativeHashLink(String id) => '#/${relativeLink(id)}'; | |
| 523 | 512 |
| 524 static const TAG_ROOT_ID = 'code/tag-0'; | 513 static const TAG_ROOT_ID = 'code/tag-0'; |
| 525 | 514 |
| 526 /// Returns the Code object for the root tag. | 515 /// Returns the Code object for the root tag. |
| 527 Code tagRoot() { | 516 Code tagRoot() { |
| 528 // TODO(turnidge): Use get() here instead? | 517 // TODO(turnidge): Use get() here instead? |
| 529 return _cache[TAG_ROOT_ID]; | 518 return _cache[TAG_ROOT_ID]; |
| 530 } | 519 } |
| 531 | 520 |
| 532 void processProfile(ServiceMap profile) { | 521 void processProfile(ServiceMap profile) { |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 578 } | 567 } |
| 579 | 568 |
| 580 void _processScriptCoverage(ObservableMap scriptCoverage) { | 569 void _processScriptCoverage(ObservableMap scriptCoverage) { |
| 581 // Because the coverage data was upgraded into a ServiceObject, | 570 // Because the coverage data was upgraded into a ServiceObject, |
| 582 // the script can be directly accessed. | 571 // the script can be directly accessed. |
| 583 Script script = scriptCoverage['script']; | 572 Script script = scriptCoverage['script']; |
| 584 assert(_cache.containsValue(script)); | 573 assert(_cache.containsValue(script)); |
| 585 script._processHits(scriptCoverage['hits']); | 574 script._processHits(scriptCoverage['hits']); |
| 586 } | 575 } |
| 587 | 576 |
| 577 /// Fetches and builds the class hierarchy for this isolate. Returns the |
| 578 /// Object class object. |
| 579 Future<Class> getClassHierarchy() { |
| 580 return get('classes').then(_loadClasses).then(_buildClassHierarchy); |
| 581 } |
| 582 |
| 583 /// Given the class list, loads each class. |
| 584 Future<List<Class>> _loadClasses(ServiceMap classList) { |
| 585 assert(classList.serviceType == 'ClassList'); |
| 586 var futureClasses = []; |
| 587 for (var cls in classList['members']) { |
| 588 // Skip over non-class classes. |
| 589 if (cls is Class) { |
| 590 futureClasses.add(cls.load()); |
| 591 } |
| 592 } |
| 593 return Future.wait(futureClasses); |
| 594 } |
| 595 |
| 596 /// Builds the class hierarchy and returns the Object class. |
| 597 Future<Class> _buildClassHierarchy(List<Class> classes) { |
| 598 rootClasses.clear(); |
| 599 objectClass = null; |
| 600 for (var cls in classes) { |
| 601 if (cls.superClass == null) { |
| 602 rootClasses.add(cls); |
| 603 } |
| 604 if ((cls.vmName == 'Object') && (cls.isPatch == false)) { |
| 605 objectClass = cls; |
| 606 } |
| 607 } |
| 608 assert(objectClass != null); |
| 609 return new Future.value(objectClass); |
| 610 } |
| 611 |
| 588 ServiceObject getFromMap(ObservableMap map) { | 612 ServiceObject getFromMap(ObservableMap map) { |
| 589 if (map == null) { | 613 if (map == null) { |
| 590 return null; | 614 return null; |
| 591 } | 615 } |
| 592 String id = map['id']; | 616 String id = map['id']; |
| 593 var obj = _cache[id]; | 617 var obj = _cache[id]; |
| 594 if (obj != null) { | 618 if (obj != null) { |
| 595 return obj; | 619 return obj; |
| 596 } | 620 } |
| 597 // Build the object from the map directly. | 621 // Build the object from the map directly. |
| (...skipping 14 matching lines...) Expand all Loading... |
| 612 // Cache miss. Get the object from the vm directly. | 636 // Cache miss. Get the object from the vm directly. |
| 613 return vm.getAsMap(relativeLink(id)).then((ObservableMap map) { | 637 return vm.getAsMap(relativeLink(id)).then((ObservableMap map) { |
| 614 var obj = new ServiceObject._fromMap(this, map); | 638 var obj = new ServiceObject._fromMap(this, map); |
| 615 if (obj.canCache) { | 639 if (obj.canCache) { |
| 616 _cache.putIfAbsent(id, () => obj); | 640 _cache.putIfAbsent(id, () => obj); |
| 617 } | 641 } |
| 618 return obj; | 642 return obj; |
| 619 }); | 643 }); |
| 620 } | 644 } |
| 621 | 645 |
| 646 @observable Class objectClass; |
| 647 @observable final rootClasses = new ObservableList<Class>(); |
| 648 |
| 622 @observable Library rootLib; | 649 @observable Library rootLib; |
| 623 @observable ObservableList<Library> libraries = | 650 @observable ObservableList<Library> libraries = |
| 624 new ObservableList<Library>(); | 651 new ObservableList<Library>(); |
| 625 @observable ObservableMap topFrame; | 652 @observable ObservableMap topFrame; |
| 626 | 653 |
| 627 @observable String name; | 654 @observable String name; |
| 628 @observable String vmName; | 655 @observable String vmName; |
| 629 @observable String mainPort; | 656 @observable String mainPort; |
| 630 @observable Map entry; | 657 @observable Map entry; |
| 631 | 658 |
| (...skipping 267 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 899 response = map['response']; | 926 response = map['response']; |
| 900 name = 'ServiceException $kind'; | 927 name = 'ServiceException $kind'; |
| 901 vmName = name; | 928 vmName = name; |
| 902 } | 929 } |
| 903 } | 930 } |
| 904 | 931 |
| 905 class Library extends ServiceObject { | 932 class Library extends ServiceObject { |
| 906 @observable String url; | 933 @observable String url; |
| 907 @reflectable final imports = new ObservableList<Library>(); | 934 @reflectable final imports = new ObservableList<Library>(); |
| 908 @reflectable final scripts = new ObservableList<Script>(); | 935 @reflectable final scripts = new ObservableList<Script>(); |
| 909 @reflectable final classes = new ObservableList<ServiceMap>(); | 936 @reflectable final classes = new ObservableList<Class>(); |
| 910 @reflectable final variables = new ObservableList<ServiceMap>(); | 937 @reflectable final variables = new ObservableList<ServiceMap>(); |
| 911 @reflectable final functions = new ObservableList<ServiceMap>(); | 938 @reflectable final functions = new ObservableList<ServiceMap>(); |
| 912 | 939 |
| 913 bool get canCache => true; | 940 bool get canCache => true; |
| 914 bool get immutable => false; | 941 bool get immutable => false; |
| 915 | 942 |
| 916 Library._empty(ServiceObjectOwner owner) : super._empty(owner); | 943 Library._empty(ServiceObjectOwner owner) : super._empty(owner); |
| 917 | 944 |
| 918 void _update(ObservableMap map, bool mapIsRef) { | 945 void _update(ObservableMap map, bool mapIsRef) { |
| 919 url = map['url']; | 946 url = map['url']; |
| (...skipping 18 matching lines...) Expand all Loading... |
| 938 scripts.addAll(map['scripts']); | 965 scripts.addAll(map['scripts']); |
| 939 classes.clear(); | 966 classes.clear(); |
| 940 classes.addAll(map['classes']); | 967 classes.addAll(map['classes']); |
| 941 variables.clear(); | 968 variables.clear(); |
| 942 variables.addAll(map['variables']); | 969 variables.addAll(map['variables']); |
| 943 functions.clear(); | 970 functions.clear(); |
| 944 functions.addAll(map['functions']); | 971 functions.addAll(map['functions']); |
| 945 } | 972 } |
| 946 } | 973 } |
| 947 | 974 |
| 975 class Class extends ServiceObject { |
| 976 @observable Library library; |
| 977 @observable Script script; |
| 978 @observable Class superClass; |
| 979 |
| 980 @observable bool isAbstract; |
| 981 @observable bool isConst; |
| 982 @observable bool isFinalized; |
| 983 @observable bool isPatch; |
| 984 @observable bool isImplemented; |
| 985 |
| 986 @observable int tokenPos; |
| 987 |
| 988 @observable ServiceMap error; |
| 989 |
| 990 @reflectable final children = new ObservableList<Class>(); |
| 991 @reflectable final subClasses = new ObservableList<Class>(); |
| 992 @reflectable final fields = new ObservableList<ServiceMap>(); |
| 993 @reflectable final functions = new ObservableList<ServiceMap>(); |
| 994 @reflectable final interfaces = new ObservableList<Class>(); |
| 995 |
| 996 bool get canCache => true; |
| 997 bool get immutable => false; |
| 998 |
| 999 Class._empty(ServiceObjectOwner owner) : super._empty(owner); |
| 1000 |
| 1001 String toString() { |
| 1002 return 'Service Class: $vmName'; |
| 1003 } |
| 1004 |
| 1005 void _update(ObservableMap map, bool mapIsRef) { |
| 1006 name = map['user_name']; |
| 1007 vmName = map['name']; |
| 1008 |
| 1009 if (mapIsRef) { |
| 1010 return; |
| 1011 } |
| 1012 |
| 1013 // We are fully loaded. |
| 1014 _loaded = true; |
| 1015 |
| 1016 // Extract full properties. |
| 1017 _upgradeCollection(map, isolate); |
| 1018 |
| 1019 // Some builtin classes aren't associated with a library. |
| 1020 if (map['library'] is Library) { |
| 1021 library = map['library']; |
| 1022 } else { |
| 1023 library = null; |
| 1024 } |
| 1025 |
| 1026 script = map['script']; |
| 1027 |
| 1028 isAbstract = map['abstract']; |
| 1029 isConst = map['const']; |
| 1030 isFinalized = map['finalized']; |
| 1031 isPatch = map['patch']; |
| 1032 isImplemented = map['implemented']; |
| 1033 |
| 1034 tokenPos = map['tokenPos']; |
| 1035 |
| 1036 subClasses.clear(); |
| 1037 subClasses.addAll(map['subclasses']); |
| 1038 |
| 1039 fields.clear(); |
| 1040 fields.addAll(map['fields']); |
| 1041 |
| 1042 functions.clear(); |
| 1043 functions.addAll(map['functions']); |
| 1044 |
| 1045 superClass = map['super']; |
| 1046 if (superClass != null) { |
| 1047 superClass._addToChildren(this); |
| 1048 } |
| 1049 error = map['error']; |
| 1050 } |
| 1051 |
| 1052 void _addToChildren(Class cls) { |
| 1053 if (children.contains(cls)) { |
| 1054 return; |
| 1055 } |
| 1056 children.add(cls); |
| 1057 } |
| 1058 } |
| 1059 |
| 948 class ScriptLine { | 1060 class ScriptLine { |
| 949 @reflectable final int line; | 1061 @reflectable final int line; |
| 950 @reflectable final String text; | 1062 @reflectable final String text; |
| 951 ScriptLine(this.line, this.text); | 1063 ScriptLine(this.line, this.text); |
| 952 } | 1064 } |
| 953 | 1065 |
| 954 class Script extends ServiceObject { | 1066 class Script extends ServiceObject { |
| 955 @reflectable final lines = new ObservableList<ScriptLine>(); | 1067 @reflectable final lines = new ObservableList<ScriptLine>(); |
| 956 @reflectable final hits = new ObservableMap<int, int>(); | 1068 @reflectable final hits = new ObservableMap<int, int>(); |
| 957 @observable String kind; | 1069 @observable String kind; |
| (...skipping 668 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1626 var v = list[i]; | 1738 var v = list[i]; |
| 1627 if ((v is ObservableMap) && _isServiceMap(v)) { | 1739 if ((v is ObservableMap) && _isServiceMap(v)) { |
| 1628 list[i] = owner.getFromMap(v); | 1740 list[i] = owner.getFromMap(v); |
| 1629 } else if (v is ObservableList) { | 1741 } else if (v is ObservableList) { |
| 1630 _upgradeObservableList(v, owner); | 1742 _upgradeObservableList(v, owner); |
| 1631 } else if (v is ObservableMap) { | 1743 } else if (v is ObservableMap) { |
| 1632 _upgradeObservableMap(v, owner); | 1744 _upgradeObservableMap(v, owner); |
| 1633 } | 1745 } |
| 1634 } | 1746 } |
| 1635 } | 1747 } |
| OLD | NEW |