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

Unified Diff: runtime/observatory/lib/src/service/object.dart

Issue 979823003: Major rework of vm service events. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 5 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « runtime/observatory/lib/src/elements/script_ref.dart ('k') | runtime/observatory/test/code_test.dart » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 925e0e75eba7d5cfaaadc88d4d4a2ee261ccb130..71c6a09682c5139f00514899c99a8d431b6a6e8e 100644
--- a/runtime/observatory/lib/src/service/object.dart
+++ b/runtime/observatory/lib/src/service/object.dart
@@ -364,16 +364,16 @@ abstract class VM extends ServiceObjectOwner {
new StreamController.broadcast();
bool _isIsolateLifecycleEvent(String eventType) {
- return _isIsolateShutdownEvent(eventType) ||
- _isIsolateCreatedEvent(eventType);
+ return _isIsolateExitEvent(eventType) ||
+ _isIsolateStartEvent(eventType);
}
- bool _isIsolateShutdownEvent(String eventType) {
- return (eventType == 'IsolateShutdown');
+ bool _isIsolateExitEvent(String eventType) {
+ return (eventType == ServiceEvent.kIsolateExit);
}
- bool _isIsolateCreatedEvent(String eventType) {
- return (eventType == 'IsolateCreated');
+ bool _isIsolateStartEvent(String eventType) {
+ return (eventType == ServiceEvent.kIsolateStart);
}
void postServiceEvent(String response, ByteData data) {
@@ -399,17 +399,17 @@ abstract class VM extends ServiceObjectOwner {
if (_isIsolateLifecycleEvent(eventType)) {
String isolateId = map['isolate']['id'];
var event;
- if (_isIsolateCreatedEvent(eventType)) {
- _onIsolateCreated(map['isolate']);
+ 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(_isIsolateShutdownEvent(eventType));
+ 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);
- _onIsolateShutdown(isolateId);
+ _onIsolateExit(isolateId);
}
assert(event != null);
events.add(event);
@@ -426,11 +426,12 @@ abstract class VM extends ServiceObjectOwner {
return;
}
var event = new ServiceObject._fromMap(owningIsolate, map);
+ owningIsolate._onEvent(event);
events.add(event);
});
}
- Isolate _onIsolateCreated(Map isolateMap) {
+ Isolate _onIsolateStart(Map isolateMap) {
var isolateId = isolateMap['id'];
assert(!_isolateCache.containsKey(isolateId));
Isolate isolate = new ServiceObject._fromMap(this, isolateMap);
@@ -443,7 +444,7 @@ abstract class VM extends ServiceObjectOwner {
return isolate;
}
- void _onIsolateShutdown(String isolateId) {
+ void _onIsolateExit(String isolateId) {
assert(_isolateCache.containsKey(isolateId));
_isolateCache.remove(isolateId);
notifyPropertyChange(#isolates, true, false);
@@ -478,12 +479,12 @@ abstract class VM extends ServiceObjectOwner {
// Process shutdown.
for (var isolateId in shutdownIsolates) {
- _onIsolateShutdown(isolateId);
+ _onIsolateExit(isolateId);
}
// Process creation.
for (var isolateMap in createdIsolates) {
- _onIsolateCreated(isolateMap);
+ _onIsolateStart(isolateMap);
}
}
@@ -505,6 +506,10 @@ abstract class VM extends ServiceObjectOwner {
// We should never see an unknown isolate here.
throw new UnimplementedError();
}
+ var mapIsRef = _hasRef(map['type']);
+ if (!mapIsRef) {
+ isolate.update(map);
+ }
return isolate;
}
@@ -774,11 +779,24 @@ class Isolate extends ServiceObjectOwner with Coverage {
@observable ObservableMap counters = new ObservableMap();
@observable ServiceEvent pauseEvent = null;
- bool get _isPaused => pauseEvent != null;
+ void _updateRunState() {
+ topFrame = (pauseEvent != null ? pauseEvent.topFrame : null);
+ paused = (pauseEvent != null &&
+ pauseEvent.eventType != ServiceEvent.kResume);
+ running = (!paused && topFrame != null);
+ idle = (!paused && topFrame == null);
+ notifyPropertyChange(#topFrame, 0, 1);
+ notifyPropertyChange(#paused, 0, 1);
+ notifyPropertyChange(#running, 0, 1);
+ notifyPropertyChange(#idle, 0, 1);
+ }
+
+ @observable bool paused = false;
@observable bool running = false;
@observable bool idle = false;
@observable bool loading = true;
+
@observable bool ioEnabled = false;
Map<String,ServiceObject> _cache = new Map<String,ServiceObject>();
@@ -844,7 +862,10 @@ class Isolate extends ServiceObjectOwner with Coverage {
String mapId = map['id'];
var obj = (mapId != null) ? _cache[mapId] : null;
if (obj != null) {
- // Consider calling update when map is not a reference.
+ var mapIsRef = _hasRef(map['type']);
+ if (!mapIsRef) {
+ obj.update(map);
+ }
return obj;
}
// Build the object from the map directly.
@@ -862,12 +883,7 @@ class Isolate extends ServiceObjectOwner with Coverage {
Future<ServiceObject> invokeRpc(String method, Map params) {
return invokeRpcNoUpgrade(method, params).then((ObservableMap response) {
- var obj = new ServiceObject._fromMap(this, response);
- if ((obj != null) && obj.canCache) {
- String objId = obj.id;
- _cache.putIfAbsent(objId, () => obj);
- }
- return obj;
+ return getFromMap(response);
});
}
@@ -912,9 +928,11 @@ class Isolate extends ServiceObjectOwner with Coverage {
@observable HeapSnapshot latestSnapshot;
Completer<HeapSnapshot> _snapshotFetch;
- void loadHeapSnapshot(ServiceEvent event) {
+ void _loadHeapSnapshot(ServiceEvent event) {
latestSnapshot = new HeapSnapshot(this, event.data);
- _snapshotFetch.complete(latestSnapshot);
+ if (_snapshotFetch != null) {
+ _snapshotFetch.complete(latestSnapshot);
+ }
}
Future<HeapSnapshot> fetchHeapSnapshot() {
@@ -940,7 +958,6 @@ class Isolate extends ServiceObjectOwner with Coverage {
_loaded = true;
loading = false;
- reloadBreakpoints();
_upgradeCollection(map, isolate);
if (map['rootLib'] == null ||
map['timers'] == null ||
@@ -952,11 +969,6 @@ class Isolate extends ServiceObjectOwner with Coverage {
if (map['entry'] != null) {
entry = map['entry'];
}
- if (map['topFrame'] != null) {
- topFrame = map['topFrame'];
- } else {
- topFrame = null ;
- }
var countersMap = map['tagCounters'];
if (countersMap != null) {
@@ -994,6 +1006,7 @@ class Isolate extends ServiceObjectOwner with Coverage {
timers['dart'] = timerMap['time_dart_execution'];
updateHeapsFromMap(map['heaps']);
+ _updateBreakpoints(map['breakpoints']);
List features = map['features'];
if (features != null) {
@@ -1003,10 +1016,8 @@ class Isolate extends ServiceObjectOwner with Coverage {
}
}
}
- // Isolate status
pauseEvent = map['pauseEvent'];
- running = (!_isPaused && map['topFrame'] != null);
- idle = (!_isPaused && map['topFrame'] == null);
+ _updateRunState();
error = map['error'];
libraries.clear();
@@ -1023,71 +1034,74 @@ class Isolate extends ServiceObjectOwner with Coverage {
});
}
- ObservableList<Breakpoint> breakpoints = new ObservableList();
+ ObservableMap<int, Breakpoint> breakpoints = new ObservableMap();
- void _removeBreakpoint(Breakpoint bpt) {
- var script = bpt.script;
- var tokenPos = bpt.tokenPos;
- assert(tokenPos != null);
- if (script.loaded) {
- var line = script.tokenToLine(tokenPos);
- assert(line != null);
- if (script.lines[line - 1] != null) {
- assert(script.lines[line - 1].bpt == bpt);
- script.lines[line - 1].bpt = null;
+ void _updateBreakpoints(List newBpts) {
+ // Build a map of new breakpoints.
+ var newBptMap = {};
+ newBpts.forEach((bpt) => (newBptMap[bpt.number] = bpt));
+
+ // Remove any old breakpoints which no longer exist.
+ List toRemove = [];
+ breakpoints.forEach((key, _) {
+ if (!newBptMap.containsKey(key)) {
+ toRemove.add(key);
}
- }
+ });
+ toRemove.forEach((key) => breakpoints.remove(key));
+
+ // Add all new breakpoints.
+ breakpoints.addAll(newBptMap);
}
void _addBreakpoint(Breakpoint bpt) {
- var script = bpt.script;
- var tokenPos = bpt.tokenPos;
- assert(tokenPos != null);
- if (script.loaded) {
- var line = script.tokenToLine(tokenPos);
- assert(line != null);
- assert(script.lines[line - 1].bpt == null);
- script.lines[line - 1].bpt = bpt;
- } else {
- // Load the script and then plop in the breakpoint.
- script.load().then((_) {
- _addBreakpoint(bpt);
- });
- }
+ breakpoints[bpt.number] = bpt;
}
- void _updateBreakpoints(ServiceMap newBreakpoints) {
- // Remove all of the old breakpoints from the Script lines.
- if (breakpoints != null) {
- for (var bpt in breakpoints) {
- _removeBreakpoint(bpt);
- }
- }
- // Add all of the new breakpoints to the Script lines.
- for (var bpt in newBreakpoints['breakpoints']) {
- _addBreakpoint(bpt);
- }
- breakpoints.clear();
- breakpoints.addAll(newBreakpoints['breakpoints']);
-
- // Sort the breakpoints by breakpointNumber.
- breakpoints.sort((a, b) => (a.number - b.number));
+ void _removeBreakpoint(Breakpoint bpt) {
+ breakpoints.remove(bpt.number);
+ bpt.remove();
}
- Future<ServiceObject> _inProgressReloadBpts;
+ void _onEvent(ServiceEvent event) {
+ assert(event.eventType != ServiceEvent.kIsolateStart &&
+ event.eventType != ServiceEvent.kIsolateExit);
+ switch(event.eventType) {
+ case ServiceEvent.kBreakpointAdded:
+ _addBreakpoint(event.breakpoint);
+ break;
+
+ case ServiceEvent.kBreakpointResolved:
+ // Update occurs as side-effect of caching.
+ break;
+
+ case ServiceEvent.kBreakpointRemoved:
+ _removeBreakpoint(event.breakpoint);
+ break;
- Future reloadBreakpoints() {
- // TODO(turnidge): Can reusing the Future here ever cause us to
- // get stale breakpoints?
- if (_inProgressReloadBpts == null) {
- _inProgressReloadBpts =
- invokeRpc('getBreakpoints', {}).then((newBpts) {
- _updateBreakpoints(newBpts);
- }).whenComplete(() {
- _inProgressReloadBpts = null;
- });
+ case ServiceEvent.kPauseStart:
+ case ServiceEvent.kPauseExit:
+ case ServiceEvent.kPauseBreakpoint:
+ case ServiceEvent.kPauseInterrupted:
+ case ServiceEvent.kPauseException:
+ case ServiceEvent.kResume:
+ pauseEvent = event;
+ _updateRunState();
+ break;
+
+ case ServiceEvent.kGraph:
+ _loadHeapSnapshot(event);
+ break;
+
+ case ServiceEvent.kGC:
+ // Ignore GC events for now.
+ break;
+
+ default:
+ // Log unrecognized events.
+ Logger.root.severe('Unrecognized event: $event');
+ break;
}
- return _inProgressReloadBpts;
}
Future<ServiceObject> addBreakpoint(Script script, int line) {
@@ -1107,41 +1121,18 @@ class Isolate extends ServiceObjectOwner with Coverage {
// Unable to set a breakpoint at desired line.
script.lines[line - 1].possibleBpt = false;
}
- // TODO(turnidge): Instead of reloading all of the breakpoints,
- // rely on events to update the breakpoint list.
- return reloadBreakpoints().then((_) {
- return result;
- });
+ return result;
});
}
Future<ServiceObject> addBreakpointAtEntry(ServiceFunction function) {
return invokeRpc('addBreakpointAtEntry',
- { 'functionId': function.id }).then((result) {
- // TODO(turnidge): Instead of reloading all of the breakpoints,
- // rely on events to update the breakpoint list.
- return reloadBreakpoints().then((_) {
- return result;
- });
- });
+ { 'functionId': function.id });
}
Future removeBreakpoint(Breakpoint bpt) {
return invokeRpc('removeBreakpoint',
- { 'breakpointId': bpt.id }).then((result) {
- if (result is DartError) {
- // TODO(turnidge): Handle this more gracefully.
- Logger.root.severe(result.message);
- return result;
- }
- if (pauseEvent != null &&
- pauseEvent.breakpoint != null &&
- (pauseEvent.breakpoint.id == bpt.id)) {
- return isolate.reload();
- } else {
- return reloadBreakpoints();
- }
- });
+ { 'breakpointId': bpt.id });
}
// TODO(turnidge): If the user invokes pause (or other rpcs) twice,
@@ -1319,14 +1310,10 @@ class ServiceMap extends ServiceObject implements ObservableMap {
ServiceMap._empty(ServiceObjectOwner owner) : super._empty(owner);
- void _upgradeValues() {
- assert(owner != null);
- _upgradeCollection(_map, owner);
- }
-
void _update(ObservableMap map, bool mapIsRef) {
_loaded = !mapIsRef;
+ _upgradeCollection(map, owner);
// TODO(turnidge): Currently _map.clear() prevents us from
// upgrading an already upgraded submap. Is clearing really the
// right thing to do here?
@@ -1335,7 +1322,6 @@ class ServiceMap extends ServiceObject implements ObservableMap {
name = _map['name'];
vmName = (_map.containsKey('vmName') ? _map['vmName'] : name);
- _upgradeValues();
}
// Forward Map interface calls.
@@ -1432,14 +1418,31 @@ class ServiceException extends ServiceObject {
/// A [ServiceEvent] is an asynchronous event notification from the vm.
class ServiceEvent extends ServiceObject {
+ /// The possible 'eventType' values.
+ static const kIsolateStart = 'IsolateStart';
+ static const kIsolateExit = 'IsolateExit';
+ static const kPauseStart = 'PauseStart';
+ static const kPauseExit = 'PauseExit';
+ static const kPauseBreakpoint = 'PauseBreakpoint';
+ static const kPauseInterrupted = 'PauseInterrupted';
+ static const kPauseException = 'PauseException';
+ static const kResume = 'Resume';
+ static const kBreakpointAdded = 'BreakpointAdded';
+ static const kBreakpointResolved = 'BreakpointResolved';
+ static const kBreakpointRemoved = 'BreakpointRemoved';
+ static const kGraph = '_Graph';
+ static const kGC = 'GC';
+ static const kVMDisconnected = 'VMDisconnected';
+
ServiceEvent._empty(ServiceObjectOwner owner) : super._empty(owner);
ServiceEvent.vmDisconencted() : super._empty(null) {
- eventType = 'VMDisconnected';
+ eventType = kVMDisconnected;
}
@observable String eventType;
@observable Breakpoint breakpoint;
+ @observable ServiceMap topFrame;
@observable ServiceMap exception;
@observable ByteData data;
@observable int count;
@@ -1453,6 +1456,9 @@ class ServiceEvent extends ServiceObject {
if (map['breakpoint'] != null) {
breakpoint = map['breakpoint'];
}
+ if (map['topFrame'] != null) {
+ topFrame = map['topFrame'];
+ }
if (map['exception'] != null) {
exception = map['exception'];
}
@@ -1465,8 +1471,12 @@ class ServiceEvent extends ServiceObject {
}
String toString() {
- return 'ServiceEvent of type $eventType with '
- '${data == null ? 0 : data.lengthInBytes} bytes of binary data';
+ if (data == null) {
+ return "ServiceEvent(owner='${owner.id}', type='${eventType}')";
+ } else {
+ return "ServiceEvent(owner='${owner.id}', type='${eventType}', "
+ "data.lengthInBytes=${data.lengthInBytes})";
+ }
}
}
@@ -1488,19 +1498,44 @@ class Breakpoint extends ServiceObject {
// The breakpoint has been assigned to a final source location.
@observable bool resolved;
- // The breakpoint is active.
- @observable bool enabled;
-
void _update(ObservableMap map, bool mapIsRef) {
_loaded = true;
_upgradeCollection(map, owner);
+ var newNumber = map['breakpointNumber'];
+ var newScript = map['location']['script'];
+ var newTokenPos = map['location']['tokenPos'];
+
+ // number and script never change.
+ assert((number == null) || (number == newNumber));
+ assert((script == null) || (script == newScript));
+
number = map['breakpointNumber'];
script = map['location']['script'];
- tokenPos = map['location']['tokenPos'];
-
resolved = map['resolved'];
- enabled = map['enabled'];
+ bool tokenPosChanged = tokenPos != newTokenPos;
+
+ if (script.loaded &&
+ (tokenPos != null) &&
+ tokenPosChanged) {
+ // The breakpoint has moved. Remove it and add it later.
+ script._removeBreakpoint(this);
+ }
+
+ tokenPos = newTokenPos;
+ if (script.loaded && tokenPosChanged) {
+ script._addBreakpoint(this);
+ }
+ }
+
+ void remove() {
+ // Remove any references to this breakpoint. It has been removed.
+ script._removeBreakpoint(this);
+ if ((isolate.pauseEvent != null) &&
+ (isolate.pauseEvent.breakpoint != null) &&
+ (isolate.pauseEvent.breakpoint.id == id)) {
+ isolate.pauseEvent.breakpoint = null;
+ }
}
String toString() {
@@ -1969,8 +2004,9 @@ class ScriptLine extends Observable {
final int line;
final String text;
@observable int hits;
- @observable Breakpoint bpt;
@observable bool possibleBpt = true;
+ @observable bool breakpointResolved = false;
+ @observable Set<Breakpoint> breakpoints;
bool get isBlank {
// Compute isBlank on demand.
@@ -2015,13 +2051,22 @@ class ScriptLine extends Observable {
ScriptLine(this.script, this.line, this.text) {
possibleBpt = !_isTrivialLine(text);
+ }
- // TODO(turnidge): This is not so efficient. Consider improving.
- for (var bpt in this.script.isolate.breakpoints) {
- if (bpt.script == this.script &&
- bpt.script.tokenToLine(bpt.tokenPos) == line) {
- this.bpt = bpt;
- }
+ void addBreakpoint(Breakpoint bpt) {
+ if (breakpoints == null) {
+ breakpoints = new Set<Breakpoint>();
+ }
+ breakpoints.add(bpt);
+ breakpointResolved = breakpointResolved || bpt.resolved;
+ }
+
+ void removeBreakpoint(Breakpoint bpt) {
+ assert(breakpoints != null && breakpoints.contains(bpt));
+ breakpoints.remove(bpt);
+ if (breakpoints.isEmpty) {
+ breakpoints = null;
+ breakpointResolved = false;
}
}
}
@@ -2064,8 +2109,8 @@ class Script extends ServiceObject with Coverage {
if (mapIsRef) {
return;
}
- _processSource(map['source']);
_parseTokenPosTable(map['tokenPosTable']);
+ _processSource(map['source']);
owningLibrary = map['owningLibrary'];
}
@@ -2145,6 +2190,12 @@ class Script extends ServiceObject with Coverage {
for (var i = 0; i < sourceLines.length; i++) {
lines.add(new ScriptLine(this, i + 1, sourceLines[i]));
}
+ for (var bpt in isolate.breakpoints.values) {
+ if (bpt.script == this) {
+ _addBreakpoint(bpt);
+ }
+ }
+
_applyHitsToLines();
// Notify any Observers that this Script's state has changed.
notifyChange(null);
@@ -2156,6 +2207,18 @@ class Script extends ServiceObject with Coverage {
line.hits = hits;
}
}
+
+ void _addBreakpoint(Breakpoint bpt) {
+ var line = tokenToLine(bpt.tokenPos);
+ getLine(line).addBreakpoint(bpt);
+ }
+
+ void _removeBreakpoint(Breakpoint bpt) {
+ var line = tokenToLine(bpt.tokenPos);
+ if (line != null) {
+ getLine(line).removeBreakpoint(bpt);
+ }
+ }
}
class PcDescriptor extends Observable {
« no previous file with comments | « runtime/observatory/lib/src/elements/script_ref.dart ('k') | runtime/observatory/test/code_test.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698