Chromium Code Reviews| Index: runtime/observatory/lib/src/service/object.dart |
| diff --git a/runtime/observatory/lib/src/service/object.dart b/runtime/observatory/lib/src/service/object.dart |
| index 2bd63a29510ec63f6207369a28d55400e882710d..ba08af8496c5d3b8d86708fbd267ce9b8648a997 100644 |
| --- a/runtime/observatory/lib/src/service/object.dart |
| +++ b/runtime/observatory/lib/src/service/object.dart |
| @@ -343,11 +343,13 @@ abstract class VM extends ServiceObjectOwner { |
| @observable String version = 'unknown'; |
| @observable String targetCPU; |
| @observable int architectureBits; |
| - @observable double uptime = 0.0; |
| @observable bool assertsEnabled = false; |
| @observable bool typeChecksEnabled = false; |
| @observable String pid = ''; |
| - @observable DateTime lastUpdate; |
| + @observable DateTime startTime; |
| + @observable DateTime refreshTime; |
| + @observable Duration get upTime => |
| + (new DateTime.now().difference(startTime)); |
| VM() : super._empty(null) { |
| name = 'vm'; |
| @@ -363,19 +365,6 @@ abstract class VM extends ServiceObjectOwner { |
| final StreamController<ServiceEvent> events = |
| new StreamController.broadcast(); |
| - bool _isIsolateLifecycleEvent(String eventType) { |
| - return _isIsolateExitEvent(eventType) || |
| - _isIsolateStartEvent(eventType); |
| - } |
| - |
| - bool _isIsolateExitEvent(String eventType) { |
| - return (eventType == ServiceEvent.kIsolateExit); |
| - } |
| - |
| - bool _isIsolateStartEvent(String eventType) { |
| - return (eventType == ServiceEvent.kIsolateStart); |
| - } |
| - |
| void postServiceEvent(String response, ByteData data) { |
| var map; |
| try { |
| @@ -394,98 +383,42 @@ abstract class VM extends ServiceObjectOwner { |
| return; |
| } |
| - var eventType = map['eventType']; |
| - |
| - if (_isIsolateLifecycleEvent(eventType)) { |
| - String isolateId = map['isolate']['id']; |
| - var event; |
| - if (_isIsolateStartEvent(eventType)) { |
| - _onIsolateStart(map['isolate']); |
| - // By constructing the event *after* adding the isolate to the |
| - // isolate cache, the call to getFromMap will use the cached Isolate. |
| - event = new ServiceObject._fromMap(this, map); |
| - } else { |
| - assert(_isIsolateExitEvent(eventType)); |
| - // By constructing the event *before* removing the isolate from the |
| - // isolate cache, the call to getFromMap will use the cached Isolate. |
| - event = new ServiceObject._fromMap(this, map); |
| - _onIsolateExit(isolateId); |
| + var eventIsolate = map['isolate']; |
| + if (eventIsolate == null) { |
| + var event = new ServiceObject._fromMap(vm, map); |
| + events.add(event); |
| + } else { |
| + // getFromMap creates the Isolate if it hasn't been seen already. |
| + var isolate = getFromMap(map['isolate']); |
| + var event = new ServiceObject._fromMap(isolate, map); |
| + if (event.eventType == ServiceEvent.kIsolateExit) { |
| + _removeIsolate(isolate.id); |
| } |
| - assert(event != null); |
| + isolate._onEvent(event); |
| events.add(event); |
| - return; |
| } |
| - |
| - // Extract the owning isolate from the event itself. |
| - String owningIsolateId = map['isolate']['id']; |
| - getIsolate(owningIsolateId).then((owningIsolate) { |
| - if (owningIsolate == null) { |
| - // TODO(koda): Do we care about GC events in VM isolate? |
| - Logger.root.severe('Ignoring event with unknown isolate id: ' |
| - '$owningIsolateId'); |
| - return; |
| - } |
| - var event = new ServiceObject._fromMap(owningIsolate, map); |
| - owningIsolate._onEvent(event); |
| - events.add(event); |
| - }); |
| } |
| - Isolate _onIsolateStart(Map isolateMap) { |
| - var isolateId = isolateMap['id']; |
| - assert(!_isolateCache.containsKey(isolateId)); |
| - Isolate isolate = new ServiceObject._fromMap(this, isolateMap); |
| - _isolateCache[isolateId] = isolate; |
| - notifyPropertyChange(#isolates, true, false); |
| - // Eagerly load the isolate. |
| - isolate.load().catchError((e) { |
| - Logger.root.info('Eagerly loading an isolate failed: $e'); |
| - }); |
| - return isolate; |
| - } |
| - |
| - void _onIsolateExit(String isolateId) { |
| + void _removeIsolate(String isolateId) { |
| assert(_isolateCache.containsKey(isolateId)); |
| _isolateCache.remove(isolateId); |
| notifyPropertyChange(#isolates, true, false); |
| } |
| - void _updateIsolatesFromList(List isolateList) { |
| - var shutdownIsolates = <String>[]; |
| - var createdIsolates = <Map>[]; |
| - var isolateStillExists = <String, bool>{}; |
| - |
| - // Start with the assumption that all isolates are gone. |
| - for (var isolateId in _isolateCache.keys) { |
| - isolateStillExists[isolateId] = false; |
| - } |
| - |
| - // Find created isolates and mark existing isolates as living. |
| - for (var isolateMap in isolateList) { |
| - var isolateId = isolateMap['id']; |
| - if (!_isolateCache.containsKey(isolateId)) { |
| - createdIsolates.add(isolateMap); |
| - } else { |
| - isolateStillExists[isolateId] = true; |
| - } |
| - } |
| + void _updateIsolates(List newIsolates) { |
| + // Build a set of new isolates. |
| + var newIsolateSet = new Set(); |
| + newIsolates.forEach((iso) => newIsolateSet.add(iso.id)); |
| - // Find shutdown isolates. |
| - isolateStillExists.forEach((isolateId, exists) { |
| - if (!exists) { |
| - shutdownIsolates.add(isolateId); |
| + // Remove any old isolates which no longer exist. |
| + List toRemove = []; |
| + _isolateCache.forEach((id, _) { |
| + if (!newIsolateSet.contains(id)) { |
| + toRemove.add(id); |
| } |
| }); |
| - |
| - // Process shutdown. |
| - for (var isolateId in shutdownIsolates) { |
| - _onIsolateExit(isolateId); |
| - } |
| - |
| - // Process creation. |
| - for (var isolateMap in createdIsolates) { |
| - _onIsolateStart(isolateMap); |
| - } |
| + toRemove.forEach((id) => _removeIsolate(id)); |
| + notifyPropertyChange(#isolates, true, false); |
| } |
| static final String _isolateIdPrefix = 'isolates/'; |
| @@ -503,11 +436,16 @@ abstract class VM extends ServiceObjectOwner { |
| // Check cache. |
| var isolate = _isolateCache[id]; |
| if (isolate == null) { |
| - // We should never see an unknown isolate here. |
| - throw new UnimplementedError(); |
| - } |
| - var mapIsRef = _hasRef(map['type']); |
| - if (!mapIsRef) { |
| + // Add new isolate to the cache. |
| + isolate = new ServiceObject._fromMap(this, map); |
| + _isolateCache[id] = isolate; |
| + notifyPropertyChange(#isolates, true, false); |
| + |
| + // Eagerly load the isolate. |
| + isolate.load().catchError((e, stack) { |
| + Logger.root.info('Eagerly loading an isolate failed: $e\n$stack'); |
| + }); |
| + } else { |
| isolate.update(map); |
| } |
| return isolate; |
| @@ -620,17 +558,23 @@ abstract class VM extends ServiceObjectOwner { |
| if (mapIsRef) { |
| return; |
| } |
| + // Note that upgrading the collection creates any isolates in the |
| + // isolate list which are new. |
| + _upgradeCollection(map, vm); |
| + |
| _loaded = true; |
| version = map['version']; |
| targetCPU = map['targetCPU']; |
| architectureBits = map['architectureBits']; |
| - uptime = map['uptime']; |
| - var dateInMillis = int.parse(map['date']); |
| - lastUpdate = new DateTime.fromMillisecondsSinceEpoch(dateInMillis); |
| + var startTimeMillis = map['startTime']; |
| + startTime = new DateTime.fromMillisecondsSinceEpoch(startTimeMillis); |
| + var refreshTimeMillis = map['refreshTime']; |
| + refreshTime = new DateTime.fromMillisecondsSinceEpoch(refreshTimeMillis); |
| + notifyPropertyChange(#upTime, 0, 1); |
| assertsEnabled = map['assertsEnabled']; |
| pid = map['pid']; |
| typeChecksEnabled = map['typeChecksEnabled']; |
| - _updateIsolatesFromList(map['isolates']); |
| + _updateIsolates(map['isolates']); |
|
Cutch
2015/03/18 20:05:48
s/_updateIsolates/_removeDeadIsolates
turnidge
2015/03/26 17:46:58
Done.
|
| } |
| // Reload all isolates. |
| @@ -776,9 +720,12 @@ class HeapSnapshot { |
| class Isolate extends ServiceObjectOwner with Coverage { |
| @reflectable VM get vm => owner; |
| @reflectable Isolate get isolate => this; |
| - @observable ObservableMap counters = new ObservableMap(); |
| + @observable int number; |
| + @observable DateTime startTime; |
| + @observable Duration get upTime => |
| + (new DateTime.now().difference(startTime)); |
| - @observable ServiceEvent pauseEvent = null; |
| + @observable ObservableMap counters = new ObservableMap(); |
| void _updateRunState() { |
| topFrame = (pauseEvent != null ? pauseEvent.topFrame : null); |
| @@ -792,6 +739,7 @@ class Isolate extends ServiceObjectOwner with Coverage { |
| notifyPropertyChange(#idle, 0, 1); |
| } |
| + @observable ServiceEvent pauseEvent = null; |
| @observable bool paused = false; |
| @observable bool running = false; |
| @observable bool idle = false; |
| @@ -859,13 +807,15 @@ class Isolate extends ServiceObjectOwner with Coverage { |
| if (map == null) { |
| return null; |
| } |
| + var mapType = _stripRef(map['type']); |
| + if (mapType == 'Isolate') { |
| + // There are sometimes isolate refs in ServiceEvents. |
| + return vm.getFromMap(map); |
| + } |
| String mapId = map['id']; |
| var obj = (mapId != null) ? _cache[mapId] : null; |
| if (obj != null) { |
| - var mapIsRef = _hasRef(map['type']); |
| - if (!mapIsRef) { |
| - obj.update(map); |
| - } |
| + obj.update(map); |
| return obj; |
| } |
| // Build the object from the map directly. |
| @@ -952,6 +902,7 @@ class Isolate extends ServiceObjectOwner with Coverage { |
| mainPort = map['mainPort']; |
| name = map['name']; |
| vmName = map['name']; |
| + number = int.parse(map['number'], onError:(_) => null); |
| if (mapIsRef) { |
| return; |
| } |
| @@ -969,7 +920,9 @@ class Isolate extends ServiceObjectOwner with Coverage { |
| if (map['entry'] != null) { |
| entry = map['entry']; |
| } |
| - |
| + var startTimeInMillis = map['startTime']; |
| + startTime = new DateTime.fromMillisecondsSinceEpoch(startTimeInMillis); |
| + notifyPropertyChange(#upTime, 0, 1); |
| var countersMap = map['tagCounters']; |
| if (countersMap != null) { |
| var names = countersMap['names']; |
| @@ -1037,21 +990,21 @@ class Isolate extends ServiceObjectOwner with Coverage { |
| ObservableMap<int, Breakpoint> breakpoints = new ObservableMap(); |
| void _updateBreakpoints(List newBpts) { |
| - // Build a map of new breakpoints. |
| - var newBptMap = {}; |
| - newBpts.forEach((bpt) => (newBptMap[bpt.number] = bpt)); |
| + // Build a set of new breakpoints. |
| + var newBptSet = new Set(); |
| + newBpts.forEach((bpt) => newBptSet.add(bpt.number)); |
| // Remove any old breakpoints which no longer exist. |
| List toRemove = []; |
| breakpoints.forEach((key, _) { |
| - if (!newBptMap.containsKey(key)) { |
| + if (!newBptSet.contains(key)) { |
| toRemove.add(key); |
| } |
| }); |
| toRemove.forEach((key) => breakpoints.remove(key)); |
| // Add all new breakpoints. |
| - breakpoints.addAll(newBptMap); |
| + newBpts.forEach((bpt) => (breakpoints[bpt.number] = bpt)); |
| } |
| void _addBreakpoint(Breakpoint bpt) { |
| @@ -1064,13 +1017,17 @@ class Isolate extends ServiceObjectOwner with Coverage { |
| } |
| void _onEvent(ServiceEvent event) { |
| - assert(event.eventType != ServiceEvent.kIsolateStart && |
| - event.eventType != ServiceEvent.kIsolateExit); |
| switch(event.eventType) { |
| + case ServiceEvent.kIsolateStart: |
| + case ServiceEvent.kIsolateExit: |
| + // Handled elsewhere. |
| + break; |
| + |
| case ServiceEvent.kBreakpointAdded: |
| _addBreakpoint(event.breakpoint); |
| break; |
| + case ServiceEvent.kIsolateUpdate: |
| case ServiceEvent.kBreakpointResolved: |
| // Update occurs as side-effect of caching. |
| break; |
| @@ -1141,6 +1098,7 @@ class Isolate extends ServiceObjectOwner with Coverage { |
| // TODO(turnidge): Handle this more gracefully. |
| Logger.root.severe(result.message); |
| } |
| + return result; |
| }); |
| } |
| @@ -1150,6 +1108,7 @@ class Isolate extends ServiceObjectOwner with Coverage { |
| // TODO(turnidge): Handle this more gracefully. |
| Logger.root.severe(result.message); |
| } |
| + return result; |
| }); |
| } |
| @@ -1159,6 +1118,7 @@ class Isolate extends ServiceObjectOwner with Coverage { |
| // TODO(turnidge): Handle this more gracefully. |
| Logger.root.severe(result.message); |
| } |
| + return result; |
| }); |
| } |
| @@ -1168,6 +1128,7 @@ class Isolate extends ServiceObjectOwner with Coverage { |
| // TODO(turnidge): Handle this more gracefully. |
| Logger.root.severe(result.message); |
| } |
| + return result; |
| }); |
| } |
| @@ -1177,9 +1138,17 @@ class Isolate extends ServiceObjectOwner with Coverage { |
| // TODO(turnidge): Handle this more gracefully. |
| Logger.root.severe(result.message); |
| } |
| + return result; |
| }); |
| } |
| + Future setName(String newName) { |
| + Map params = { |
| + 'name': newName, |
| + }; |
| + return invokeRpc('setName', params); |
| + } |
| + |
| Future<ServiceMap> getStack() { |
| return invokeRpc('getStack', {}).then((result) { |
| if (result is DartError) { |
| @@ -1422,6 +1391,7 @@ class ServiceEvent extends ServiceObject { |
| /// The possible 'eventType' values. |
| static const kIsolateStart = 'IsolateStart'; |
| static const kIsolateExit = 'IsolateExit'; |
| + static const kIsolateUpdate = 'IsolateUpdate'; |
| static const kPauseStart = 'PauseStart'; |
| static const kPauseExit = 'PauseExit'; |
| static const kPauseBreakpoint = 'PauseBreakpoint'; |
| @@ -1451,6 +1421,7 @@ class ServiceEvent extends ServiceObject { |
| void _update(ObservableMap map, bool mapIsRef) { |
| _loaded = true; |
| _upgradeCollection(map, owner); |
| + assert(map['isolate'] == null || owner == map['isolate']); |
| eventType = map['eventType']; |
| name = 'ServiceEvent $eventType'; |
| vmName = name; |
| @@ -1864,7 +1835,7 @@ class FunctionKind { |
| case 'Stub': return kStub; |
| case 'Tag': return kTag; |
| } |
| - print('did not understand $value'); |
| + Logger.root.severe('Unrecognized function kind: $value'); |
| throw new FallThroughError(); |
| } |
| @@ -2430,7 +2401,7 @@ class CodeKind { |
| } else if (s == 'Stub') { |
| return Stub; |
| } |
| - print('do not understand code kind $s'); |
| + Logger.root.severe('Unrecognized code kind: $s'); |
| throw new FallThroughError(); |
| } |
| static const Collected = const CodeKind._internal('Collected'); |