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] represents a persistent object within the vm. |
8 /// to an owning [Isolate]. | |
9 abstract class ServiceObject extends Observable { | 8 abstract class ServiceObject extends Observable { |
10 static int LexicalSortName(ServiceObject o1, ServiceObject o2) { | 9 static int LexicalSortName(ServiceObject o1, ServiceObject o2) { |
11 return o1.name.compareTo(o2.name); | 10 return o1.name.compareTo(o2.name); |
12 } | 11 } |
13 | 12 |
14 List removeDuplicatesAndSortLexical(List<ServiceObject> list) { | 13 List removeDuplicatesAndSortLexical(List<ServiceObject> list) { |
15 return list.toSet().toList()..sort(LexicalSortName); | 14 return list.toSet().toList()..sort(LexicalSortName); |
16 } | 15 } |
17 | 16 |
18 /// The owner of this [ServiceObject]. This can be an [Isolate], a | 17 /// The owner of this [ServiceObject]. This can be an [Isolate], a |
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
83 | 82 |
84 // Kinds of Instance. | 83 // Kinds of Instance. |
85 bool get isMirrorReference => vmType == 'MirrorReference'; | 84 bool get isMirrorReference => vmType == 'MirrorReference'; |
86 bool get isWeakProperty => vmType == 'WeakProperty'; | 85 bool get isWeakProperty => vmType == 'WeakProperty'; |
87 bool get isClosure => false; | 86 bool get isClosure => false; |
88 bool get isPlainInstance { | 87 bool get isPlainInstance { |
89 return (type == 'Instance' && | 88 return (type == 'Instance' && |
90 !isMirrorReference && !isWeakProperty && !isClosure); | 89 !isMirrorReference && !isWeakProperty && !isClosure); |
91 } | 90 } |
92 | 91 |
93 /// The complete service url of this object. | |
94 @reflectable String get link => _owner.relativeLink(_id); | |
95 | |
96 /// Has this object been fully loaded? | 92 /// Has this object been fully loaded? |
97 bool get loaded => _loaded; | 93 bool get loaded => _loaded; |
98 bool _loaded = false; | 94 bool _loaded = false; |
99 // TODO(turnidge): Make loaded observable and get rid of loading | 95 // TODO(turnidge): Make loaded observable and get rid of loading |
100 // from Isolate. | 96 // from Isolate. |
101 | 97 |
102 /// Is this object cacheable? That is, is it impossible for the [id] | 98 /// Is this object cacheable? That is, is it impossible for the [id] |
103 /// of this object to change? | 99 /// of this object to change? |
104 bool get canCache => false; | 100 bool get canCache => false; |
105 | 101 |
(...skipping 169 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
275 _vmType = _stripRef(map['_vmType']); | 271 _vmType = _stripRef(map['_vmType']); |
276 } else { | 272 } else { |
277 _vmType = _type; | 273 _vmType = _type; |
278 } | 274 } |
279 | 275 |
280 _update(map, mapIsRef); | 276 _update(map, mapIsRef); |
281 } | 277 } |
282 | 278 |
283 // Updates internal state from [map]. [map] can be a reference. | 279 // Updates internal state from [map]. [map] can be a reference. |
284 void _update(ObservableMap map, bool mapIsRef); | 280 void _update(ObservableMap map, bool mapIsRef); |
285 | |
286 String relativeLink(String id) { | |
287 assert(id != null); | |
288 return "${link}/${id}"; | |
289 } | |
290 } | 281 } |
291 | 282 |
292 abstract class Coverage { | 283 abstract class Coverage { |
293 // Following getters and functions will be provided by [ServiceObject]. | 284 // Following getters and functions will be provided by [ServiceObject]. |
294 ServiceObjectOwner get owner; | 285 ServiceObjectOwner get owner; |
295 String get type; | 286 String get type; |
296 VM get vm; | 287 VM get vm; |
297 String relativeLink(String id); | |
298 | 288 |
299 /// Default handler for coverage data. | 289 /// Default handler for coverage data. |
300 void processCoverageData(List coverageData) { | 290 void processCoverageData(List coverageData) { |
301 coverageData.forEach((scriptCoverage) { | 291 coverageData.forEach((scriptCoverage) { |
302 assert(scriptCoverage['script'] != null); | 292 assert(scriptCoverage['script'] != null); |
303 scriptCoverage['script']._processHits(scriptCoverage['hits']); | 293 scriptCoverage['script']._processHits(scriptCoverage['hits']); |
304 }); | 294 }); |
305 } | 295 } |
306 | 296 |
307 Future refreshCoverage() { | 297 Future refreshCoverage() { |
(...skipping 14 matching lines...) Expand all Loading... |
322 } | 312 } |
323 | 313 |
324 abstract class ServiceObjectOwner extends ServiceObject { | 314 abstract class ServiceObjectOwner extends ServiceObject { |
325 /// Creates an empty [ServiceObjectOwner]. | 315 /// Creates an empty [ServiceObjectOwner]. |
326 ServiceObjectOwner._empty(ServiceObjectOwner owner) : super._empty(owner); | 316 ServiceObjectOwner._empty(ServiceObjectOwner owner) : super._empty(owner); |
327 | 317 |
328 /// Builds a [ServiceObject] corresponding to the [id] from [map]. | 318 /// Builds a [ServiceObject] corresponding to the [id] from [map]. |
329 /// The result may come from the cache. The result will not necessarily | 319 /// The result may come from the cache. The result will not necessarily |
330 /// be [loaded]. | 320 /// be [loaded]. |
331 ServiceObject getFromMap(ObservableMap map); | 321 ServiceObject getFromMap(ObservableMap map); |
332 | |
333 /// Creates a link to [id] relative to [this]. | |
334 String relativeLink(String id); | |
335 } | 322 } |
336 | 323 |
337 /// State for a VM being inspected. | 324 /// State for a VM being inspected. |
338 abstract class VM extends ServiceObjectOwner { | 325 abstract class VM extends ServiceObjectOwner { |
339 @reflectable VM get vm => this; | 326 @reflectable VM get vm => this; |
340 @reflectable Isolate get isolate => null; | 327 @reflectable Isolate get isolate => null; |
341 | 328 |
342 @reflectable Iterable<Isolate> get isolates => _isolateCache.values; | 329 @reflectable Iterable<Isolate> get isolates => _isolateCache.values; |
343 | 330 |
344 @reflectable String get link => '$id'; | |
345 @reflectable String relativeLink(String id) => '$id'; | |
346 | |
347 @observable String version = 'unknown'; | 331 @observable String version = 'unknown'; |
348 @observable String targetCPU; | 332 @observable String targetCPU; |
349 @observable int architectureBits; | 333 @observable int architectureBits; |
350 @observable double uptime = 0.0; | 334 @observable double uptime = 0.0; |
351 @observable bool assertsEnabled = false; | 335 @observable bool assertsEnabled = false; |
352 @observable bool typeChecksEnabled = false; | 336 @observable bool typeChecksEnabled = false; |
353 @observable String pid = ''; | 337 @observable String pid = ''; |
354 @observable DateTime lastUpdate; | 338 @observable DateTime lastUpdate; |
355 | 339 |
356 VM() : super._empty(null) { | 340 VM() : super._empty(null) { |
(...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
443 // Doesn't scale well. Change this to be more fine-grained. | 427 // Doesn't scale well. Change this to be more fine-grained. |
444 return reload().then((result) { | 428 return reload().then((result) { |
445 if (result is! VM) { | 429 if (result is! VM) { |
446 return null; | 430 return null; |
447 } | 431 } |
448 assert(result == this); | 432 assert(result == this); |
449 return _isolateCache[isolateId]; | 433 return _isolateCache[isolateId]; |
450 }); | 434 }); |
451 } | 435 } |
452 | 436 |
453 Future<ServiceObject> getDeprecated(String id) { | |
454 assert(id.startsWith('/') == false); | |
455 // Isolates are handled specially, since they can cache sub-objects. | |
456 if (id.startsWith(_isolatesPrefix)) { | |
457 String isolateId = _parseIsolateId(id); | |
458 String objectId = _parseObjectId(id); | |
459 return getIsolate(isolateId).then((isolate) { | |
460 if (isolate == null) { | |
461 // The isolate does not exist. Return the VM object instead. | |
462 // | |
463 // TODO(turnidge): Generate a service error? | |
464 return this; | |
465 } | |
466 if (objectId == null) { | |
467 return isolate.reload(); | |
468 } else { | |
469 return isolate.getDeprecated(objectId); | |
470 } | |
471 }); | |
472 } | |
473 | |
474 var obj = _cache[id]; | |
475 if (obj != null) { | |
476 return obj.reload(); | |
477 } | |
478 | |
479 // Cache miss. Get the object from the vm directly. | |
480 return _getAsMapDeprecated(id).then((ObservableMap map) { | |
481 var obj = new ServiceObject._fromMap(this, map); | |
482 if (obj.canCache) { | |
483 _cache.putIfAbsent(id, () => obj); | |
484 } | |
485 return obj; | |
486 }); | |
487 } | |
488 | |
489 dynamic _reviver(dynamic key, dynamic value) { | 437 dynamic _reviver(dynamic key, dynamic value) { |
490 return value; | 438 return value; |
491 } | 439 } |
492 | 440 |
493 ObservableMap _parseJSON(String response) { | 441 ObservableMap _parseJSON(String response) { |
494 var map; | 442 var map; |
495 try { | 443 try { |
496 var decoder = new JsonDecoder(_reviver); | 444 var decoder = new JsonDecoder(_reviver); |
497 map = decoder.convert(response); | 445 map = decoder.convert(response); |
498 } catch (e) { | 446 } catch (e) { |
(...skipping 21 matching lines...) Expand all Loading... |
520 // Preemptively capture ServiceError and ServiceExceptions. | 468 // Preemptively capture ServiceError and ServiceExceptions. |
521 if (map['type'] == 'ServiceError') { | 469 if (map['type'] == 'ServiceError') { |
522 return new Future.error(new ServiceObject._fromMap(this, map)); | 470 return new Future.error(new ServiceObject._fromMap(this, map)); |
523 } else if (map['type'] == 'ServiceException') { | 471 } else if (map['type'] == 'ServiceException') { |
524 return new Future.error(new ServiceObject._fromMap(this, map)); | 472 return new Future.error(new ServiceObject._fromMap(this, map)); |
525 } | 473 } |
526 // map is now guaranteed to be a non-error/exception ServiceObject. | 474 // map is now guaranteed to be a non-error/exception ServiceObject. |
527 return new Future.value(map); | 475 return new Future.value(map); |
528 } | 476 } |
529 | 477 |
530 /// Gets [id] as an [ObservableMap] from the service directly. If | |
531 /// an error occurs, the future is completed as an error with a | |
532 /// ServiceError or ServiceException. Therefore any chained then() calls | |
533 /// will only receive a map encoding a valid ServiceObject. | |
534 Future<ObservableMap> _getAsMapDeprecated(String id) { | |
535 return getStringDeprecated(id).then((response) { | |
536 var map = _parseJSON(response); | |
537 if (Tracer.current != null) { | |
538 Tracer.current.trace("Received response for ${id}", map:map); | |
539 } | |
540 return _processMap(map); | |
541 }).catchError((error) { | |
542 // ServiceError, forward to VM's ServiceError stream. | |
543 errors.add(error); | |
544 return new Future.error(error); | |
545 }, test: (e) => e is ServiceError).catchError((exception) { | |
546 // ServiceException, forward to VM's ServiceException stream. | |
547 exceptions.add(exception); | |
548 return new Future.error(exception); | |
549 }, test: (e) => e is ServiceException); | |
550 } | |
551 | |
552 /// Get [id] as a [String] from the service directly. See [getAsMap]. | |
553 Future<String> getStringDeprecated(String id); | |
554 | |
555 // Implemented in subclass. | 478 // Implemented in subclass. |
556 Future<String> invokeRpcRaw(String method, Map params); | 479 Future<String> invokeRpcRaw(String method, Map params); |
557 | 480 |
558 Future<ObservableMap> invokeRpcNoUpgrade(String method, Map params) { | 481 Future<ObservableMap> invokeRpcNoUpgrade(String method, Map params) { |
559 return invokeRpcRaw(method, params).then((String response) { | 482 return invokeRpcRaw(method, params).then((String response) { |
560 var map = _parseJSON(response); | 483 var map = _parseJSON(response); |
561 if (Tracer.current != null) { | 484 if (Tracer.current != null) { |
562 Tracer.current.trace("Received response for ${method}/${params}}", | 485 Tracer.current.trace("Received response for ${method}/${params}}", |
563 map:map); | 486 map:map); |
564 } | 487 } |
(...skipping 20 matching lines...) Expand all Loading... |
585 _cache.putIfAbsent(id, () => obj); | 508 _cache.putIfAbsent(id, () => obj); |
586 } | 509 } |
587 return obj; | 510 return obj; |
588 }); | 511 }); |
589 } | 512 } |
590 | 513 |
591 Future<ObservableMap> _fetchDirect() { | 514 Future<ObservableMap> _fetchDirect() { |
592 return invokeRpcNoUpgrade('getVM', {}); | 515 return invokeRpcNoUpgrade('getVM', {}); |
593 } | 516 } |
594 | 517 |
| 518 Future<ServiceObject> getFlagList() { |
| 519 return invokeRpc('getFlagList', {}); |
| 520 } |
| 521 |
595 /// Force the VM to disconnect. | 522 /// Force the VM to disconnect. |
596 void disconnect(); | 523 void disconnect(); |
597 /// Completes when the VM first connects. | 524 /// Completes when the VM first connects. |
598 Future get onConnect; | 525 Future get onConnect; |
599 /// Completes when the VM disconnects or there was an error connecting. | 526 /// Completes when the VM disconnects or there was an error connecting. |
600 Future get onDisconnect; | 527 Future get onDisconnect; |
601 | 528 |
602 void _update(ObservableMap map, bool mapIsRef) { | 529 void _update(ObservableMap map, bool mapIsRef) { |
603 if (mapIsRef) { | 530 if (mapIsRef) { |
604 return; | 531 return; |
(...skipping 142 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
747 | 674 |
748 HeapSnapshot(this.isolate, ByteData data) : | 675 HeapSnapshot(this.isolate, ByteData data) : |
749 graph = new ObjectGraph(new ReadStream(data)), | 676 graph = new ObjectGraph(new ReadStream(data)), |
750 timeStamp = new DateTime.now() { | 677 timeStamp = new DateTime.now() { |
751 } | 678 } |
752 | 679 |
753 List<Future<ServiceObject>> getMostRetained({int classId, int limit}) { | 680 List<Future<ServiceObject>> getMostRetained({int classId, int limit}) { |
754 var result = []; | 681 var result = []; |
755 for (var v in graph.getMostRetained(classId: classId, limit: limit)) { | 682 for (var v in graph.getMostRetained(classId: classId, limit: limit)) { |
756 var address = v.addressForWordSize(isolate.vm.architectureBits ~/ 8); | 683 var address = v.addressForWordSize(isolate.vm.architectureBits ~/ 8); |
757 result.add(isolate.getDeprecated( | 684 result.add(isolate.getObjectByAddress(address.toRadixString(16)).then((obj
) { |
758 'address/${address.toRadixString(16)}?ref=true').then((obj) { | |
759 obj.retainedSize = v.retainedSize; | 685 obj.retainedSize = v.retainedSize; |
760 return new Future(() => obj); | 686 return new Future(() => obj); |
761 })); | 687 })); |
762 } | 688 } |
763 return result; | 689 return result; |
764 } | 690 } |
765 | 691 |
766 | 692 |
767 } | 693 } |
768 | 694 |
769 /// State for a running isolate. | 695 /// State for a running isolate. |
770 class Isolate extends ServiceObjectOwner with Coverage { | 696 class Isolate extends ServiceObjectOwner with Coverage { |
771 @reflectable VM get vm => owner; | 697 @reflectable VM get vm => owner; |
772 @reflectable Isolate get isolate => this; | 698 @reflectable Isolate get isolate => this; |
773 @observable ObservableMap counters = new ObservableMap(); | 699 @observable ObservableMap counters = new ObservableMap(); |
774 | 700 |
775 String get link => '/${_id}'; | |
776 | |
777 @observable ServiceEvent pauseEvent = null; | 701 @observable ServiceEvent pauseEvent = null; |
778 bool get _isPaused => pauseEvent != null; | 702 bool get _isPaused => pauseEvent != null; |
779 | 703 |
780 @observable bool running = false; | 704 @observable bool running = false; |
781 @observable bool idle = false; | 705 @observable bool idle = false; |
782 @observable bool loading = true; | 706 @observable bool loading = true; |
783 @observable bool ioEnabled = false; | 707 @observable bool ioEnabled = false; |
784 | 708 |
785 Map<String,ServiceObject> _cache = new Map<String,ServiceObject>(); | 709 Map<String,ServiceObject> _cache = new Map<String,ServiceObject>(); |
786 final TagProfile tagProfile = new TagProfile(20); | 710 final TagProfile tagProfile = new TagProfile(20); |
787 | 711 |
788 Isolate._empty(ServiceObjectOwner owner) : super._empty(owner) { | 712 Isolate._empty(ServiceObjectOwner owner) : super._empty(owner) { |
789 assert(owner is VM); | 713 assert(owner is VM); |
790 } | 714 } |
791 | 715 |
792 /// Creates a link to [id] relative to [this]. | |
793 @reflectable String relativeLink(String id) => '/${this.id}/$id'; | |
794 | |
795 static const TAG_ROOT_ID = 'code/tag-0'; | 716 static const TAG_ROOT_ID = 'code/tag-0'; |
796 | 717 |
797 /// Returns the Code object for the root tag. | 718 /// Returns the Code object for the root tag. |
798 Code tagRoot() { | 719 Code tagRoot() { |
799 // TODO(turnidge): Use get() here instead? | 720 // TODO(turnidge): Use get() here instead? |
800 return _cache[TAG_ROOT_ID]; | 721 return _cache[TAG_ROOT_ID]; |
801 } | 722 } |
802 | 723 |
803 void processProfile(ServiceMap profile) { | 724 void processProfile(ServiceMap profile) { |
804 assert(profile.type == 'CpuProfile'); | 725 assert(profile.type == 'CpuProfile'); |
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
883 return obj; | 804 return obj; |
884 } | 805 } |
885 // Build the object from the map directly. | 806 // Build the object from the map directly. |
886 obj = new ServiceObject._fromMap(this, map); | 807 obj = new ServiceObject._fromMap(this, map); |
887 if (obj != null && obj.canCache) { | 808 if (obj != null && obj.canCache) { |
888 _cache[id] = obj; | 809 _cache[id] = obj; |
889 } | 810 } |
890 return obj; | 811 return obj; |
891 } | 812 } |
892 | 813 |
893 Future<ServiceObject> getDeprecated(String id) { | |
894 // Do not allow null ids or empty ids. | |
895 assert(id != null && id != ''); | |
896 var obj = _cache[id]; | |
897 if (obj != null) { | |
898 return obj.reload(); | |
899 } | |
900 // Cache miss. Get the object from the vm directly. | |
901 return vm._getAsMapDeprecated(relativeLink(id)).then((ObservableMap map) { | |
902 var obj = new ServiceObject._fromMap(this, map); | |
903 if (obj.canCache) { | |
904 _cache.putIfAbsent(id, () => obj); | |
905 } | |
906 return obj; | |
907 }); | |
908 } | |
909 | |
910 Future<ObservableMap> invokeRpcNoUpgrade(String method, Map params) { | 814 Future<ObservableMap> invokeRpcNoUpgrade(String method, Map params) { |
911 params['isolate'] = id; | 815 params['isolateId'] = id; |
912 return vm.invokeRpcNoUpgrade(method, params); | 816 return vm.invokeRpcNoUpgrade(method, params); |
913 } | 817 } |
914 | 818 |
915 Future<ServiceObject> invokeRpc(String method, Map params) { | 819 Future<ServiceObject> invokeRpc(String method, Map params) { |
916 return invokeRpcNoUpgrade(method, params).then((ObservableMap response) { | 820 return invokeRpcNoUpgrade(method, params).then((ObservableMap response) { |
917 var obj = new ServiceObject._fromMap(this, response); | 821 var obj = new ServiceObject._fromMap(this, response); |
918 if (obj.canCache) { | 822 if (obj.canCache) { |
919 _cache.putIfAbsent(id, () => obj); | 823 _cache.putIfAbsent(id, () => obj); |
920 } | 824 } |
921 return obj; | 825 return obj; |
(...skipping 398 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1320 } | 1224 } |
1321 | 1225 |
1322 Future<ServiceObject> getInstances(Class cls, var limit) { | 1226 Future<ServiceObject> getInstances(Class cls, var limit) { |
1323 Map params = { | 1227 Map params = { |
1324 'classId': cls.id, | 1228 'classId': cls.id, |
1325 'limit': limit.toString(), | 1229 'limit': limit.toString(), |
1326 }; | 1230 }; |
1327 return invokeRpc('getInstances', params); | 1231 return invokeRpc('getInstances', params); |
1328 } | 1232 } |
1329 | 1233 |
| 1234 Future<ServiceObject> getObjectByAddress(String address, [bool ref=true]) { |
| 1235 Map params = { |
| 1236 'address': address, |
| 1237 'ref': ref, |
| 1238 }; |
| 1239 return invokeRpc('getObjectByAddress', params); |
| 1240 } |
| 1241 |
1330 final ObservableMap<String, ServiceMetric> dartMetrics = | 1242 final ObservableMap<String, ServiceMetric> dartMetrics = |
1331 new ObservableMap<String, ServiceMetric>(); | 1243 new ObservableMap<String, ServiceMetric>(); |
1332 | 1244 |
1333 final ObservableMap<String, ServiceMetric> nativeMetrics = | 1245 final ObservableMap<String, ServiceMetric> nativeMetrics = |
1334 new ObservableMap<String, ServiceMetric>(); | 1246 new ObservableMap<String, ServiceMetric>(); |
1335 | 1247 |
1336 Future<ObservableMap<String, ServiceMetric>> _refreshMetrics( | 1248 Future<ObservableMap<String, ServiceMetric>> _refreshMetrics( |
1337 String metricType, | 1249 String metricType, |
1338 ObservableMap<String, ServiceMetric> metricsMap) { | 1250 ObservableMap<String, ServiceMetric> metricsMap) { |
1339 return invokeRpc('getIsolateMetricList', | 1251 return invokeRpc('getIsolateMetricList', |
(...skipping 1602 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2942 var v = list[i]; | 2854 var v = list[i]; |
2943 if ((v is ObservableMap) && _isServiceMap(v)) { | 2855 if ((v is ObservableMap) && _isServiceMap(v)) { |
2944 list[i] = owner.getFromMap(v); | 2856 list[i] = owner.getFromMap(v); |
2945 } else if (v is ObservableList) { | 2857 } else if (v is ObservableList) { |
2946 _upgradeObservableList(v, owner); | 2858 _upgradeObservableList(v, owner); |
2947 } else if (v is ObservableMap) { | 2859 } else if (v is ObservableMap) { |
2948 _upgradeObservableMap(v, owner); | 2860 _upgradeObservableMap(v, owner); |
2949 } | 2861 } |
2950 } | 2862 } |
2951 } | 2863 } |
OLD | NEW |