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 == 'IsolateExit'); |
373 } | 373 } |
374 | 374 |
375 bool _isIsolateCreatedEvent(String eventType) { | 375 bool _isIsolateStartEvent(String eventType) { |
376 return (eventType == 'IsolateCreated'); | 376 return (eventType == 'IsolateStart'); |
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 && pauseEvent.eventType != 'Resume'; | |
786 running = (!paused && topFrame != null); | |
787 idle = (!paused && topFrame == null); | |
788 notifyPropertyChange(#topFrame, 0, 1); | |
789 notifyPropertyChange(#paused, 0, 1); | |
790 notifyPropertyChange(#running, 0, 1); | |
791 notifyPropertyChange(#idle, 0, 1); | |
792 } | |
793 | |
794 @observable bool paused = false; | |
779 @observable bool running = false; | 795 @observable bool running = false; |
780 @observable bool idle = false; | 796 @observable bool idle = false; |
781 @observable bool loading = true; | 797 @observable bool loading = true; |
798 | |
782 @observable bool ioEnabled = false; | 799 @observable bool ioEnabled = false; |
783 | 800 |
784 Map<String,ServiceObject> _cache = new Map<String,ServiceObject>(); | 801 Map<String,ServiceObject> _cache = new Map<String,ServiceObject>(); |
785 final TagProfile tagProfile = new TagProfile(20); | 802 final TagProfile tagProfile = new TagProfile(20); |
786 | 803 |
787 Isolate._empty(ServiceObjectOwner owner) : super._empty(owner) { | 804 Isolate._empty(ServiceObjectOwner owner) : super._empty(owner) { |
788 assert(owner is VM); | 805 assert(owner is VM); |
789 } | 806 } |
790 | 807 |
791 void resetCachedProfileData() { | 808 void resetCachedProfileData() { |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
837 return new Future.value(objectClass); | 854 return new Future.value(objectClass); |
838 } | 855 } |
839 | 856 |
840 ServiceObject getFromMap(ObservableMap map) { | 857 ServiceObject getFromMap(ObservableMap map) { |
841 if (map == null) { | 858 if (map == null) { |
842 return null; | 859 return null; |
843 } | 860 } |
844 String mapId = map['id']; | 861 String mapId = map['id']; |
845 var obj = (mapId != null) ? _cache[mapId] : null; | 862 var obj = (mapId != null) ? _cache[mapId] : null; |
846 if (obj != null) { | 863 if (obj != null) { |
847 // Consider calling update when map is not a reference. | 864 var mapIsRef = _hasRef(map['type']); |
865 if (!mapIsRef) { | |
866 obj.update(map); | |
867 } | |
848 return obj; | 868 return obj; |
849 } | 869 } |
850 // Build the object from the map directly. | 870 // Build the object from the map directly. |
851 obj = new ServiceObject._fromMap(this, map); | 871 obj = new ServiceObject._fromMap(this, map); |
852 if ((obj != null) && obj.canCache) { | 872 if ((obj != null) && obj.canCache) { |
853 _cache[mapId] = obj; | 873 _cache[mapId] = obj; |
854 } | 874 } |
855 return obj; | 875 return obj; |
856 } | 876 } |
857 | 877 |
858 Future<ObservableMap> invokeRpcNoUpgrade(String method, Map params) { | 878 Future<ObservableMap> invokeRpcNoUpgrade(String method, Map params) { |
859 params['isolateId'] = id; | 879 params['isolateId'] = id; |
860 return vm.invokeRpcNoUpgrade(method, params); | 880 return vm.invokeRpcNoUpgrade(method, params); |
861 } | 881 } |
862 | 882 |
863 Future<ServiceObject> invokeRpc(String method, Map params) { | 883 Future<ServiceObject> invokeRpc(String method, Map params) { |
864 return invokeRpcNoUpgrade(method, params).then((ObservableMap response) { | 884 return invokeRpcNoUpgrade(method, params).then((ObservableMap response) { |
865 var obj = new ServiceObject._fromMap(this, response); | 885 return getFromMap(response); |
866 if ((obj != null) && obj.canCache) { | |
867 String objId = obj.id; | |
868 _cache.putIfAbsent(objId, () => obj); | |
869 } | |
870 return obj; | |
871 }); | 886 }); |
872 } | 887 } |
873 | 888 |
874 Future<ServiceObject> getObject(String objectId) { | 889 Future<ServiceObject> getObject(String objectId) { |
875 assert(objectId != null && objectId != ''); | 890 assert(objectId != null && objectId != ''); |
876 var obj = _cache[objectId]; | 891 var obj = _cache[objectId]; |
877 if (obj != null) { | 892 if (obj != null) { |
878 return obj.reload(); | 893 return obj.reload(); |
879 } | 894 } |
880 Map params = { | 895 Map params = { |
(...skipping 24 matching lines...) Expand all Loading... | |
905 | 920 |
906 final HeapSpace newSpace = new HeapSpace(); | 921 final HeapSpace newSpace = new HeapSpace(); |
907 final HeapSpace oldSpace = new HeapSpace(); | 922 final HeapSpace oldSpace = new HeapSpace(); |
908 | 923 |
909 @observable String fileAndLine; | 924 @observable String fileAndLine; |
910 | 925 |
911 @observable DartError error; | 926 @observable DartError error; |
912 @observable HeapSnapshot latestSnapshot; | 927 @observable HeapSnapshot latestSnapshot; |
913 Completer<HeapSnapshot> _snapshotFetch; | 928 Completer<HeapSnapshot> _snapshotFetch; |
914 | 929 |
915 void loadHeapSnapshot(ServiceEvent event) { | 930 void _loadHeapSnapshot(ServiceEvent event) { |
916 latestSnapshot = new HeapSnapshot(this, event.data); | 931 latestSnapshot = new HeapSnapshot(this, event.data); |
917 _snapshotFetch.complete(latestSnapshot); | 932 _snapshotFetch.complete(latestSnapshot); |
918 } | 933 } |
919 | 934 |
920 Future<HeapSnapshot> fetchHeapSnapshot() { | 935 Future<HeapSnapshot> fetchHeapSnapshot() { |
921 if (_snapshotFetch == null || _snapshotFetch.isCompleted) { | 936 if (_snapshotFetch == null || _snapshotFetch.isCompleted) { |
922 _snapshotFetch = new Completer<HeapSnapshot>(); | 937 _snapshotFetch = new Completer<HeapSnapshot>(); |
923 isolate.invokeRpcNoUpgrade('requestHeapSnapshot', {}); | 938 isolate.invokeRpcNoUpgrade('requestHeapSnapshot', {}); |
924 } | 939 } |
925 return _snapshotFetch.future; | 940 return _snapshotFetch.future; |
926 } | 941 } |
927 | 942 |
928 void updateHeapsFromMap(ObservableMap map) { | 943 void updateHeapsFromMap(ObservableMap map) { |
929 newSpace.update(map['new']); | 944 newSpace.update(map['new']); |
930 oldSpace.update(map['old']); | 945 oldSpace.update(map['old']); |
931 } | 946 } |
932 | 947 |
933 void _update(ObservableMap map, bool mapIsRef) { | 948 void _update(ObservableMap map, bool mapIsRef) { |
934 mainPort = map['mainPort']; | 949 mainPort = map['mainPort']; |
935 name = map['name']; | 950 name = map['name']; |
936 vmName = map['name']; | 951 vmName = map['name']; |
937 if (mapIsRef) { | 952 if (mapIsRef) { |
938 return; | 953 return; |
939 } | 954 } |
940 _loaded = true; | 955 _loaded = true; |
941 loading = false; | 956 loading = false; |
942 | 957 |
943 reloadBreakpoints(); | |
944 _upgradeCollection(map, isolate); | 958 _upgradeCollection(map, isolate); |
945 if (map['rootLib'] == null || | 959 if (map['rootLib'] == null || |
946 map['timers'] == null || | 960 map['timers'] == null || |
947 map['heaps'] == null) { | 961 map['heaps'] == null) { |
948 Logger.root.severe("Malformed 'Isolate' response: $map"); | 962 Logger.root.severe("Malformed 'Isolate' response: $map"); |
949 return; | 963 return; |
950 } | 964 } |
951 rootLib = map['rootLib']; | 965 rootLib = map['rootLib']; |
952 if (map['entry'] != null) { | 966 if (map['entry'] != null) { |
953 entry = map['entry']; | 967 entry = map['entry']; |
954 } | 968 } |
955 if (map['topFrame'] != null) { | |
956 topFrame = map['topFrame']; | |
957 } else { | |
958 topFrame = null ; | |
959 } | |
960 | 969 |
961 var countersMap = map['tagCounters']; | 970 var countersMap = map['tagCounters']; |
962 if (countersMap != null) { | 971 if (countersMap != null) { |
963 var names = countersMap['names']; | 972 var names = countersMap['names']; |
964 var counts = countersMap['counters']; | 973 var counts = countersMap['counters']; |
965 assert(names.length == counts.length); | 974 assert(names.length == counts.length); |
966 var sum = 0; | 975 var sum = 0; |
967 for (var i = 0; i < counts.length; i++) { | 976 for (var i = 0; i < counts.length; i++) { |
968 sum += counts[i]; | 977 sum += counts[i]; |
969 } | 978 } |
(...skipping 17 matching lines...) Expand all Loading... | |
987 timers['total'] = timerMap['time_total_runtime']; | 996 timers['total'] = timerMap['time_total_runtime']; |
988 timers['compile'] = timerMap['time_compilation']; | 997 timers['compile'] = timerMap['time_compilation']; |
989 timers['gc'] = 0.0; // TODO(turnidge): Export this from VM. | 998 timers['gc'] = 0.0; // TODO(turnidge): Export this from VM. |
990 timers['init'] = (timerMap['time_script_loading'] + | 999 timers['init'] = (timerMap['time_script_loading'] + |
991 timerMap['time_creating_snapshot'] + | 1000 timerMap['time_creating_snapshot'] + |
992 timerMap['time_isolate_initialization'] + | 1001 timerMap['time_isolate_initialization'] + |
993 timerMap['time_bootstrap']); | 1002 timerMap['time_bootstrap']); |
994 timers['dart'] = timerMap['time_dart_execution']; | 1003 timers['dart'] = timerMap['time_dart_execution']; |
995 | 1004 |
996 updateHeapsFromMap(map['heaps']); | 1005 updateHeapsFromMap(map['heaps']); |
1006 _updateBreakpoints(map['breakpoints']); | |
997 | 1007 |
998 List features = map['features']; | 1008 List features = map['features']; |
999 if (features != null) { | 1009 if (features != null) { |
1000 for (var feature in features) { | 1010 for (var feature in features) { |
1001 if (feature == 'io') { | 1011 if (feature == 'io') { |
1002 ioEnabled = true; | 1012 ioEnabled = true; |
1003 } | 1013 } |
1004 } | 1014 } |
1005 } | 1015 } |
1006 // Isolate status | |
1007 pauseEvent = map['pauseEvent']; | 1016 pauseEvent = map['pauseEvent']; |
1008 running = (!_isPaused && map['topFrame'] != null); | 1017 _updateRunState(); |
1009 idle = (!_isPaused && map['topFrame'] == null); | |
1010 error = map['error']; | 1018 error = map['error']; |
1011 | 1019 |
1012 libraries.clear(); | 1020 libraries.clear(); |
1013 libraries.addAll(map['libraries']); | 1021 libraries.addAll(map['libraries']); |
1014 libraries.sort(ServiceObject.LexicalSortName); | 1022 libraries.sort(ServiceObject.LexicalSortName); |
1015 } | 1023 } |
1016 | 1024 |
1017 Future<TagProfile> updateTagProfile() { | 1025 Future<TagProfile> updateTagProfile() { |
1018 return isolate.invokeRpcNoUpgrade('getTagProfile', {}).then( | 1026 return isolate.invokeRpcNoUpgrade('getTagProfile', {}).then( |
1019 (ObservableMap map) { | 1027 (ObservableMap map) { |
1020 var seconds = new DateTime.now().millisecondsSinceEpoch / 1000.0; | 1028 var seconds = new DateTime.now().millisecondsSinceEpoch / 1000.0; |
1021 tagProfile._processTagProfile(seconds, map); | 1029 tagProfile._processTagProfile(seconds, map); |
1022 return tagProfile; | 1030 return tagProfile; |
1023 }); | 1031 }); |
1024 } | 1032 } |
1025 | 1033 |
1026 ObservableList<Breakpoint> breakpoints = new ObservableList(); | 1034 ObservableMap<int, Breakpoint> breakpoints = new ObservableMap(); |
1035 | |
1036 void _updateBreakpoints(List newBpts) { | |
1037 // Build a map of new breakpoints. | |
1038 var newBptMap = {}; | |
1039 newBpts.forEach((bpt) => (newBptMap[bpt.number] = bpt)); | |
1040 | |
1041 // Remove any old breakpoints which no longer exist. | |
1042 List toRemove = []; | |
1043 breakpoints.forEach((key, _) { | |
1044 if (!newBptMap.containsKey(key)) { | |
1045 toRemove.add(key); | |
1046 } | |
1047 }); | |
1048 toRemove.forEach((key) => breakpoints.remove(key)); | |
1049 | |
1050 // Add all new breakpoints. | |
1051 breakpoints.addAll(newBptMap); | |
1052 } | |
1053 | |
1054 void _addBreakpoint(Breakpoint bpt) { | |
1055 breakpoints[bpt.number] = bpt; | |
1056 } | |
1027 | 1057 |
1028 void _removeBreakpoint(Breakpoint bpt) { | 1058 void _removeBreakpoint(Breakpoint bpt) { |
1029 var script = bpt.script; | 1059 breakpoints.remove(bpt.number); |
1030 var tokenPos = bpt.tokenPos; | 1060 bpt.remove(); |
1031 assert(tokenPos != null); | 1061 } |
1032 if (script.loaded) { | 1062 |
1033 var line = script.tokenToLine(tokenPos); | 1063 void _onEvent(ServiceEvent event) { |
1034 assert(line != null); | 1064 switch(event.eventType) { |
1035 if (script.lines[line - 1] != null) { | 1065 case 'IsolateStart': |
1036 assert(script.lines[line - 1].bpt == bpt); | 1066 case 'IsolateExit': |
1037 script.lines[line - 1].bpt = null; | 1067 Logger.root.severe( |
1038 } | 1068 'Isolate lifecycle event should not be delivered to isolate'); |
Cutch
2015/03/05 16:30:57
Throw here.
turnidge
2015/03/05 18:42:24
Turned this into an assert.
| |
1069 break; | |
1070 | |
1071 case 'BreakpointAdded': | |
1072 _addBreakpoint(event.breakpoint); | |
1073 break; | |
1074 | |
1075 case 'BreakpointResolved': | |
1076 // Update occurs as side-effect of caching. | |
1077 break; | |
1078 | |
1079 case 'BreakpointRemoved': | |
1080 _removeBreakpoint(event.breakpoint); | |
1081 break; | |
1082 | |
1083 case 'PauseStart': | |
1084 case 'PauseExit': | |
1085 case 'PauseBreakpoint': | |
1086 case 'PauseInterrupted': | |
1087 case 'PauseException': | |
1088 case 'Resume': | |
1089 pauseEvent = event; | |
1090 _updateRunState(); | |
1091 break; | |
1092 | |
1093 case '_Graph': | |
1094 _loadHeapSnapshot(event); | |
1095 break; | |
1096 | |
1097 case 'GC': | |
1098 // Ignore GC events for now. | |
1099 break; | |
1100 | |
1101 default: | |
1102 // Log unrecognized events. | |
1103 Logger.root.severe('Unrecognized event: $event'); | |
1104 break; | |
1039 } | 1105 } |
1040 } | 1106 } |
1041 | 1107 |
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) { | 1108 Future<ServiceObject> addBreakpoint(Script script, int line) { |
1094 // TODO(turnidge): Pass line as an int instead of a string. | 1109 // TODO(turnidge): Pass line as an int instead of a string. |
1095 Map params = { | 1110 Map params = { |
1096 'scriptId': script.id, | 1111 'scriptId': script.id, |
1097 'line': '$line', | 1112 'line': '$line', |
1098 }; | 1113 }; |
1099 return invokeRpc('addBreakpoint', params).then((result) { | 1114 return invokeRpc('addBreakpoint', params).then((result) { |
1100 if (result is DartError) { | 1115 if (result is DartError) { |
1101 return result; | 1116 return result; |
1102 } | 1117 } |
1103 Breakpoint bpt = result; | 1118 Breakpoint bpt = result; |
1104 if (bpt.resolved && | 1119 if (bpt.resolved && |
1105 script.loaded && | 1120 script.loaded && |
1106 script.tokenToLine(result.tokenPos) != line) { | 1121 script.tokenToLine(result.tokenPos) != line) { |
1107 // Unable to set a breakpoint at desired line. | 1122 // Unable to set a breakpoint at desired line. |
1108 script.lines[line - 1].possibleBpt = false; | 1123 script.lines[line - 1].possibleBpt = false; |
1109 } | 1124 } |
1110 // TODO(turnidge): Instead of reloading all of the breakpoints, | 1125 return result; |
1111 // rely on events to update the breakpoint list. | |
1112 return reloadBreakpoints().then((_) { | |
1113 return result; | |
1114 }); | |
1115 }); | 1126 }); |
1116 } | 1127 } |
1117 | 1128 |
1118 Future<ServiceObject> addBreakpointAtEntry(ServiceFunction function) { | 1129 Future<ServiceObject> addBreakpointAtEntry(ServiceFunction function) { |
1119 return invokeRpc('addBreakpointAtEntry', | 1130 return invokeRpc('addBreakpointAtEntry', |
1120 { 'functionId': function.id }).then((result) { | 1131 { '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 } | 1132 } |
1128 | 1133 |
1129 Future removeBreakpoint(Breakpoint bpt) { | 1134 Future removeBreakpoint(Breakpoint bpt) { |
1130 return invokeRpc('removeBreakpoint', | 1135 return invokeRpc('removeBreakpoint', |
1131 { 'breakpointId': bpt.id }).then((result) { | 1136 { '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 } | 1137 } |
1146 | 1138 |
1147 // TODO(turnidge): If the user invokes pause (or other rpcs) twice, | 1139 // TODO(turnidge): If the user invokes pause (or other rpcs) twice, |
1148 // they could get a race. Consider returning an "in progress" | 1140 // they could get a race. Consider returning an "in progress" |
1149 // future to avoid this. | 1141 // future to avoid this. |
1150 Future pause() { | 1142 Future pause() { |
1151 return invokeRpc('pause', {}).then((result) { | 1143 return invokeRpc('pause', {}).then((result) { |
1152 if (result is DartError) { | 1144 if (result is DartError) { |
1153 // TODO(turnidge): Handle this more gracefully. | 1145 // TODO(turnidge): Handle this more gracefully. |
1154 Logger.root.severe(result.message); | 1146 Logger.root.severe(result.message); |
(...skipping 157 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1312 bool get canCache { | 1304 bool get canCache { |
1313 return (_type == 'Class' || | 1305 return (_type == 'Class' || |
1314 _type == 'Function' || | 1306 _type == 'Function' || |
1315 _type == 'Field') && | 1307 _type == 'Field') && |
1316 !_id.startsWith(objectIdRingPrefix); | 1308 !_id.startsWith(objectIdRingPrefix); |
1317 } | 1309 } |
1318 bool get immutable => false; | 1310 bool get immutable => false; |
1319 | 1311 |
1320 ServiceMap._empty(ServiceObjectOwner owner) : super._empty(owner); | 1312 ServiceMap._empty(ServiceObjectOwner owner) : super._empty(owner); |
1321 | 1313 |
1322 void _upgradeValues() { | |
1323 assert(owner != null); | |
1324 _upgradeCollection(_map, owner); | |
1325 } | |
1326 | |
1327 void _update(ObservableMap map, bool mapIsRef) { | 1314 void _update(ObservableMap map, bool mapIsRef) { |
1328 _loaded = !mapIsRef; | 1315 _loaded = !mapIsRef; |
1329 | 1316 |
1317 _upgradeCollection(map, owner); | |
1330 // TODO(turnidge): Currently _map.clear() prevents us from | 1318 // TODO(turnidge): Currently _map.clear() prevents us from |
1331 // upgrading an already upgraded submap. Is clearing really the | 1319 // upgrading an already upgraded submap. Is clearing really the |
1332 // right thing to do here? | 1320 // right thing to do here? |
1333 _map.clear(); | 1321 _map.clear(); |
1334 _map.addAll(map); | 1322 _map.addAll(map); |
1335 | 1323 |
1336 name = _map['name']; | 1324 name = _map['name']; |
1337 vmName = (_map.containsKey('vmName') ? _map['vmName'] : name); | 1325 vmName = (_map.containsKey('vmName') ? _map['vmName'] : name); |
1338 _upgradeValues(); | |
1339 } | 1326 } |
1340 | 1327 |
1341 // Forward Map interface calls. | 1328 // Forward Map interface calls. |
1342 void addAll(Map other) => _map.addAll(other); | 1329 void addAll(Map other) => _map.addAll(other); |
1343 void clear() => _map.clear(); | 1330 void clear() => _map.clear(); |
1344 bool containsValue(v) => _map.containsValue(v); | 1331 bool containsValue(v) => _map.containsValue(v); |
1345 bool containsKey(k) => _map.containsKey(k); | 1332 bool containsKey(k) => _map.containsKey(k); |
1346 void forEach(Function f) => _map.forEach(f); | 1333 void forEach(Function f) => _map.forEach(f); |
1347 putIfAbsent(key, Function ifAbsent) => _map.putIfAbsent(key, ifAbsent); | 1334 putIfAbsent(key, Function ifAbsent) => _map.putIfAbsent(key, ifAbsent); |
1348 void remove(key) => _map.remove(key); | 1335 void remove(key) => _map.remove(key); |
(...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1433 /// A [ServiceEvent] is an asynchronous event notification from the vm. | 1420 /// A [ServiceEvent] is an asynchronous event notification from the vm. |
1434 class ServiceEvent extends ServiceObject { | 1421 class ServiceEvent extends ServiceObject { |
1435 ServiceEvent._empty(ServiceObjectOwner owner) : super._empty(owner); | 1422 ServiceEvent._empty(ServiceObjectOwner owner) : super._empty(owner); |
1436 | 1423 |
1437 ServiceEvent.vmDisconencted() : super._empty(null) { | 1424 ServiceEvent.vmDisconencted() : super._empty(null) { |
1438 eventType = 'VMDisconnected'; | 1425 eventType = 'VMDisconnected'; |
1439 } | 1426 } |
1440 | 1427 |
1441 @observable String eventType; | 1428 @observable String eventType; |
1442 @observable Breakpoint breakpoint; | 1429 @observable Breakpoint breakpoint; |
1430 @observable ServiceMap topFrame; | |
1443 @observable ServiceMap exception; | 1431 @observable ServiceMap exception; |
1444 @observable ByteData data; | 1432 @observable ByteData data; |
1445 @observable int count; | 1433 @observable int count; |
1446 | 1434 |
1447 void _update(ObservableMap map, bool mapIsRef) { | 1435 void _update(ObservableMap map, bool mapIsRef) { |
1448 _loaded = true; | 1436 _loaded = true; |
1449 _upgradeCollection(map, owner); | 1437 _upgradeCollection(map, owner); |
1450 eventType = map['eventType']; | 1438 eventType = map['eventType']; |
1451 name = 'ServiceEvent $eventType'; | 1439 name = 'ServiceEvent $eventType'; |
1452 vmName = name; | 1440 vmName = name; |
1453 if (map['breakpoint'] != null) { | 1441 if (map['breakpoint'] != null) { |
1454 breakpoint = map['breakpoint']; | 1442 breakpoint = map['breakpoint']; |
1455 } | 1443 } |
1444 if (map['topFrame'] != null) { | |
1445 topFrame = map['topFrame']; | |
1446 } | |
1456 if (map['exception'] != null) { | 1447 if (map['exception'] != null) { |
1457 exception = map['exception']; | 1448 exception = map['exception']; |
1458 } | 1449 } |
1459 if (map['_data'] != null) { | 1450 if (map['_data'] != null) { |
1460 data = map['_data']; | 1451 data = map['_data']; |
1461 } | 1452 } |
1462 if (map['count'] != null) { | 1453 if (map['count'] != null) { |
1463 count = map['count']; | 1454 count = map['count']; |
1464 } | 1455 } |
1465 } | 1456 } |
1466 | 1457 |
1467 String toString() { | 1458 String toString() { |
1468 return 'ServiceEvent of type $eventType with ' | 1459 if (data == null) { |
1469 '${data == null ? 0 : data.lengthInBytes} bytes of binary data'; | 1460 return "ServiceEvent(owner='${owner.id}', type='${eventType}')"; |
1461 } else { | |
1462 return "ServiceEvent(owner='${owner.id}', type='${eventType}', " | |
1463 "data.lengthInBytes=${data.lengthInBytes})"; | |
1464 } | |
1470 } | 1465 } |
1471 } | 1466 } |
1472 | 1467 |
1473 class Breakpoint extends ServiceObject { | 1468 class Breakpoint extends ServiceObject { |
1474 Breakpoint._empty(ServiceObjectOwner owner) : super._empty(owner); | 1469 Breakpoint._empty(ServiceObjectOwner owner) : super._empty(owner); |
1475 | 1470 |
1476 // TODO(turnidge): Add state to track if a breakpoint has been | 1471 // TODO(turnidge): Add state to track if a breakpoint has been |
1477 // removed from the program. Remove from the cache when deleted. | 1472 // removed from the program. Remove from the cache when deleted. |
1478 bool get canCache => true; | 1473 bool get canCache => true; |
1479 bool get immutable => false; | 1474 bool get immutable => false; |
1480 | 1475 |
1481 // A unique integer identifier for this breakpoint. | 1476 // A unique integer identifier for this breakpoint. |
1482 @observable int number; | 1477 @observable int number; |
1483 | 1478 |
1484 // Source location information. | 1479 // Source location information. |
1485 @observable Script script; | 1480 @observable Script script; |
1486 @observable int tokenPos; | 1481 @observable int tokenPos; |
1487 | 1482 |
1488 // The breakpoint has been assigned to a final source location. | 1483 // The breakpoint has been assigned to a final source location. |
1489 @observable bool resolved; | 1484 @observable bool resolved; |
1490 | 1485 |
1491 // The breakpoint is active. | |
1492 @observable bool enabled; | |
1493 | |
1494 void _update(ObservableMap map, bool mapIsRef) { | 1486 void _update(ObservableMap map, bool mapIsRef) { |
1495 _loaded = true; | 1487 _loaded = true; |
1496 _upgradeCollection(map, owner); | 1488 _upgradeCollection(map, owner); |
1497 | 1489 |
1490 var newNumber = map['breakpointNumber']; | |
1491 var newScript = map['location']['script']; | |
1492 var newTokenPos = map['location']['tokenPos']; | |
1493 | |
1494 // number and script never change. | |
1495 assert(number == null || number == newNumber); | |
Cutch
2015/03/05 16:30:57
Wrap comparisons in ( ) here and elsewhere.
e.g.
turnidge
2015/03/05 18:43:14
Done.
| |
1496 assert(script == null || script == newScript); | |
1497 | |
1498 number = map['breakpointNumber']; | 1498 number = map['breakpointNumber']; |
1499 script = map['location']['script']; | 1499 script = map['location']['script']; |
1500 tokenPos = map['location']['tokenPos']; | 1500 resolved = map['resolved']; |
1501 bool tokenPosChanged = tokenPos != newTokenPos; | |
1501 | 1502 |
1502 resolved = map['resolved']; | 1503 if (script.loaded && |
1503 enabled = map['enabled']; | 1504 tokenPos != null && |
1505 tokenPosChanged) { | |
1506 // The breakpoint has moved. Remove it and add it later. | |
1507 script._removeBreakpoint(this); | |
1508 } | |
1509 | |
1510 tokenPos = newTokenPos; | |
1511 if (script.loaded && tokenPosChanged) { | |
1512 script._addBreakpoint(this); | |
1513 } | |
1514 } | |
1515 | |
1516 void remove() { | |
1517 // Remove any references to this breakpoint. It has been removed. | |
1518 script._removeBreakpoint(this); | |
1519 if (isolate.pauseEvent != null && | |
1520 isolate.pauseEvent.breakpoint != null && | |
1521 isolate.pauseEvent.breakpoint.id == id) { | |
1522 isolate.pauseEvent.breakpoint = null; | |
1523 } | |
1504 } | 1524 } |
1505 | 1525 |
1506 String toString() { | 1526 String toString() { |
1507 if (number != null) { | 1527 if (number != null) { |
1508 return 'Breakpoint ${number} at ${script.name}(token:${tokenPos})'; | 1528 return 'Breakpoint ${number} at ${script.name}(token:${tokenPos})'; |
1509 } else { | 1529 } else { |
1510 return 'Uninitialized breakpoint'; | 1530 return 'Uninitialized breakpoint'; |
1511 } | 1531 } |
1512 } | 1532 } |
1513 } | 1533 } |
(...skipping 448 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1962 | 1982 |
1963 String toString() => 'Field(${owner.name}.$name)'; | 1983 String toString() => 'Field(${owner.name}.$name)'; |
1964 } | 1984 } |
1965 | 1985 |
1966 | 1986 |
1967 class ScriptLine extends Observable { | 1987 class ScriptLine extends Observable { |
1968 final Script script; | 1988 final Script script; |
1969 final int line; | 1989 final int line; |
1970 final String text; | 1990 final String text; |
1971 @observable int hits; | 1991 @observable int hits; |
1972 @observable Breakpoint bpt; | |
1973 @observable bool possibleBpt = true; | 1992 @observable bool possibleBpt = true; |
1993 @observable bool breakpointResolved = false; | |
1994 @observable Set<Breakpoint> breakpoints; | |
1974 | 1995 |
1975 bool get isBlank { | 1996 bool get isBlank { |
1976 // Compute isBlank on demand. | 1997 // Compute isBlank on demand. |
1977 if (_isBlank == null) { | 1998 if (_isBlank == null) { |
1978 _isBlank = text.trim().isEmpty; | 1999 _isBlank = text.trim().isEmpty; |
1979 } | 2000 } |
1980 return _isBlank; | 2001 return _isBlank; |
1981 } | 2002 } |
1982 bool _isBlank; | 2003 bool _isBlank; |
1983 | 2004 |
(...skipping 24 matching lines...) Expand all Loading... | |
2008 if (!_isTrivialToken(token)) { | 2029 if (!_isTrivialToken(token)) { |
2009 return false; | 2030 return false; |
2010 } | 2031 } |
2011 } | 2032 } |
2012 } | 2033 } |
2013 return true; | 2034 return true; |
2014 } | 2035 } |
2015 | 2036 |
2016 ScriptLine(this.script, this.line, this.text) { | 2037 ScriptLine(this.script, this.line, this.text) { |
2017 possibleBpt = !_isTrivialLine(text); | 2038 possibleBpt = !_isTrivialLine(text); |
2039 } | |
2018 | 2040 |
2019 // TODO(turnidge): This is not so efficient. Consider improving. | 2041 void addBreakpoint(Breakpoint bpt) { |
2020 for (var bpt in this.script.isolate.breakpoints) { | 2042 if (breakpoints == null) { |
2021 if (bpt.script == this.script && | 2043 breakpoints = new Set<Breakpoint>(); |
2022 bpt.script.tokenToLine(bpt.tokenPos) == line) { | 2044 } |
2023 this.bpt = bpt; | 2045 breakpoints.add(bpt); |
2024 } | 2046 breakpointResolved = breakpointResolved || bpt.resolved; |
2047 } | |
2048 | |
2049 void removeBreakpoint(Breakpoint bpt) { | |
2050 assert(breakpoints != null && breakpoints.contains(bpt)); | |
2051 breakpoints.remove(bpt); | |
2052 if (breakpoints.isEmpty) { | |
2053 breakpoints = null; | |
2054 breakpointResolved = false; | |
2025 } | 2055 } |
2026 } | 2056 } |
2027 } | 2057 } |
2028 | 2058 |
2029 class Script extends ServiceObject with Coverage { | 2059 class Script extends ServiceObject with Coverage { |
2030 final lines = new ObservableList<ScriptLine>(); | 2060 final lines = new ObservableList<ScriptLine>(); |
2031 final _hits = new Map<int, int>(); | 2061 final _hits = new Map<int, int>(); |
2032 @observable String kind; | 2062 @observable String kind; |
2033 @observable int firstTokenPos; | 2063 @observable int firstTokenPos; |
2034 @observable int lastTokenPos; | 2064 @observable int lastTokenPos; |
(...skipping 22 matching lines...) Expand all Loading... | |
2057 void _update(ObservableMap map, bool mapIsRef) { | 2087 void _update(ObservableMap map, bool mapIsRef) { |
2058 _upgradeCollection(map, isolate); | 2088 _upgradeCollection(map, isolate); |
2059 kind = map['kind']; | 2089 kind = map['kind']; |
2060 _url = map['name']; | 2090 _url = map['name']; |
2061 _shortUrl = _url.substring(_url.lastIndexOf('/') + 1); | 2091 _shortUrl = _url.substring(_url.lastIndexOf('/') + 1); |
2062 name = _shortUrl; | 2092 name = _shortUrl; |
2063 vmName = _url; | 2093 vmName = _url; |
2064 if (mapIsRef) { | 2094 if (mapIsRef) { |
2065 return; | 2095 return; |
2066 } | 2096 } |
2097 _parseTokenPosTable(map['tokenPosTable']); | |
2067 _processSource(map['source']); | 2098 _processSource(map['source']); |
2068 _parseTokenPosTable(map['tokenPosTable']); | |
2069 owningLibrary = map['owningLibrary']; | 2099 owningLibrary = map['owningLibrary']; |
2070 } | 2100 } |
2071 | 2101 |
2072 void _parseTokenPosTable(List<List<int>> table) { | 2102 void _parseTokenPosTable(List<List<int>> table) { |
2073 if (table == null) { | 2103 if (table == null) { |
2074 return; | 2104 return; |
2075 } | 2105 } |
2076 _tokenToLine.clear(); | 2106 _tokenToLine.clear(); |
2077 _tokenToCol.clear(); | 2107 _tokenToCol.clear(); |
2078 firstTokenPos = null; | 2108 firstTokenPos = null; |
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2138 if (sourceLines.length == 0) { | 2168 if (sourceLines.length == 0) { |
2139 return; | 2169 return; |
2140 } | 2170 } |
2141 // We have the source to the script. This is now loaded. | 2171 // We have the source to the script. This is now loaded. |
2142 _loaded = true; | 2172 _loaded = true; |
2143 lines.clear(); | 2173 lines.clear(); |
2144 Logger.root.info('Adding ${sourceLines.length} source lines for ${_url}'); | 2174 Logger.root.info('Adding ${sourceLines.length} source lines for ${_url}'); |
2145 for (var i = 0; i < sourceLines.length; i++) { | 2175 for (var i = 0; i < sourceLines.length; i++) { |
2146 lines.add(new ScriptLine(this, i + 1, sourceLines[i])); | 2176 lines.add(new ScriptLine(this, i + 1, sourceLines[i])); |
2147 } | 2177 } |
2178 for (var bpt in isolate.breakpoints.values) { | |
2179 if (bpt.script == this) { | |
2180 _addBreakpoint(bpt); | |
2181 } | |
2182 } | |
2183 | |
2148 _applyHitsToLines(); | 2184 _applyHitsToLines(); |
2149 // Notify any Observers that this Script's state has changed. | 2185 // Notify any Observers that this Script's state has changed. |
2150 notifyChange(null); | 2186 notifyChange(null); |
2151 } | 2187 } |
2152 | 2188 |
2153 void _applyHitsToLines() { | 2189 void _applyHitsToLines() { |
2154 for (var line in lines) { | 2190 for (var line in lines) { |
2155 var hits = _hits[line.line]; | 2191 var hits = _hits[line.line]; |
2156 line.hits = hits; | 2192 line.hits = hits; |
2157 } | 2193 } |
2158 } | 2194 } |
2195 | |
2196 void _addBreakpoint(Breakpoint bpt) { | |
2197 var line = tokenToLine(bpt.tokenPos); | |
2198 getLine(line).addBreakpoint(bpt); | |
2199 } | |
2200 | |
2201 void _removeBreakpoint(Breakpoint bpt) { | |
2202 var line = tokenToLine(bpt.tokenPos); | |
2203 if (line != null) { | |
2204 getLine(line).removeBreakpoint(bpt); | |
2205 } | |
2206 } | |
2159 } | 2207 } |
2160 | 2208 |
2161 class PcDescriptor extends Observable { | 2209 class PcDescriptor extends Observable { |
2162 final int pcOffset; | 2210 final int pcOffset; |
2163 @reflectable final int deoptId; | 2211 @reflectable final int deoptId; |
2164 @reflectable final int tokenPos; | 2212 @reflectable final int tokenPos; |
2165 @reflectable final int tryIndex; | 2213 @reflectable final int tryIndex; |
2166 @reflectable final String kind; | 2214 @reflectable final String kind; |
2167 @observable Script script; | 2215 @observable Script script; |
2168 @observable String formattedLine; | 2216 @observable String formattedLine; |
(...skipping 663 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2832 var v = list[i]; | 2880 var v = list[i]; |
2833 if ((v is ObservableMap) && _isServiceMap(v)) { | 2881 if ((v is ObservableMap) && _isServiceMap(v)) { |
2834 list[i] = owner.getFromMap(v); | 2882 list[i] = owner.getFromMap(v); |
2835 } else if (v is ObservableList) { | 2883 } else if (v is ObservableList) { |
2836 _upgradeObservableList(v, owner); | 2884 _upgradeObservableList(v, owner); |
2837 } else if (v is ObservableMap) { | 2885 } else if (v is ObservableMap) { |
2838 _upgradeObservableMap(v, owner); | 2886 _upgradeObservableMap(v, owner); |
2839 } | 2887 } |
2840 } | 2888 } |
2841 } | 2889 } |
OLD | NEW |