Index: runtime/bin/vmservice/client/lib/src/service/object.dart |
diff --git a/runtime/bin/vmservice/client/lib/src/service/object.dart b/runtime/bin/vmservice/client/lib/src/service/object.dart |
index 63e253f021a4a60c53cc05b7034d73c2bfb178a6..0a2129f692a9521410be796be8fdf5f8492db8c6 100644 |
--- a/runtime/bin/vmservice/client/lib/src/service/object.dart |
+++ b/runtime/bin/vmservice/client/lib/src/service/object.dart |
@@ -7,47 +7,73 @@ part of service; |
/// A [ServiceObject] is an object known to the VM service and is tied |
/// to an owning [Isolate]. |
abstract class ServiceObject extends Observable { |
- Isolate _isolate; |
+ /// The owner of this [ServiceObject]. This can be an [Isolate], a |
+ /// [VM], or null. |
+ @reflectable ServiceObject get owner => _owner; |
+ ServiceObject _owner; |
+ |
+ /// The [VM] which owns this [ServiceObject]. |
+ @reflectable VM get vm { |
+ if (owner == null) { |
+ assert(this is VM); |
+ return this; |
+ } else if (owner is VM) { |
+ return owner; |
+ } else { |
+ assert(owner.owner is VM); |
+ return owner.owner; |
+ } |
+ } |
- /// Owning isolate. |
- @reflectable Isolate get isolate => _isolate; |
+ /// The [Isolate] which owns this [ServiceObject]. May be null. |
+ @reflectable Isolate get isolate { |
+ if (owner == null) { |
+ return null; |
+ } else if (this is Isolate) { |
+ return this; |
+ } else { |
+ assert(owner is Isolate); |
+ return owner; |
+ } |
+ } |
- /// Owning vm. |
- @reflectable VM get vm => _isolate.vm; |
+ /// The id of this object. |
+ @reflectable String get id => _id; |
+ String _id; |
+ |
+ /// The service type of this object. |
+ @reflectable String get serviceType => _serviceType; |
+ String _serviceType; |
/// The complete service url of this object. |
@reflectable String get link => isolate.relativeLink(_id); |
/// The complete service url of this object with a '#/' prefix. |
- @reflectable String get hashLink => isolate.relativeHashLink(_id); |
+ @reflectable String get hashLink => '#/${link}'; |
set hashLink(var o) { /* silence polymer */ } |
- String _id; |
- /// The id of this object. |
- @reflectable String get id => _id; |
- |
- String _serviceType; |
- /// The service type of this object. |
- @reflectable String get serviceType => _serviceType; |
- |
+ /// Returns true if [this] has only been partially initialized via |
+ /// a reference. See [load]. |
+ bool isRef() => _ref; |
bool _ref; |
@observable String name; |
@observable String vmName; |
+ @observable String mainPort; |
- ServiceObject(this._isolate, this._id, this._serviceType) { |
+ ServiceObject(this._owner, this._id, this._serviceType) { |
_ref = isRefType(_serviceType); |
_serviceType = stripRef(_serviceType); |
_created(); |
} |
- ServiceObject.fromMap(this._isolate, ObservableMap m) { |
- assert(isServiceMap(m)); |
- _id = m['id']; |
- _ref = isRefType(m['type']); |
- _serviceType = stripRef(m['type']); |
+ ServiceObject.fromMap(this._owner, ObservableMap map) { |
+ assert(isServiceMap(map)); |
+ _id = map['id']; |
+ _ref = isRefType(map['type']); |
+ _serviceType = stripRef(map['type']); |
+ update(map); |
_created(); |
- update(m); |
} |
/// If [this] was created from a reference, load the full object |
@@ -64,13 +90,12 @@ abstract class ServiceObject extends Observable { |
/// Reload [this]. Returns a future which completes to [this] or |
/// a [ServiceError]. |
Future<ServiceObject> reload() { |
- assert(isolate != null); |
if (id == '') { |
// Errors don't have ids. |
assert(serviceType == 'Error'); |
return new Future.value(this); |
} |
- return isolate.vm.getAsMap(link).then(update); |
+ return vm.getAsMap(link).then(update); |
} |
/// Update [this] using [m] as a source. [m] can be a reference. |
@@ -92,16 +117,14 @@ abstract class ServiceObject extends Observable { |
// update internal state from [map]. [map] can be a reference. |
void _update(ObservableMap map); |
- /// Returns true if [this] has only been partially initialized via |
- /// a reference. See [load]. |
- bool isRef() => _ref; |
- |
void _created() { |
var refNotice = _ref ? ' Created from reference.' : ''; |
Logger.root.info('Created ServiceObject for \'${_id}\' with type ' |
'\'${_serviceType}\'.' + refNotice); |
} |
+ // ------------------------------------------------------ |
+ |
/// Returns true if [map] is a service map. i.e. it has the following keys: |
/// 'id' and a 'type'. |
static bool isServiceMap(ObservableMap m) { |
@@ -125,25 +148,87 @@ abstract class ServiceObject extends Observable { |
} |
/// State for a VM being inspected. |
-abstract class VM extends Observable { |
+abstract class VM extends ServiceObject { |
@reflectable IsolateList _isolates; |
@reflectable IsolateList get isolates => _isolates; |
+ @observable List<Isolate> allIsolates = toObservable([]); |
+ |
+ @reflectable String get link => "$id"; |
+ |
+ @observable String version = 'unknown'; |
+ @observable String architecture = 'unknown'; |
+ @observable double uptime = 0.0; |
+ |
void _initOnce() { |
assert(_isolates == null); |
_isolates = new IsolateList(this); |
+ name = "vm"; |
+ vmName = "vm"; |
} |
- VM() { |
+ VM() : super(null, "vm", "VM") { |
_initOnce(); |
} |
- /// Get [id] as an [ObservableMap] from the service directly. |
+ static final RegExp _currentIsolateMatcher = new RegExp(r'isolates/\d+'); |
+ static final RegExp _currentObjectMatcher = new RegExp(r'isolates/\d+(/|$)'); |
+ |
+ String _parseObjectId(String id) { |
+ Match m = _currentObjectMatcher.matchAsPrefix(id); |
+ if (m == null) { |
+ return null; |
+ } |
+ return m.input.substring(m.end); |
+ } |
+ |
+ String _parseIsolateId(String id) { |
+ Match m = _currentIsolateMatcher.matchAsPrefix(id); |
+ if (m == null) { |
+ return ''; |
+ } |
+ return id.substring(0, m.end); |
+ } |
+ |
+ Future<ServiceObject> getDirect(String id) { |
+ return vm.getAsMap(id).then((ObservableMap m) { |
+ return _upgradeToServiceObject(vm, null, m); |
+ }); |
+ } |
+ |
+ Future<ServiceObject> get(String id) { |
+ if (id.startsWith('isolates/')) { |
+ String isolateId = _parseIsolateId(id); |
+ if (isolateId == '') { |
+ return reload(); |
+ } else { |
+ Isolate isolate = _isolates.getIsolate(isolateId); |
+ if (isolate == null) { |
+ // TODO(turnidge): Isolate not found error. |
+ return reload(); |
+ } else { |
+ String objectId = _parseObjectId(id); |
+ if (objectId == null) { |
+ return isolate.reload(); |
+ } else { |
+ return isolate.get(objectId); |
+ } |
+ } |
+ } |
+ } else if (id == 'vm') { |
+ return reload(); |
+ } else { |
+ return getDirect(id); |
+ } |
+ } |
+ |
+ /// Gets [id] as an [ObservableMap] from the service directly. |
Future<ObservableMap> getAsMap(String id) { |
return getString(id).then((response) { |
try { |
var map = JSON.decode(response); |
Logger.root.info('Decoded $id'); |
+ Logger.root.info('Response $response'); |
return toObservable(map); |
} catch (e, st) { |
return toObservable({ |
@@ -165,14 +250,28 @@ abstract class VM extends Observable { |
/// Get [id] as a [String] from the service directly. See [getAsMap]. |
Future<String> getString(String id); |
+ |
+ void _update(ObservableMap map) { |
+ _ref = false; |
+ version = map['version']; |
+ architecture = map['architecture']; |
+ uptime = map['uptime']; |
+ _isolates.updateIsolates(map['isolates']); |
+ allIsolates.clear(); |
+ allIsolates.addAll(_isolates.isolates.values); |
+ } |
} |
/// State for a running isolate. |
class Isolate extends ServiceObject { |
- final VM vm; |
String get link => _id; |
String get hashLink => '#/$_id'; |
+ @observable bool pausedOnStart = false; |
+ @observable bool pausedOnExit = false; |
+ @observable bool running = false; |
+ @observable bool idle = false; |
+ |
ScriptCache _scripts; |
/// Script cache. |
ScriptCache get scripts => _scripts; |
@@ -188,19 +287,18 @@ class Isolate extends ServiceObject { |
void _initOnce() { |
// Only called once. |
- assert(_isolate == null); |
- _isolate = this; |
+ assert(_scripts == null); |
_scripts = new ScriptCache(this); |
_codes = new CodeCache(this); |
_classes = new ClassCache(this); |
_functions = new FunctionCache(this); |
} |
- Isolate.fromId(this.vm, String id) : super(null, id, '@Isolate') { |
+ Isolate.fromId(VM vm, String id) : super(vm, id, '@Isolate') { |
_initOnce(); |
} |
- Isolate.fromMap(this.vm, Map map) : super.fromMap(null, map) { |
+ Isolate.fromMap(VM vm, Map map) : super.fromMap(vm, map) { |
_initOnce(); |
} |
@@ -276,6 +374,11 @@ class Isolate extends ServiceObject { |
void _update(ObservableMap map) { |
upgradeCollection(map, vm, this); |
+ mainPort = map['mainPort']; |
+ name = map['name']; |
+ if (ServiceObject.isRefType(map['type'])) { |
+ return; |
+ } |
_ref = false; |
if (map['rootLib'] == null || |
map['timers'] == null || |
@@ -287,10 +390,6 @@ class Isolate extends ServiceObject { |
vmName = map['name']; |
if (map['entry'] != null) { |
entry = map['entry']; |
- name = entry['name']; |
- } else { |
- // fred |
- name = 'root'; |
} |
if (map['topFrame'] != null) { |
topFrame = map['topFrame']; |
@@ -315,6 +414,12 @@ class Isolate extends ServiceObject { |
oldHeapUsed = map['heap']['usedOld']; |
newHeapCapacity = map['heap']['capacityNew']; |
oldHeapCapacity = map['heap']['capacityOld']; |
+ |
+ // Isolate status |
+ pausedOnStart = map['pausedOnStart']; |
+ pausedOnExit = map['pausedOnExit']; |
+ running = map['topFrame'] != null; |
+ idle = !pausedOnStart && !pausedOnExit && !running; |
} |
@reflectable CodeTrieNode profileTrieRoot; |
@@ -364,28 +469,13 @@ class Isolate extends ServiceObject { |
} |
// TODO(johnmccutchan): Make this into an IsolateCache. |
-class IsolateList extends ServiceObject { |
+class IsolateList { |
final VM _vm; |
- VM get vm => _vm; |
- @observable final isolates = new ObservableMap<String, Isolate>(); |
- IsolateList(this._vm) : super(null, 'isolates', 'IsolateList') { |
- name = 'IsolateList'; |
- vmName = name; |
- } |
- IsolateList.fromMap(this._vm, Map m) : super.fromMap(null, m) { |
- name = 'IsolateList'; |
- vmName = name; |
- } |
- |
- Future<ServiceObject> reload() { |
- return vm.getAsMap(id).then(update); |
- } |
- |
- void _update(ObservableMap map) { |
- _updateIsolates(map['members']); |
- } |
+ final isolates = new ObservableMap<String, Isolate>(); |
- void _updateIsolates(List<Map> members) { |
+ IsolateList(this._vm); |
+ |
+ void updateIsolates(List<Map> members) { |
// Find dead isolates. |
var deadIsolates = []; |
isolates.forEach((k, v) { |
@@ -404,7 +494,7 @@ class IsolateList extends ServiceObject { |
var id = map['id']; |
var isolate = isolates[id]; |
if (isolate == null) { |
- isolate = new Isolate.fromMap(vm, map); |
+ isolate = new Isolate.fromMap(_vm, map); |
Logger.root.info('Created ServiceObject for \'${isolate.id}\' with ' |
'type \'${isolate.serviceType}\''); |
isolates[id] = isolate; |
@@ -429,7 +519,7 @@ class IsolateList extends ServiceObject { |
if (isolate != null) { |
return isolate; |
} |
- isolate = new Isolate.fromId(vm, id); |
+ isolate = new Isolate.fromId(_vm, id); |
isolates[id] = isolate; |
isolate.load(); |
return isolate; |
@@ -444,7 +534,7 @@ class IsolateList extends ServiceObject { |
isolate.update(m); |
return isolate; |
} |
- isolate = new Isolate.fromMap(vm, m); |
+ isolate = new Isolate.fromMap(_vm, m); |
isolates[id] = isolate; |
isolate.load(); |
return isolate; |
@@ -509,7 +599,7 @@ class ServiceMap extends ServiceObject implements ObservableMap { |
} |
class ServiceError extends ServiceObject { |
- ServiceError.fromMap(Isolate isolate, Map m) : super.fromMap(isolate, m); |
+ ServiceError.fromMap(ServiceObject owner, Map m) : super.fromMap(owner, m); |
@observable String kind; |
@observable String message; |