Chromium Code Reviews| 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 Future getClassHierarchy() { | |
|
turnidge
2014/06/04 18:02:24
Can we add a type param to this Future? I think
Cutch
2014/06/04 20:28:57
Done.
| |
| 578 return get('classes').then(_processClasses).then(_postProcessClasses); | |
| 579 } | |
| 580 | |
| 581 Future _processClasses(ServiceMap classList) { | |
|
turnidge
2014/06/04 18:02:24
Maybe name this _loadClasses?
Cutch
2014/06/04 20:28:57
Woah! I made that rename before reading this comme
| |
| 582 assert(classList.serviceType == 'ClassList'); | |
| 583 var futureClasses = []; | |
| 584 for (var cls in classList['members']) { | |
| 585 // Skip over non-class classes. | |
| 586 if (cls is Class) { | |
| 587 futureClasses.add(cls.load()); | |
| 588 } | |
| 589 } | |
| 590 return Future.wait(futureClasses); | |
| 591 } | |
| 592 | |
| 593 Future _postProcessClasses(List<Class> classes) { | |
| 594 rootClasses.clear(); | |
| 595 objectClass = null; | |
| 596 for (var cls in classes) { | |
| 597 if (cls.superClass == null) { | |
| 598 rootClasses.add(cls); | |
|
turnidge
2014/06/04 18:02:24
I thought that Object was the root class. Am I be
Cutch
2014/06/04 20:28:57
Internal VM classes (Field, Function, etc).
Note,
| |
| 599 } | |
| 600 if ((cls.vmName == 'Object') && (cls.isPatch == false)) { | |
| 601 objectClass = cls; | |
| 602 } | |
| 603 } | |
| 604 assert(objectClass != null); | |
| 605 return new Future.value(objectClass); | |
| 606 } | |
| 607 | |
| 588 ServiceObject getFromMap(ObservableMap map) { | 608 ServiceObject getFromMap(ObservableMap map) { |
| 589 if (map == null) { | 609 if (map == null) { |
| 590 return null; | 610 return null; |
| 591 } | 611 } |
| 592 String id = map['id']; | 612 String id = map['id']; |
| 593 var obj = _cache[id]; | 613 var obj = _cache[id]; |
| 594 if (obj != null) { | 614 if (obj != null) { |
| 595 return obj; | 615 return obj; |
| 596 } | 616 } |
| 597 // Build the object from the map directly. | 617 // Build the object from the map directly. |
| (...skipping 14 matching lines...) Expand all Loading... | |
| 612 // Cache miss. Get the object from the vm directly. | 632 // Cache miss. Get the object from the vm directly. |
| 613 return vm.getAsMap(relativeLink(id)).then((ObservableMap map) { | 633 return vm.getAsMap(relativeLink(id)).then((ObservableMap map) { |
| 614 var obj = new ServiceObject._fromMap(this, map); | 634 var obj = new ServiceObject._fromMap(this, map); |
| 615 if (obj.canCache) { | 635 if (obj.canCache) { |
| 616 _cache.putIfAbsent(id, () => obj); | 636 _cache.putIfAbsent(id, () => obj); |
| 617 } | 637 } |
| 618 return obj; | 638 return obj; |
| 619 }); | 639 }); |
| 620 } | 640 } |
| 621 | 641 |
| 642 @observable Class objectClass; | |
| 643 @observable final rootClasses = new ObservableList<Class>(); | |
| 644 | |
| 622 @observable Library rootLib; | 645 @observable Library rootLib; |
| 623 @observable ObservableList<Library> libraries = | 646 @observable ObservableList<Library> libraries = |
| 624 new ObservableList<Library>(); | 647 new ObservableList<Library>(); |
| 625 @observable ObservableMap topFrame; | 648 @observable ObservableMap topFrame; |
| 626 | 649 |
| 627 @observable String name; | 650 @observable String name; |
| 628 @observable String vmName; | 651 @observable String vmName; |
| 629 @observable String mainPort; | 652 @observable String mainPort; |
| 630 @observable Map entry; | 653 @observable Map entry; |
| 631 | 654 |
| (...skipping 267 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 899 response = map['response']; | 922 response = map['response']; |
| 900 name = 'ServiceException $kind'; | 923 name = 'ServiceException $kind'; |
| 901 vmName = name; | 924 vmName = name; |
| 902 } | 925 } |
| 903 } | 926 } |
| 904 | 927 |
| 905 class Library extends ServiceObject { | 928 class Library extends ServiceObject { |
| 906 @observable String url; | 929 @observable String url; |
| 907 @reflectable final imports = new ObservableList<Library>(); | 930 @reflectable final imports = new ObservableList<Library>(); |
| 908 @reflectable final scripts = new ObservableList<Script>(); | 931 @reflectable final scripts = new ObservableList<Script>(); |
| 909 @reflectable final classes = new ObservableList<ServiceMap>(); | 932 @reflectable final classes = new ObservableList<Class>(); |
| 910 @reflectable final variables = new ObservableList<ServiceMap>(); | 933 @reflectable final variables = new ObservableList<ServiceMap>(); |
| 911 @reflectable final functions = new ObservableList<ServiceMap>(); | 934 @reflectable final functions = new ObservableList<ServiceMap>(); |
| 912 | 935 |
| 913 bool get canCache => true; | 936 bool get canCache => true; |
| 914 bool get immutable => false; | 937 bool get immutable => false; |
| 915 | 938 |
| 916 Library._empty(ServiceObjectOwner owner) : super._empty(owner); | 939 Library._empty(ServiceObjectOwner owner) : super._empty(owner); |
| 917 | 940 |
| 918 void _update(ObservableMap map, bool mapIsRef) { | 941 void _update(ObservableMap map, bool mapIsRef) { |
| 919 url = map['url']; | 942 url = map['url']; |
| (...skipping 18 matching lines...) Expand all Loading... | |
| 938 scripts.addAll(map['scripts']); | 961 scripts.addAll(map['scripts']); |
| 939 classes.clear(); | 962 classes.clear(); |
| 940 classes.addAll(map['classes']); | 963 classes.addAll(map['classes']); |
| 941 variables.clear(); | 964 variables.clear(); |
| 942 variables.addAll(map['variables']); | 965 variables.addAll(map['variables']); |
| 943 functions.clear(); | 966 functions.clear(); |
| 944 functions.addAll(map['functions']); | 967 functions.addAll(map['functions']); |
| 945 } | 968 } |
| 946 } | 969 } |
| 947 | 970 |
| 971 class Class extends ServiceObject { | |
| 972 @observable Library library; | |
| 973 @observable Script script; | |
| 974 @observable Class superClass; | |
| 975 | |
| 976 @observable bool isAbstract; | |
| 977 @observable bool isConst; | |
| 978 @observable bool isFinalized; | |
| 979 @observable bool isPatch; | |
| 980 @observable bool isImplemented; | |
| 981 | |
| 982 @observable int tokenPos; | |
| 983 | |
| 984 @observable ServiceMap error; | |
| 985 | |
| 986 @reflectable final children = new ObservableList<Class>(); | |
| 987 @reflectable final subClasses = new ObservableList<Class>(); | |
| 988 @reflectable final fields = new ObservableList<ServiceMap>(); | |
| 989 @reflectable final functions = new ObservableList<ServiceMap>(); | |
| 990 @reflectable final interfaces = new ObservableList<Class>(); | |
| 991 | |
| 992 bool get canCache => true; | |
| 993 bool get immutable => false; | |
| 994 | |
| 995 Class._empty(ServiceObjectOwner owner) : super._empty(owner) { | |
| 996 } | |
|
turnidge
2014/06/04 18:02:24
Instead of empty body, just use a ';'?
Cutch
2014/06/04 20:28:57
Done.
| |
| 997 | |
| 998 String toString() { | |
| 999 return 'Service Class: $vmName'; | |
| 1000 } | |
| 1001 | |
| 1002 void _update(ObservableMap map, bool mapIsRef) { | |
| 1003 name = map['user_name']; | |
| 1004 vmName = map['name']; | |
| 1005 | |
| 1006 if (mapIsRef) { | |
| 1007 return; | |
| 1008 } | |
| 1009 | |
| 1010 // We are fully loaded. | |
| 1011 _loaded = true; | |
| 1012 | |
| 1013 // Extract full properties. | |
| 1014 _upgradeCollection(map, isolate); | |
| 1015 | |
| 1016 // Some builtin classes aren't associated with a library. | |
| 1017 if (map['library'] is Library) { | |
| 1018 library = map['library']; | |
| 1019 } else { | |
| 1020 library = null; | |
| 1021 } | |
| 1022 | |
| 1023 script = map['script']; | |
| 1024 | |
| 1025 isAbstract = map['abstract']; | |
| 1026 isConst = map['const']; | |
| 1027 isFinalized = map['finalized']; | |
| 1028 isPatch = map['patch']; | |
| 1029 isImplemented = map['implemented']; | |
| 1030 | |
| 1031 tokenPos = map['tokenPos']; | |
| 1032 | |
| 1033 subClasses.clear(); | |
| 1034 subClasses.addAll(map['subclasses']); | |
| 1035 | |
| 1036 fields.clear(); | |
| 1037 fields.addAll(map['fields']); | |
| 1038 | |
| 1039 functions.clear(); | |
| 1040 functions.addAll(map['functions']); | |
| 1041 | |
| 1042 superClass = map['super']; | |
| 1043 if (superClass != null) { | |
| 1044 superClass._addToChildren(this); | |
| 1045 } | |
| 1046 error = map['error']; | |
| 1047 } | |
| 1048 | |
| 1049 void _addToChildren(Class cls) { | |
| 1050 if (children.contains(cls)) { | |
| 1051 return; | |
| 1052 } | |
| 1053 children.add(cls); | |
| 1054 } | |
| 1055 } | |
| 1056 | |
| 948 class ScriptLine { | 1057 class ScriptLine { |
| 949 @reflectable final int line; | 1058 @reflectable final int line; |
| 950 @reflectable final String text; | 1059 @reflectable final String text; |
| 951 ScriptLine(this.line, this.text); | 1060 ScriptLine(this.line, this.text); |
| 952 } | 1061 } |
| 953 | 1062 |
| 954 class Script extends ServiceObject { | 1063 class Script extends ServiceObject { |
| 955 @reflectable final lines = new ObservableList<ScriptLine>(); | 1064 @reflectable final lines = new ObservableList<ScriptLine>(); |
| 956 @reflectable final hits = new ObservableMap<int, int>(); | 1065 @reflectable final hits = new ObservableMap<int, int>(); |
| 957 @observable String kind; | 1066 @observable String kind; |
| (...skipping 668 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1626 var v = list[i]; | 1735 var v = list[i]; |
| 1627 if ((v is ObservableMap) && _isServiceMap(v)) { | 1736 if ((v is ObservableMap) && _isServiceMap(v)) { |
| 1628 list[i] = owner.getFromMap(v); | 1737 list[i] = owner.getFromMap(v); |
| 1629 } else if (v is ObservableList) { | 1738 } else if (v is ObservableList) { |
| 1630 _upgradeObservableList(v, owner); | 1739 _upgradeObservableList(v, owner); |
| 1631 } else if (v is ObservableMap) { | 1740 } else if (v is ObservableMap) { |
| 1632 _upgradeObservableMap(v, owner); | 1741 _upgradeObservableMap(v, owner); |
| 1633 } | 1742 } |
| 1634 } | 1743 } |
| 1635 } | 1744 } |
| OLD | NEW |