OLD | NEW |
1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 part of service; | 5 part of service; |
6 | 6 |
7 /// A [ServiceObject] represents a persistent object within the vm. | 7 /// A [ServiceObject] represents a persistent object within the vm. |
8 abstract class ServiceObject extends Observable { | 8 abstract class ServiceObject extends Observable { |
9 static int LexicalSortName(ServiceObject o1, ServiceObject o2) { | 9 static int LexicalSortName(ServiceObject o1, ServiceObject o2) { |
10 return o1.name.compareTo(o2.name); | 10 return o1.name.compareTo(o2.name); |
(...skipping 346 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 } |
OLD | NEW |