Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(436)

Side by Side Diff: runtime/observatory/lib/src/service/object.dart

Issue 979823003: Major rework of vm service events. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 5 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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 346 matching lines...) Expand 10 before | Expand all | Expand 10 after
357 } 357 }
358 358
359 final StreamController<ServiceException> exceptions = 359 final StreamController<ServiceException> exceptions =
360 new StreamController.broadcast(); 360 new StreamController.broadcast();
361 final StreamController<ServiceError> errors = 361 final StreamController<ServiceError> errors =
362 new StreamController.broadcast(); 362 new StreamController.broadcast();
363 final StreamController<ServiceEvent> events = 363 final StreamController<ServiceEvent> events =
364 new StreamController.broadcast(); 364 new StreamController.broadcast();
365 365
366 bool _isIsolateLifecycleEvent(String eventType) { 366 bool _isIsolateLifecycleEvent(String eventType) {
367 return _isIsolateShutdownEvent(eventType) || 367 return _isIsolateExitEvent(eventType) ||
368 _isIsolateCreatedEvent(eventType); 368 _isIsolateStartEvent(eventType);
369 } 369 }
370 370
371 bool _isIsolateShutdownEvent(String eventType) { 371 bool _isIsolateExitEvent(String eventType) {
372 return (eventType == 'IsolateShutdown'); 372 return (eventType == ServiceEvent.kIsolateExit);
373 } 373 }
374 374
375 bool _isIsolateCreatedEvent(String eventType) { 375 bool _isIsolateStartEvent(String eventType) {
376 return (eventType == 'IsolateCreated'); 376 return (eventType == ServiceEvent.kIsolateStart);
377 } 377 }
378 378
379 void postServiceEvent(String response, ByteData data) { 379 void postServiceEvent(String response, ByteData data) {
380 var map; 380 var map;
381 try { 381 try {
382 map = _parseJSON(response); 382 map = _parseJSON(response);
383 assert(!map.containsKey('_data')); 383 assert(!map.containsKey('_data'));
384 if (data != null) { 384 if (data != null) {
385 map['_data'] = data; 385 map['_data'] = data;
386 } 386 }
387 } catch (e, st) { 387 } catch (e, st) {
388 Logger.root.severe('Ignoring malformed event response: ${response}'); 388 Logger.root.severe('Ignoring malformed event response: ${response}');
389 return; 389 return;
390 } 390 }
391 if (map['type'] != 'ServiceEvent') { 391 if (map['type'] != 'ServiceEvent') {
392 Logger.root.severe( 392 Logger.root.severe(
393 "Expected 'ServiceEvent' but found '${map['type']}'"); 393 "Expected 'ServiceEvent' but found '${map['type']}'");
394 return; 394 return;
395 } 395 }
396 396
397 var eventType = map['eventType']; 397 var eventType = map['eventType'];
398 398
399 if (_isIsolateLifecycleEvent(eventType)) { 399 if (_isIsolateLifecycleEvent(eventType)) {
400 String isolateId = map['isolate']['id']; 400 String isolateId = map['isolate']['id'];
401 var event; 401 var event;
402 if (_isIsolateCreatedEvent(eventType)) { 402 if (_isIsolateStartEvent(eventType)) {
403 _onIsolateCreated(map['isolate']); 403 _onIsolateStart(map['isolate']);
404 // By constructing the event *after* adding the isolate to the 404 // By constructing the event *after* adding the isolate to the
405 // isolate cache, the call to getFromMap will use the cached Isolate. 405 // isolate cache, the call to getFromMap will use the cached Isolate.
406 event = new ServiceObject._fromMap(this, map); 406 event = new ServiceObject._fromMap(this, map);
407 } else { 407 } else {
408 assert(_isIsolateShutdownEvent(eventType)); 408 assert(_isIsolateExitEvent(eventType));
409 // By constructing the event *before* removing the isolate from the 409 // By constructing the event *before* removing the isolate from the
410 // isolate cache, the call to getFromMap will use the cached Isolate. 410 // isolate cache, the call to getFromMap will use the cached Isolate.
411 event = new ServiceObject._fromMap(this, map); 411 event = new ServiceObject._fromMap(this, map);
412 _onIsolateShutdown(isolateId); 412 _onIsolateExit(isolateId);
413 } 413 }
414 assert(event != null); 414 assert(event != null);
415 events.add(event); 415 events.add(event);
416 return; 416 return;
417 } 417 }
418 418
419 // Extract the owning isolate from the event itself. 419 // Extract the owning isolate from the event itself.
420 String owningIsolateId = map['isolate']['id']; 420 String owningIsolateId = map['isolate']['id'];
421 getIsolate(owningIsolateId).then((owningIsolate) { 421 getIsolate(owningIsolateId).then((owningIsolate) {
422 if (owningIsolate == null) { 422 if (owningIsolate == null) {
423 // TODO(koda): Do we care about GC events in VM isolate? 423 // TODO(koda): Do we care about GC events in VM isolate?
424 Logger.root.severe('Ignoring event with unknown isolate id: ' 424 Logger.root.severe('Ignoring event with unknown isolate id: '
425 '$owningIsolateId'); 425 '$owningIsolateId');
426 return; 426 return;
427 } 427 }
428 var event = new ServiceObject._fromMap(owningIsolate, map); 428 var event = new ServiceObject._fromMap(owningIsolate, map);
429 owningIsolate._onEvent(event);
429 events.add(event); 430 events.add(event);
430 }); 431 });
431 } 432 }
432 433
433 Isolate _onIsolateCreated(Map isolateMap) { 434 Isolate _onIsolateStart(Map isolateMap) {
434 var isolateId = isolateMap['id']; 435 var isolateId = isolateMap['id'];
435 assert(!_isolateCache.containsKey(isolateId)); 436 assert(!_isolateCache.containsKey(isolateId));
436 Isolate isolate = new ServiceObject._fromMap(this, isolateMap); 437 Isolate isolate = new ServiceObject._fromMap(this, isolateMap);
437 _isolateCache[isolateId] = isolate; 438 _isolateCache[isolateId] = isolate;
438 notifyPropertyChange(#isolates, true, false); 439 notifyPropertyChange(#isolates, true, false);
439 // Eagerly load the isolate. 440 // Eagerly load the isolate.
440 isolate.load().catchError((e) { 441 isolate.load().catchError((e) {
441 Logger.root.info('Eagerly loading an isolate failed: $e'); 442 Logger.root.info('Eagerly loading an isolate failed: $e');
442 }); 443 });
443 return isolate; 444 return isolate;
444 } 445 }
445 446
446 void _onIsolateShutdown(String isolateId) { 447 void _onIsolateExit(String isolateId) {
447 assert(_isolateCache.containsKey(isolateId)); 448 assert(_isolateCache.containsKey(isolateId));
448 _isolateCache.remove(isolateId); 449 _isolateCache.remove(isolateId);
449 notifyPropertyChange(#isolates, true, false); 450 notifyPropertyChange(#isolates, true, false);
450 } 451 }
451 452
452 void _updateIsolatesFromList(List isolateList) { 453 void _updateIsolatesFromList(List isolateList) {
453 var shutdownIsolates = <String>[]; 454 var shutdownIsolates = <String>[];
454 var createdIsolates = <Map>[]; 455 var createdIsolates = <Map>[];
455 var isolateStillExists = <String, bool>{}; 456 var isolateStillExists = <String, bool>{};
456 457
(...skipping 14 matching lines...) Expand all
471 472
472 // Find shutdown isolates. 473 // Find shutdown isolates.
473 isolateStillExists.forEach((isolateId, exists) { 474 isolateStillExists.forEach((isolateId, exists) {
474 if (!exists) { 475 if (!exists) {
475 shutdownIsolates.add(isolateId); 476 shutdownIsolates.add(isolateId);
476 } 477 }
477 }); 478 });
478 479
479 // Process shutdown. 480 // Process shutdown.
480 for (var isolateId in shutdownIsolates) { 481 for (var isolateId in shutdownIsolates) {
481 _onIsolateShutdown(isolateId); 482 _onIsolateExit(isolateId);
482 } 483 }
483 484
484 // Process creation. 485 // Process creation.
485 for (var isolateMap in createdIsolates) { 486 for (var isolateMap in createdIsolates) {
486 _onIsolateCreated(isolateMap); 487 _onIsolateStart(isolateMap);
487 } 488 }
488 } 489 }
489 490
490 static final String _isolateIdPrefix = 'isolates/'; 491 static final String _isolateIdPrefix = 'isolates/';
491 492
492 ServiceObject getFromMap(ObservableMap map) { 493 ServiceObject getFromMap(ObservableMap map) {
493 if (map == null) { 494 if (map == null) {
494 return null; 495 return null;
495 } 496 }
496 String id = map['id']; 497 String id = map['id'];
497 if (!id.startsWith(_isolateIdPrefix)) { 498 if (!id.startsWith(_isolateIdPrefix)) {
498 // Currently the VM only supports upgrading Isolate ServiceObjects. 499 // Currently the VM only supports upgrading Isolate ServiceObjects.
499 throw new UnimplementedError(); 500 throw new UnimplementedError();
500 } 501 }
501 502
502 // Check cache. 503 // Check cache.
503 var isolate = _isolateCache[id]; 504 var isolate = _isolateCache[id];
504 if (isolate == null) { 505 if (isolate == null) {
505 // We should never see an unknown isolate here. 506 // We should never see an unknown isolate here.
506 throw new UnimplementedError(); 507 throw new UnimplementedError();
507 } 508 }
509 var mapIsRef = _hasRef(map['type']);
510 if (!mapIsRef) {
511 isolate.update(map);
512 }
508 return isolate; 513 return isolate;
509 } 514 }
510 515
511 // Note that this function does not reload the isolate if it found 516 // Note that this function does not reload the isolate if it found
512 // in the cache. 517 // in the cache.
513 Future<ServiceObject> getIsolate(String isolateId) { 518 Future<ServiceObject> getIsolate(String isolateId) {
514 if (!loaded) { 519 if (!loaded) {
515 // Trigger a VM load, then get the isolate. 520 // Trigger a VM load, then get the isolate.
516 return load().then((_) => getIsolate(isolateId)).catchError(_ignoreError); 521 return load().then((_) => getIsolate(isolateId)).catchError(_ignoreError);
517 } 522 }
(...skipping 249 matching lines...) Expand 10 before | Expand all | Expand 10 after
767 772
768 } 773 }
769 774
770 /// State for a running isolate. 775 /// State for a running isolate.
771 class Isolate extends ServiceObjectOwner with Coverage { 776 class Isolate extends ServiceObjectOwner with Coverage {
772 @reflectable VM get vm => owner; 777 @reflectable VM get vm => owner;
773 @reflectable Isolate get isolate => this; 778 @reflectable Isolate get isolate => this;
774 @observable ObservableMap counters = new ObservableMap(); 779 @observable ObservableMap counters = new ObservableMap();
775 780
776 @observable ServiceEvent pauseEvent = null; 781 @observable ServiceEvent pauseEvent = null;
777 bool get _isPaused => pauseEvent != null;
778 782
783 void _updateRunState() {
784 topFrame = (pauseEvent != null ? pauseEvent.topFrame : null);
785 paused = (pauseEvent != null &&
786 pauseEvent.eventType != ServiceEvent.kResume);
787 running = (!paused && topFrame != null);
788 idle = (!paused && topFrame == null);
789 notifyPropertyChange(#topFrame, 0, 1);
790 notifyPropertyChange(#paused, 0, 1);
791 notifyPropertyChange(#running, 0, 1);
792 notifyPropertyChange(#idle, 0, 1);
793 }
794
795 @observable bool paused = false;
779 @observable bool running = false; 796 @observable bool running = false;
780 @observable bool idle = false; 797 @observable bool idle = false;
781 @observable bool loading = true; 798 @observable bool loading = true;
799
782 @observable bool ioEnabled = false; 800 @observable bool ioEnabled = false;
783 801
784 Map<String,ServiceObject> _cache = new Map<String,ServiceObject>(); 802 Map<String,ServiceObject> _cache = new Map<String,ServiceObject>();
785 final TagProfile tagProfile = new TagProfile(20); 803 final TagProfile tagProfile = new TagProfile(20);
786 804
787 Isolate._empty(ServiceObjectOwner owner) : super._empty(owner) { 805 Isolate._empty(ServiceObjectOwner owner) : super._empty(owner) {
788 assert(owner is VM); 806 assert(owner is VM);
789 } 807 }
790 808
791 void resetCachedProfileData() { 809 void resetCachedProfileData() {
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
837 return new Future.value(objectClass); 855 return new Future.value(objectClass);
838 } 856 }
839 857
840 ServiceObject getFromMap(ObservableMap map) { 858 ServiceObject getFromMap(ObservableMap map) {
841 if (map == null) { 859 if (map == null) {
842 return null; 860 return null;
843 } 861 }
844 String mapId = map['id']; 862 String mapId = map['id'];
845 var obj = (mapId != null) ? _cache[mapId] : null; 863 var obj = (mapId != null) ? _cache[mapId] : null;
846 if (obj != null) { 864 if (obj != null) {
847 // Consider calling update when map is not a reference. 865 var mapIsRef = _hasRef(map['type']);
866 if (!mapIsRef) {
867 obj.update(map);
868 }
848 return obj; 869 return obj;
849 } 870 }
850 // Build the object from the map directly. 871 // Build the object from the map directly.
851 obj = new ServiceObject._fromMap(this, map); 872 obj = new ServiceObject._fromMap(this, map);
852 if ((obj != null) && obj.canCache) { 873 if ((obj != null) && obj.canCache) {
853 _cache[mapId] = obj; 874 _cache[mapId] = obj;
854 } 875 }
855 return obj; 876 return obj;
856 } 877 }
857 878
858 Future<ObservableMap> invokeRpcNoUpgrade(String method, Map params) { 879 Future<ObservableMap> invokeRpcNoUpgrade(String method, Map params) {
859 params['isolateId'] = id; 880 params['isolateId'] = id;
860 return vm.invokeRpcNoUpgrade(method, params); 881 return vm.invokeRpcNoUpgrade(method, params);
861 } 882 }
862 883
863 Future<ServiceObject> invokeRpc(String method, Map params) { 884 Future<ServiceObject> invokeRpc(String method, Map params) {
864 return invokeRpcNoUpgrade(method, params).then((ObservableMap response) { 885 return invokeRpcNoUpgrade(method, params).then((ObservableMap response) {
865 var obj = new ServiceObject._fromMap(this, response); 886 return getFromMap(response);
866 if ((obj != null) && obj.canCache) {
867 String objId = obj.id;
868 _cache.putIfAbsent(objId, () => obj);
869 }
870 return obj;
871 }); 887 });
872 } 888 }
873 889
874 Future<ServiceObject> getObject(String objectId) { 890 Future<ServiceObject> getObject(String objectId) {
875 assert(objectId != null && objectId != ''); 891 assert(objectId != null && objectId != '');
876 var obj = _cache[objectId]; 892 var obj = _cache[objectId];
877 if (obj != null) { 893 if (obj != null) {
878 return obj.reload(); 894 return obj.reload();
879 } 895 }
880 Map params = { 896 Map params = {
(...skipping 24 matching lines...) Expand all
905 921
906 final HeapSpace newSpace = new HeapSpace(); 922 final HeapSpace newSpace = new HeapSpace();
907 final HeapSpace oldSpace = new HeapSpace(); 923 final HeapSpace oldSpace = new HeapSpace();
908 924
909 @observable String fileAndLine; 925 @observable String fileAndLine;
910 926
911 @observable DartError error; 927 @observable DartError error;
912 @observable HeapSnapshot latestSnapshot; 928 @observable HeapSnapshot latestSnapshot;
913 Completer<HeapSnapshot> _snapshotFetch; 929 Completer<HeapSnapshot> _snapshotFetch;
914 930
915 void loadHeapSnapshot(ServiceEvent event) { 931 void _loadHeapSnapshot(ServiceEvent event) {
916 latestSnapshot = new HeapSnapshot(this, event.data); 932 latestSnapshot = new HeapSnapshot(this, event.data);
917 _snapshotFetch.complete(latestSnapshot); 933 if (_snapshotFetch != null) {
934 _snapshotFetch.complete(latestSnapshot);
935 }
918 } 936 }
919 937
920 Future<HeapSnapshot> fetchHeapSnapshot() { 938 Future<HeapSnapshot> fetchHeapSnapshot() {
921 if (_snapshotFetch == null || _snapshotFetch.isCompleted) { 939 if (_snapshotFetch == null || _snapshotFetch.isCompleted) {
922 _snapshotFetch = new Completer<HeapSnapshot>(); 940 _snapshotFetch = new Completer<HeapSnapshot>();
923 isolate.invokeRpcNoUpgrade('requestHeapSnapshot', {}); 941 isolate.invokeRpcNoUpgrade('requestHeapSnapshot', {});
924 } 942 }
925 return _snapshotFetch.future; 943 return _snapshotFetch.future;
926 } 944 }
927 945
928 void updateHeapsFromMap(ObservableMap map) { 946 void updateHeapsFromMap(ObservableMap map) {
929 newSpace.update(map['new']); 947 newSpace.update(map['new']);
930 oldSpace.update(map['old']); 948 oldSpace.update(map['old']);
931 } 949 }
932 950
933 void _update(ObservableMap map, bool mapIsRef) { 951 void _update(ObservableMap map, bool mapIsRef) {
934 mainPort = map['mainPort']; 952 mainPort = map['mainPort'];
935 name = map['name']; 953 name = map['name'];
936 vmName = map['name']; 954 vmName = map['name'];
937 if (mapIsRef) { 955 if (mapIsRef) {
938 return; 956 return;
939 } 957 }
940 _loaded = true; 958 _loaded = true;
941 loading = false; 959 loading = false;
942 960
943 reloadBreakpoints();
944 _upgradeCollection(map, isolate); 961 _upgradeCollection(map, isolate);
945 if (map['rootLib'] == null || 962 if (map['rootLib'] == null ||
946 map['timers'] == null || 963 map['timers'] == null ||
947 map['heaps'] == null) { 964 map['heaps'] == null) {
948 Logger.root.severe("Malformed 'Isolate' response: $map"); 965 Logger.root.severe("Malformed 'Isolate' response: $map");
949 return; 966 return;
950 } 967 }
951 rootLib = map['rootLib']; 968 rootLib = map['rootLib'];
952 if (map['entry'] != null) { 969 if (map['entry'] != null) {
953 entry = map['entry']; 970 entry = map['entry'];
954 } 971 }
955 if (map['topFrame'] != null) {
956 topFrame = map['topFrame'];
957 } else {
958 topFrame = null ;
959 }
960 972
961 var countersMap = map['tagCounters']; 973 var countersMap = map['tagCounters'];
962 if (countersMap != null) { 974 if (countersMap != null) {
963 var names = countersMap['names']; 975 var names = countersMap['names'];
964 var counts = countersMap['counters']; 976 var counts = countersMap['counters'];
965 assert(names.length == counts.length); 977 assert(names.length == counts.length);
966 var sum = 0; 978 var sum = 0;
967 for (var i = 0; i < counts.length; i++) { 979 for (var i = 0; i < counts.length; i++) {
968 sum += counts[i]; 980 sum += counts[i];
969 } 981 }
(...skipping 17 matching lines...) Expand all
987 timers['total'] = timerMap['time_total_runtime']; 999 timers['total'] = timerMap['time_total_runtime'];
988 timers['compile'] = timerMap['time_compilation']; 1000 timers['compile'] = timerMap['time_compilation'];
989 timers['gc'] = 0.0; // TODO(turnidge): Export this from VM. 1001 timers['gc'] = 0.0; // TODO(turnidge): Export this from VM.
990 timers['init'] = (timerMap['time_script_loading'] + 1002 timers['init'] = (timerMap['time_script_loading'] +
991 timerMap['time_creating_snapshot'] + 1003 timerMap['time_creating_snapshot'] +
992 timerMap['time_isolate_initialization'] + 1004 timerMap['time_isolate_initialization'] +
993 timerMap['time_bootstrap']); 1005 timerMap['time_bootstrap']);
994 timers['dart'] = timerMap['time_dart_execution']; 1006 timers['dart'] = timerMap['time_dart_execution'];
995 1007
996 updateHeapsFromMap(map['heaps']); 1008 updateHeapsFromMap(map['heaps']);
1009 _updateBreakpoints(map['breakpoints']);
997 1010
998 List features = map['features']; 1011 List features = map['features'];
999 if (features != null) { 1012 if (features != null) {
1000 for (var feature in features) { 1013 for (var feature in features) {
1001 if (feature == 'io') { 1014 if (feature == 'io') {
1002 ioEnabled = true; 1015 ioEnabled = true;
1003 } 1016 }
1004 } 1017 }
1005 } 1018 }
1006 // Isolate status
1007 pauseEvent = map['pauseEvent']; 1019 pauseEvent = map['pauseEvent'];
1008 running = (!_isPaused && map['topFrame'] != null); 1020 _updateRunState();
1009 idle = (!_isPaused && map['topFrame'] == null);
1010 error = map['error']; 1021 error = map['error'];
1011 1022
1012 libraries.clear(); 1023 libraries.clear();
1013 libraries.addAll(map['libraries']); 1024 libraries.addAll(map['libraries']);
1014 libraries.sort(ServiceObject.LexicalSortName); 1025 libraries.sort(ServiceObject.LexicalSortName);
1015 } 1026 }
1016 1027
1017 Future<TagProfile> updateTagProfile() { 1028 Future<TagProfile> updateTagProfile() {
1018 return isolate.invokeRpcNoUpgrade('getTagProfile', {}).then( 1029 return isolate.invokeRpcNoUpgrade('getTagProfile', {}).then(
1019 (ObservableMap map) { 1030 (ObservableMap map) {
1020 var seconds = new DateTime.now().millisecondsSinceEpoch / 1000.0; 1031 var seconds = new DateTime.now().millisecondsSinceEpoch / 1000.0;
1021 tagProfile._processTagProfile(seconds, map); 1032 tagProfile._processTagProfile(seconds, map);
1022 return tagProfile; 1033 return tagProfile;
1023 }); 1034 });
1024 } 1035 }
1025 1036
1026 ObservableList<Breakpoint> breakpoints = new ObservableList(); 1037 ObservableMap<int, Breakpoint> breakpoints = new ObservableMap();
1038
1039 void _updateBreakpoints(List newBpts) {
1040 // Build a map of new breakpoints.
1041 var newBptMap = {};
1042 newBpts.forEach((bpt) => (newBptMap[bpt.number] = bpt));
1043
1044 // Remove any old breakpoints which no longer exist.
1045 List toRemove = [];
1046 breakpoints.forEach((key, _) {
1047 if (!newBptMap.containsKey(key)) {
1048 toRemove.add(key);
1049 }
1050 });
1051 toRemove.forEach((key) => breakpoints.remove(key));
1052
1053 // Add all new breakpoints.
1054 breakpoints.addAll(newBptMap);
1055 }
1056
1057 void _addBreakpoint(Breakpoint bpt) {
1058 breakpoints[bpt.number] = bpt;
1059 }
1027 1060
1028 void _removeBreakpoint(Breakpoint bpt) { 1061 void _removeBreakpoint(Breakpoint bpt) {
1029 var script = bpt.script; 1062 breakpoints.remove(bpt.number);
1030 var tokenPos = bpt.tokenPos; 1063 bpt.remove();
1031 assert(tokenPos != null); 1064 }
1032 if (script.loaded) { 1065
1033 var line = script.tokenToLine(tokenPos); 1066 void _onEvent(ServiceEvent event) {
1034 assert(line != null); 1067 assert(event.eventType != ServiceEvent.kIsolateStart &&
1035 if (script.lines[line - 1] != null) { 1068 event.eventType != ServiceEvent.kIsolateExit);
1036 assert(script.lines[line - 1].bpt == bpt); 1069 switch(event.eventType) {
1037 script.lines[line - 1].bpt = null; 1070 case ServiceEvent.kBreakpointAdded:
1038 } 1071 _addBreakpoint(event.breakpoint);
1072 break;
1073
1074 case ServiceEvent.kBreakpointResolved:
1075 // Update occurs as side-effect of caching.
1076 break;
1077
1078 case ServiceEvent.kBreakpointRemoved:
1079 _removeBreakpoint(event.breakpoint);
1080 break;
1081
1082 case ServiceEvent.kPauseStart:
1083 case ServiceEvent.kPauseExit:
1084 case ServiceEvent.kPauseBreakpoint:
1085 case ServiceEvent.kPauseInterrupted:
1086 case ServiceEvent.kPauseException:
1087 case ServiceEvent.kResume:
1088 pauseEvent = event;
1089 _updateRunState();
1090 break;
1091
1092 case ServiceEvent.kGraph:
1093 _loadHeapSnapshot(event);
1094 break;
1095
1096 case ServiceEvent.kGC:
1097 // Ignore GC events for now.
1098 break;
1099
1100 default:
1101 // Log unrecognized events.
1102 Logger.root.severe('Unrecognized event: $event');
1103 break;
1039 } 1104 }
1040 } 1105 }
1041 1106
1042 void _addBreakpoint(Breakpoint bpt) {
1043 var script = bpt.script;
1044 var tokenPos = bpt.tokenPos;
1045 assert(tokenPos != null);
1046 if (script.loaded) {
1047 var line = script.tokenToLine(tokenPos);
1048 assert(line != null);
1049 assert(script.lines[line - 1].bpt == null);
1050 script.lines[line - 1].bpt = bpt;
1051 } else {
1052 // Load the script and then plop in the breakpoint.
1053 script.load().then((_) {
1054 _addBreakpoint(bpt);
1055 });
1056 }
1057 }
1058
1059 void _updateBreakpoints(ServiceMap newBreakpoints) {
1060 // Remove all of the old breakpoints from the Script lines.
1061 if (breakpoints != null) {
1062 for (var bpt in breakpoints) {
1063 _removeBreakpoint(bpt);
1064 }
1065 }
1066 // Add all of the new breakpoints to the Script lines.
1067 for (var bpt in newBreakpoints['breakpoints']) {
1068 _addBreakpoint(bpt);
1069 }
1070 breakpoints.clear();
1071 breakpoints.addAll(newBreakpoints['breakpoints']);
1072
1073 // Sort the breakpoints by breakpointNumber.
1074 breakpoints.sort((a, b) => (a.number - b.number));
1075 }
1076
1077 Future<ServiceObject> _inProgressReloadBpts;
1078
1079 Future reloadBreakpoints() {
1080 // TODO(turnidge): Can reusing the Future here ever cause us to
1081 // get stale breakpoints?
1082 if (_inProgressReloadBpts == null) {
1083 _inProgressReloadBpts =
1084 invokeRpc('getBreakpoints', {}).then((newBpts) {
1085 _updateBreakpoints(newBpts);
1086 }).whenComplete(() {
1087 _inProgressReloadBpts = null;
1088 });
1089 }
1090 return _inProgressReloadBpts;
1091 }
1092
1093 Future<ServiceObject> addBreakpoint(Script script, int line) { 1107 Future<ServiceObject> addBreakpoint(Script script, int line) {
1094 // TODO(turnidge): Pass line as an int instead of a string. 1108 // TODO(turnidge): Pass line as an int instead of a string.
1095 Map params = { 1109 Map params = {
1096 'scriptId': script.id, 1110 'scriptId': script.id,
1097 'line': '$line', 1111 'line': '$line',
1098 }; 1112 };
1099 return invokeRpc('addBreakpoint', params).then((result) { 1113 return invokeRpc('addBreakpoint', params).then((result) {
1100 if (result is DartError) { 1114 if (result is DartError) {
1101 return result; 1115 return result;
1102 } 1116 }
1103 Breakpoint bpt = result; 1117 Breakpoint bpt = result;
1104 if (bpt.resolved && 1118 if (bpt.resolved &&
1105 script.loaded && 1119 script.loaded &&
1106 script.tokenToLine(result.tokenPos) != line) { 1120 script.tokenToLine(result.tokenPos) != line) {
1107 // Unable to set a breakpoint at desired line. 1121 // Unable to set a breakpoint at desired line.
1108 script.lines[line - 1].possibleBpt = false; 1122 script.lines[line - 1].possibleBpt = false;
1109 } 1123 }
1110 // TODO(turnidge): Instead of reloading all of the breakpoints, 1124 return result;
1111 // rely on events to update the breakpoint list.
1112 return reloadBreakpoints().then((_) {
1113 return result;
1114 });
1115 }); 1125 });
1116 } 1126 }
1117 1127
1118 Future<ServiceObject> addBreakpointAtEntry(ServiceFunction function) { 1128 Future<ServiceObject> addBreakpointAtEntry(ServiceFunction function) {
1119 return invokeRpc('addBreakpointAtEntry', 1129 return invokeRpc('addBreakpointAtEntry',
1120 { 'functionId': function.id }).then((result) { 1130 { 'functionId': function.id });
1121 // TODO(turnidge): Instead of reloading all of the breakpoints,
1122 // rely on events to update the breakpoint list.
1123 return reloadBreakpoints().then((_) {
1124 return result;
1125 });
1126 });
1127 } 1131 }
1128 1132
1129 Future removeBreakpoint(Breakpoint bpt) { 1133 Future removeBreakpoint(Breakpoint bpt) {
1130 return invokeRpc('removeBreakpoint', 1134 return invokeRpc('removeBreakpoint',
1131 { 'breakpointId': bpt.id }).then((result) { 1135 { 'breakpointId': bpt.id });
1132 if (result is DartError) {
1133 // TODO(turnidge): Handle this more gracefully.
1134 Logger.root.severe(result.message);
1135 return result;
1136 }
1137 if (pauseEvent != null &&
1138 pauseEvent.breakpoint != null &&
1139 (pauseEvent.breakpoint.id == bpt.id)) {
1140 return isolate.reload();
1141 } else {
1142 return reloadBreakpoints();
1143 }
1144 });
1145 } 1136 }
1146 1137
1147 // TODO(turnidge): If the user invokes pause (or other rpcs) twice, 1138 // TODO(turnidge): If the user invokes pause (or other rpcs) twice,
1148 // they could get a race. Consider returning an "in progress" 1139 // they could get a race. Consider returning an "in progress"
1149 // future to avoid this. 1140 // future to avoid this.
1150 Future pause() { 1141 Future pause() {
1151 return invokeRpc('pause', {}).then((result) { 1142 return invokeRpc('pause', {}).then((result) {
1152 if (result is DartError) { 1143 if (result is DartError) {
1153 // TODO(turnidge): Handle this more gracefully. 1144 // TODO(turnidge): Handle this more gracefully.
1154 Logger.root.severe(result.message); 1145 Logger.root.severe(result.message);
(...skipping 157 matching lines...) Expand 10 before | Expand all | Expand 10 after
1312 bool get canCache { 1303 bool get canCache {
1313 return (_type == 'Class' || 1304 return (_type == 'Class' ||
1314 _type == 'Function' || 1305 _type == 'Function' ||
1315 _type == 'Field') && 1306 _type == 'Field') &&
1316 !_id.startsWith(objectIdRingPrefix); 1307 !_id.startsWith(objectIdRingPrefix);
1317 } 1308 }
1318 bool get immutable => false; 1309 bool get immutable => false;
1319 1310
1320 ServiceMap._empty(ServiceObjectOwner owner) : super._empty(owner); 1311 ServiceMap._empty(ServiceObjectOwner owner) : super._empty(owner);
1321 1312
1322 void _upgradeValues() {
1323 assert(owner != null);
1324 _upgradeCollection(_map, owner);
1325 }
1326
1327 void _update(ObservableMap map, bool mapIsRef) { 1313 void _update(ObservableMap map, bool mapIsRef) {
1328 _loaded = !mapIsRef; 1314 _loaded = !mapIsRef;
1329 1315
1316 _upgradeCollection(map, owner);
1330 // TODO(turnidge): Currently _map.clear() prevents us from 1317 // TODO(turnidge): Currently _map.clear() prevents us from
1331 // upgrading an already upgraded submap. Is clearing really the 1318 // upgrading an already upgraded submap. Is clearing really the
1332 // right thing to do here? 1319 // right thing to do here?
1333 _map.clear(); 1320 _map.clear();
1334 _map.addAll(map); 1321 _map.addAll(map);
1335 1322
1336 name = _map['name']; 1323 name = _map['name'];
1337 vmName = (_map.containsKey('vmName') ? _map['vmName'] : name); 1324 vmName = (_map.containsKey('vmName') ? _map['vmName'] : name);
1338 _upgradeValues();
1339 } 1325 }
1340 1326
1341 // Forward Map interface calls. 1327 // Forward Map interface calls.
1342 void addAll(Map other) => _map.addAll(other); 1328 void addAll(Map other) => _map.addAll(other);
1343 void clear() => _map.clear(); 1329 void clear() => _map.clear();
1344 bool containsValue(v) => _map.containsValue(v); 1330 bool containsValue(v) => _map.containsValue(v);
1345 bool containsKey(k) => _map.containsKey(k); 1331 bool containsKey(k) => _map.containsKey(k);
1346 void forEach(Function f) => _map.forEach(f); 1332 void forEach(Function f) => _map.forEach(f);
1347 putIfAbsent(key, Function ifAbsent) => _map.putIfAbsent(key, ifAbsent); 1333 putIfAbsent(key, Function ifAbsent) => _map.putIfAbsent(key, ifAbsent);
1348 void remove(key) => _map.remove(key); 1334 void remove(key) => _map.remove(key);
(...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after
1425 response = map['response']; 1411 response = map['response'];
1426 name = 'ServiceException $kind'; 1412 name = 'ServiceException $kind';
1427 vmName = name; 1413 vmName = name;
1428 } 1414 }
1429 1415
1430 String toString() => 'ServiceException($message)'; 1416 String toString() => 'ServiceException($message)';
1431 } 1417 }
1432 1418
1433 /// A [ServiceEvent] is an asynchronous event notification from the vm. 1419 /// A [ServiceEvent] is an asynchronous event notification from the vm.
1434 class ServiceEvent extends ServiceObject { 1420 class ServiceEvent extends ServiceObject {
1421 /// The possible 'eventType' values.
1422 static const kIsolateStart = 'IsolateStart';
1423 static const kIsolateExit = 'IsolateExit';
1424 static const kPauseStart = 'PauseStart';
1425 static const kPauseExit = 'PauseExit';
1426 static const kPauseBreakpoint = 'PauseBreakpoint';
1427 static const kPauseInterrupted = 'PauseInterrupted';
1428 static const kPauseException = 'PauseException';
1429 static const kResume = 'Resume';
1430 static const kBreakpointAdded = 'BreakpointAdded';
1431 static const kBreakpointResolved = 'BreakpointResolved';
1432 static const kBreakpointRemoved = 'BreakpointRemoved';
1433 static const kGraph = '_Graph';
1434 static const kGC = 'GC';
1435 static const kVMDisconnected = 'VMDisconnected';
1436
1435 ServiceEvent._empty(ServiceObjectOwner owner) : super._empty(owner); 1437 ServiceEvent._empty(ServiceObjectOwner owner) : super._empty(owner);
1436 1438
1437 ServiceEvent.vmDisconencted() : super._empty(null) { 1439 ServiceEvent.vmDisconencted() : super._empty(null) {
1438 eventType = 'VMDisconnected'; 1440 eventType = kVMDisconnected;
1439 } 1441 }
1440 1442
1441 @observable String eventType; 1443 @observable String eventType;
1442 @observable Breakpoint breakpoint; 1444 @observable Breakpoint breakpoint;
1445 @observable ServiceMap topFrame;
1443 @observable ServiceMap exception; 1446 @observable ServiceMap exception;
1444 @observable ByteData data; 1447 @observable ByteData data;
1445 @observable int count; 1448 @observable int count;
1446 1449
1447 void _update(ObservableMap map, bool mapIsRef) { 1450 void _update(ObservableMap map, bool mapIsRef) {
1448 _loaded = true; 1451 _loaded = true;
1449 _upgradeCollection(map, owner); 1452 _upgradeCollection(map, owner);
1450 eventType = map['eventType']; 1453 eventType = map['eventType'];
1451 name = 'ServiceEvent $eventType'; 1454 name = 'ServiceEvent $eventType';
1452 vmName = name; 1455 vmName = name;
1453 if (map['breakpoint'] != null) { 1456 if (map['breakpoint'] != null) {
1454 breakpoint = map['breakpoint']; 1457 breakpoint = map['breakpoint'];
1455 } 1458 }
1459 if (map['topFrame'] != null) {
1460 topFrame = map['topFrame'];
1461 }
1456 if (map['exception'] != null) { 1462 if (map['exception'] != null) {
1457 exception = map['exception']; 1463 exception = map['exception'];
1458 } 1464 }
1459 if (map['_data'] != null) { 1465 if (map['_data'] != null) {
1460 data = map['_data']; 1466 data = map['_data'];
1461 } 1467 }
1462 if (map['count'] != null) { 1468 if (map['count'] != null) {
1463 count = map['count']; 1469 count = map['count'];
1464 } 1470 }
1465 } 1471 }
1466 1472
1467 String toString() { 1473 String toString() {
1468 return 'ServiceEvent of type $eventType with ' 1474 if (data == null) {
1469 '${data == null ? 0 : data.lengthInBytes} bytes of binary data'; 1475 return "ServiceEvent(owner='${owner.id}', type='${eventType}')";
1476 } else {
1477 return "ServiceEvent(owner='${owner.id}', type='${eventType}', "
1478 "data.lengthInBytes=${data.lengthInBytes})";
1479 }
1470 } 1480 }
1471 } 1481 }
1472 1482
1473 class Breakpoint extends ServiceObject { 1483 class Breakpoint extends ServiceObject {
1474 Breakpoint._empty(ServiceObjectOwner owner) : super._empty(owner); 1484 Breakpoint._empty(ServiceObjectOwner owner) : super._empty(owner);
1475 1485
1476 // TODO(turnidge): Add state to track if a breakpoint has been 1486 // TODO(turnidge): Add state to track if a breakpoint has been
1477 // removed from the program. Remove from the cache when deleted. 1487 // removed from the program. Remove from the cache when deleted.
1478 bool get canCache => true; 1488 bool get canCache => true;
1479 bool get immutable => false; 1489 bool get immutable => false;
1480 1490
1481 // A unique integer identifier for this breakpoint. 1491 // A unique integer identifier for this breakpoint.
1482 @observable int number; 1492 @observable int number;
1483 1493
1484 // Source location information. 1494 // Source location information.
1485 @observable Script script; 1495 @observable Script script;
1486 @observable int tokenPos; 1496 @observable int tokenPos;
1487 1497
1488 // The breakpoint has been assigned to a final source location. 1498 // The breakpoint has been assigned to a final source location.
1489 @observable bool resolved; 1499 @observable bool resolved;
1490 1500
1491 // The breakpoint is active.
1492 @observable bool enabled;
1493
1494 void _update(ObservableMap map, bool mapIsRef) { 1501 void _update(ObservableMap map, bool mapIsRef) {
1495 _loaded = true; 1502 _loaded = true;
1496 _upgradeCollection(map, owner); 1503 _upgradeCollection(map, owner);
1497 1504
1505 var newNumber = map['breakpointNumber'];
1506 var newScript = map['location']['script'];
1507 var newTokenPos = map['location']['tokenPos'];
1508
1509 // number and script never change.
1510 assert((number == null) || (number == newNumber));
1511 assert((script == null) || (script == newScript));
1512
1498 number = map['breakpointNumber']; 1513 number = map['breakpointNumber'];
1499 script = map['location']['script']; 1514 script = map['location']['script'];
1500 tokenPos = map['location']['tokenPos']; 1515 resolved = map['resolved'];
1516 bool tokenPosChanged = tokenPos != newTokenPos;
1501 1517
1502 resolved = map['resolved']; 1518 if (script.loaded &&
1503 enabled = map['enabled']; 1519 (tokenPos != null) &&
1520 tokenPosChanged) {
1521 // The breakpoint has moved. Remove it and add it later.
1522 script._removeBreakpoint(this);
1523 }
1524
1525 tokenPos = newTokenPos;
1526 if (script.loaded && tokenPosChanged) {
1527 script._addBreakpoint(this);
1528 }
1529 }
1530
1531 void remove() {
1532 // Remove any references to this breakpoint. It has been removed.
1533 script._removeBreakpoint(this);
1534 if ((isolate.pauseEvent != null) &&
1535 (isolate.pauseEvent.breakpoint != null) &&
1536 (isolate.pauseEvent.breakpoint.id == id)) {
1537 isolate.pauseEvent.breakpoint = null;
1538 }
1504 } 1539 }
1505 1540
1506 String toString() { 1541 String toString() {
1507 if (number != null) { 1542 if (number != null) {
1508 return 'Breakpoint ${number} at ${script.name}(token:${tokenPos})'; 1543 return 'Breakpoint ${number} at ${script.name}(token:${tokenPos})';
1509 } else { 1544 } else {
1510 return 'Uninitialized breakpoint'; 1545 return 'Uninitialized breakpoint';
1511 } 1546 }
1512 } 1547 }
1513 } 1548 }
(...skipping 448 matching lines...) Expand 10 before | Expand all | Expand 10 after
1962 1997
1963 String toString() => 'Field(${owner.name}.$name)'; 1998 String toString() => 'Field(${owner.name}.$name)';
1964 } 1999 }
1965 2000
1966 2001
1967 class ScriptLine extends Observable { 2002 class ScriptLine extends Observable {
1968 final Script script; 2003 final Script script;
1969 final int line; 2004 final int line;
1970 final String text; 2005 final String text;
1971 @observable int hits; 2006 @observable int hits;
1972 @observable Breakpoint bpt;
1973 @observable bool possibleBpt = true; 2007 @observable bool possibleBpt = true;
2008 @observable bool breakpointResolved = false;
2009 @observable Set<Breakpoint> breakpoints;
1974 2010
1975 bool get isBlank { 2011 bool get isBlank {
1976 // Compute isBlank on demand. 2012 // Compute isBlank on demand.
1977 if (_isBlank == null) { 2013 if (_isBlank == null) {
1978 _isBlank = text.trim().isEmpty; 2014 _isBlank = text.trim().isEmpty;
1979 } 2015 }
1980 return _isBlank; 2016 return _isBlank;
1981 } 2017 }
1982 bool _isBlank; 2018 bool _isBlank;
1983 2019
(...skipping 24 matching lines...) Expand all
2008 if (!_isTrivialToken(token)) { 2044 if (!_isTrivialToken(token)) {
2009 return false; 2045 return false;
2010 } 2046 }
2011 } 2047 }
2012 } 2048 }
2013 return true; 2049 return true;
2014 } 2050 }
2015 2051
2016 ScriptLine(this.script, this.line, this.text) { 2052 ScriptLine(this.script, this.line, this.text) {
2017 possibleBpt = !_isTrivialLine(text); 2053 possibleBpt = !_isTrivialLine(text);
2054 }
2018 2055
2019 // TODO(turnidge): This is not so efficient. Consider improving. 2056 void addBreakpoint(Breakpoint bpt) {
2020 for (var bpt in this.script.isolate.breakpoints) { 2057 if (breakpoints == null) {
2021 if (bpt.script == this.script && 2058 breakpoints = new Set<Breakpoint>();
2022 bpt.script.tokenToLine(bpt.tokenPos) == line) { 2059 }
2023 this.bpt = bpt; 2060 breakpoints.add(bpt);
2024 } 2061 breakpointResolved = breakpointResolved || bpt.resolved;
2062 }
2063
2064 void removeBreakpoint(Breakpoint bpt) {
2065 assert(breakpoints != null && breakpoints.contains(bpt));
2066 breakpoints.remove(bpt);
2067 if (breakpoints.isEmpty) {
2068 breakpoints = null;
2069 breakpointResolved = false;
2025 } 2070 }
2026 } 2071 }
2027 } 2072 }
2028 2073
2029 class Script extends ServiceObject with Coverage { 2074 class Script extends ServiceObject with Coverage {
2030 final lines = new ObservableList<ScriptLine>(); 2075 final lines = new ObservableList<ScriptLine>();
2031 final _hits = new Map<int, int>(); 2076 final _hits = new Map<int, int>();
2032 @observable String kind; 2077 @observable String kind;
2033 @observable int firstTokenPos; 2078 @observable int firstTokenPos;
2034 @observable int lastTokenPos; 2079 @observable int lastTokenPos;
(...skipping 22 matching lines...) Expand all
2057 void _update(ObservableMap map, bool mapIsRef) { 2102 void _update(ObservableMap map, bool mapIsRef) {
2058 _upgradeCollection(map, isolate); 2103 _upgradeCollection(map, isolate);
2059 kind = map['kind']; 2104 kind = map['kind'];
2060 _url = map['name']; 2105 _url = map['name'];
2061 _shortUrl = _url.substring(_url.lastIndexOf('/') + 1); 2106 _shortUrl = _url.substring(_url.lastIndexOf('/') + 1);
2062 name = _shortUrl; 2107 name = _shortUrl;
2063 vmName = _url; 2108 vmName = _url;
2064 if (mapIsRef) { 2109 if (mapIsRef) {
2065 return; 2110 return;
2066 } 2111 }
2112 _parseTokenPosTable(map['tokenPosTable']);
2067 _processSource(map['source']); 2113 _processSource(map['source']);
2068 _parseTokenPosTable(map['tokenPosTable']);
2069 owningLibrary = map['owningLibrary']; 2114 owningLibrary = map['owningLibrary'];
2070 } 2115 }
2071 2116
2072 void _parseTokenPosTable(List<List<int>> table) { 2117 void _parseTokenPosTable(List<List<int>> table) {
2073 if (table == null) { 2118 if (table == null) {
2074 return; 2119 return;
2075 } 2120 }
2076 _tokenToLine.clear(); 2121 _tokenToLine.clear();
2077 _tokenToCol.clear(); 2122 _tokenToCol.clear();
2078 firstTokenPos = null; 2123 firstTokenPos = null;
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after
2138 if (sourceLines.length == 0) { 2183 if (sourceLines.length == 0) {
2139 return; 2184 return;
2140 } 2185 }
2141 // We have the source to the script. This is now loaded. 2186 // We have the source to the script. This is now loaded.
2142 _loaded = true; 2187 _loaded = true;
2143 lines.clear(); 2188 lines.clear();
2144 Logger.root.info('Adding ${sourceLines.length} source lines for ${_url}'); 2189 Logger.root.info('Adding ${sourceLines.length} source lines for ${_url}');
2145 for (var i = 0; i < sourceLines.length; i++) { 2190 for (var i = 0; i < sourceLines.length; i++) {
2146 lines.add(new ScriptLine(this, i + 1, sourceLines[i])); 2191 lines.add(new ScriptLine(this, i + 1, sourceLines[i]));
2147 } 2192 }
2193 for (var bpt in isolate.breakpoints.values) {
2194 if (bpt.script == this) {
2195 _addBreakpoint(bpt);
2196 }
2197 }
2198
2148 _applyHitsToLines(); 2199 _applyHitsToLines();
2149 // Notify any Observers that this Script's state has changed. 2200 // Notify any Observers that this Script's state has changed.
2150 notifyChange(null); 2201 notifyChange(null);
2151 } 2202 }
2152 2203
2153 void _applyHitsToLines() { 2204 void _applyHitsToLines() {
2154 for (var line in lines) { 2205 for (var line in lines) {
2155 var hits = _hits[line.line]; 2206 var hits = _hits[line.line];
2156 line.hits = hits; 2207 line.hits = hits;
2157 } 2208 }
2158 } 2209 }
2210
2211 void _addBreakpoint(Breakpoint bpt) {
2212 var line = tokenToLine(bpt.tokenPos);
2213 getLine(line).addBreakpoint(bpt);
2214 }
2215
2216 void _removeBreakpoint(Breakpoint bpt) {
2217 var line = tokenToLine(bpt.tokenPos);
2218 if (line != null) {
2219 getLine(line).removeBreakpoint(bpt);
2220 }
2221 }
2159 } 2222 }
2160 2223
2161 class PcDescriptor extends Observable { 2224 class PcDescriptor extends Observable {
2162 final int pcOffset; 2225 final int pcOffset;
2163 @reflectable final int deoptId; 2226 @reflectable final int deoptId;
2164 @reflectable final int tokenPos; 2227 @reflectable final int tokenPos;
2165 @reflectable final int tryIndex; 2228 @reflectable final int tryIndex;
2166 @reflectable final String kind; 2229 @reflectable final String kind;
2167 @observable Script script; 2230 @observable Script script;
2168 @observable String formattedLine; 2231 @observable String formattedLine;
(...skipping 663 matching lines...) Expand 10 before | Expand all | Expand 10 after
2832 var v = list[i]; 2895 var v = list[i];
2833 if ((v is ObservableMap) && _isServiceMap(v)) { 2896 if ((v is ObservableMap) && _isServiceMap(v)) {
2834 list[i] = owner.getFromMap(v); 2897 list[i] = owner.getFromMap(v);
2835 } else if (v is ObservableList) { 2898 } else if (v is ObservableList) {
2836 _upgradeObservableList(v, owner); 2899 _upgradeObservableList(v, owner);
2837 } else if (v is ObservableMap) { 2900 } else if (v is ObservableMap) {
2838 _upgradeObservableMap(v, owner); 2901 _upgradeObservableMap(v, owner);
2839 } 2902 }
2840 } 2903 }
2841 } 2904 }
OLDNEW
« no previous file with comments | « runtime/observatory/lib/src/elements/script_ref.dart ('k') | runtime/observatory/test/code_test.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698