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 /// An RpcException represents an exceptional event that happened |
| 8 /// while invoking an rpc. |
| 9 abstract class RpcException implements Exception { |
| 10 RpcException(this.message); |
| 11 |
| 12 String message; |
| 13 } |
| 14 |
| 15 /// A ServerRpcException represents an error returned by the VM. |
| 16 class ServerRpcException extends RpcException { |
| 17 /// A list of well-known server error codes. |
| 18 static const kParseError = -32700; |
| 19 static const kInvalidRequest = -32600; |
| 20 static const kMethodNotFound = -32601; |
| 21 static const kInvalidParams = -32602; |
| 22 static const kInternalError = -32603; |
| 23 static const kVMMustBePaused = 100; |
| 24 static const kNoBreakAtLine = 101; |
| 25 static const kNoBreakAtFunction = 102; |
| 26 static const kProfilingDisabled = 200; |
| 27 |
| 28 int code; |
| 29 Map data; |
| 30 |
| 31 static _getMessage(Map errorMap) { |
| 32 Map data = errorMap['data']; |
| 33 if (data != null && data['details'] != null) { |
| 34 return data['details']; |
| 35 } else { |
| 36 return errorMap['message']; |
| 37 } |
| 38 } |
| 39 |
| 40 ServerRpcException.fromMap(Map errorMap) : super(_getMessage(errorMap)) { |
| 41 code = errorMap['code']; |
| 42 data = errorMap['data']; |
| 43 } |
| 44 |
| 45 String toString() => 'ServerRpcException(${message})'; |
| 46 } |
| 47 |
| 48 /// A NetworkRpcException is used to indicate that an rpc has |
| 49 /// been canceled due to network error. |
| 50 class NetworkRpcException extends RpcException { |
| 51 NetworkRpcException(String message) : super(message); |
| 52 |
| 53 String toString() => 'NetworkRpcException(${message})'; |
| 54 } |
| 55 |
| 56 class MalformedResponseRpcException extends RpcException { |
| 57 MalformedResponseRpcException(String message, this.response) |
| 58 : super(message); |
| 59 |
| 60 Map response; |
| 61 |
| 62 String toString() => 'MalformedResponseRpcException(${message})'; |
| 63 } |
| 64 |
| 65 class FakeVMRpcException extends RpcException { |
| 66 FakeVMRpcException(String message) : super(message); |
| 67 |
| 68 String toString() => 'FakeVMRpcException(${message})'; |
| 69 } |
| 70 |
7 /// A [ServiceObject] represents a persistent object within the vm. | 71 /// A [ServiceObject] represents a persistent object within the vm. |
8 abstract class ServiceObject extends Observable { | 72 abstract class ServiceObject extends Observable { |
9 static int LexicalSortName(ServiceObject o1, ServiceObject o2) { | 73 static int LexicalSortName(ServiceObject o1, ServiceObject o2) { |
10 return o1.name.compareTo(o2.name); | 74 return o1.name.compareTo(o2.name); |
11 } | 75 } |
12 | 76 |
13 List removeDuplicatesAndSortLexical(List<ServiceObject> list) { | 77 List removeDuplicatesAndSortLexical(List<ServiceObject> list) { |
14 return list.toSet().toList()..sort(LexicalSortName); | 78 return list.toSet().toList()..sort(LexicalSortName); |
15 } | 79 } |
16 | 80 |
(...skipping 146 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
163 obj = new PcDescriptors._empty(owner); | 227 obj = new PcDescriptors._empty(owner); |
164 break; | 228 break; |
165 case 'LocalVarDescriptors': | 229 case 'LocalVarDescriptors': |
166 obj = new LocalVarDescriptors._empty(owner); | 230 obj = new LocalVarDescriptors._empty(owner); |
167 break; | 231 break; |
168 case 'TokenStream': | 232 case 'TokenStream': |
169 obj = new TokenStream._empty(owner); | 233 obj = new TokenStream._empty(owner); |
170 break; | 234 break; |
171 } | 235 } |
172 break; | 236 break; |
173 case 'ServiceError': | |
174 obj = new ServiceError._empty(owner); | |
175 break; | |
176 case 'ServiceEvent': | 237 case 'ServiceEvent': |
177 obj = new ServiceEvent._empty(owner); | 238 obj = new ServiceEvent._empty(owner); |
178 break; | 239 break; |
179 case 'ServiceException': | |
180 obj = new ServiceException._empty(owner); | |
181 break; | |
182 case 'Script': | 240 case 'Script': |
183 obj = new Script._empty(owner); | 241 obj = new Script._empty(owner); |
184 break; | 242 break; |
185 case 'Socket': | 243 case 'Socket': |
186 obj = new Socket._empty(owner); | 244 obj = new Socket._empty(owner); |
187 break; | 245 break; |
188 default: | 246 default: |
189 if (_isInstanceType(type) || | 247 if (_isInstanceType(type) || |
190 type == 'Sentinel') { // TODO(rmacnak): Separate this out. | 248 type == 'Sentinel') { // TODO(rmacnak): Separate this out. |
191 obj = new Instance._empty(owner); | 249 obj = new Instance._empty(owner); |
(...skipping 20 matching lines...) Expand all Loading... |
212 Future<ServiceObject> _inProgressReload; | 270 Future<ServiceObject> _inProgressReload; |
213 | 271 |
214 Future<ObservableMap> _fetchDirect() { | 272 Future<ObservableMap> _fetchDirect() { |
215 Map params = { | 273 Map params = { |
216 'objectId': id, | 274 'objectId': id, |
217 }; | 275 }; |
218 return isolate.invokeRpcNoUpgrade('getObject', params); | 276 return isolate.invokeRpcNoUpgrade('getObject', params); |
219 } | 277 } |
220 | 278 |
221 /// Reload [this]. Returns a future which completes to [this] or | 279 /// Reload [this]. Returns a future which completes to [this] or |
222 /// a [ServiceError]. | 280 /// an exception. |
223 Future<ServiceObject> reload() { | 281 Future<ServiceObject> reload() { |
224 if (id == '') { | 282 // TODO(turnidge): Checkign for a null id should be part of the |
225 // Errors don't have ids. | 283 // "immmutable" check. |
226 assert(type == 'Error'); | 284 if (id == null || id == '') { |
227 return new Future.value(this); | 285 return new Future.value(this); |
228 } | 286 } |
229 if (loaded && immutable) { | 287 if (loaded && immutable) { |
230 return new Future.value(this); | 288 return new Future.value(this); |
231 } | 289 } |
232 if (_inProgressReload == null) { | 290 if (_inProgressReload == null) { |
233 _inProgressReload = _fetchDirect().then((ObservableMap map) { | 291 var completer = new Completer<ServiceObject>(); |
234 var mapType = _stripRef(map['type']); | 292 _inProgressReload = completer.future; |
235 if (mapType != _type) { | 293 _fetchDirect().then((ObservableMap map) { |
236 // If the type changes, return a new object instead of | 294 var mapType = _stripRef(map['type']); |
237 // updating the existing one. | 295 if (mapType == 'Sentinel') { |
238 // | 296 // An object may have been collected, etc. |
239 // TODO(turnidge): Check for vmType changing as well? | 297 completer.complete(new ServiceObject._fromMap(owner, map)); |
240 assert(mapType == 'Error' || mapType == 'Sentinel'); | 298 } else { |
241 return new ServiceObject._fromMap(owner, map); | 299 // TODO(turnidge): Check for vmType changing as well? |
242 } | 300 assert(mapType == _type); |
243 update(map); | 301 update(map); |
244 return this; | 302 completer.complete(this); |
| 303 } |
| 304 |
| 305 }).catchError((e, st) { |
| 306 Logger.root.severe("Unable to reload object: $e\n$st"); |
| 307 _inProgressReload = null; |
| 308 completer.completeError(e, st); |
245 }).whenComplete(() { | 309 }).whenComplete(() { |
246 // This reload is complete. | 310 // This reload is complete. |
247 _inProgressReload = null; | 311 _inProgressReload = null; |
248 }); | 312 }); |
249 } | 313 } |
250 return _inProgressReload; | 314 return _inProgressReload; |
251 } | 315 } |
252 | 316 |
253 /// Update [this] using [map] as a source. [map] can be a reference. | 317 /// Update [this] using [map] as a source. [map] can be a reference. |
254 void update(ObservableMap map) { | 318 void update(ObservableMap map) { |
255 assert(_isServiceMap(map)); | 319 assert(_isServiceMap(map)); |
256 | 320 |
257 // Don't allow the type to change on an object update. | 321 // Don't allow the type to change on an object update. |
258 // TODO(turnidge): Make this a ServiceError? | |
259 var mapIsRef = _hasRef(map['type']); | 322 var mapIsRef = _hasRef(map['type']); |
260 var mapType = _stripRef(map['type']); | 323 var mapType = _stripRef(map['type']); |
261 assert(_type == null || _type == mapType); | 324 assert(_type == null || _type == mapType); |
262 | 325 |
263 if (_id != null && _id != map['id']) { | 326 if (_id != null && _id != map['id']) { |
264 // It is only safe to change an id when the object isn't cacheable. | 327 // It is only safe to change an id when the object isn't cacheable. |
265 assert(!canCache); | 328 assert(!canCache); |
266 } | 329 } |
267 _id = map['id']; | 330 _id = map['id']; |
268 | 331 |
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
331 /// The result may come from the cache. The result will not necessarily | 394 /// The result may come from the cache. The result will not necessarily |
332 /// be [loaded]. | 395 /// be [loaded]. |
333 ServiceObject getFromMap(ObservableMap map); | 396 ServiceObject getFromMap(ObservableMap map); |
334 } | 397 } |
335 | 398 |
336 /// State for a VM being inspected. | 399 /// State for a VM being inspected. |
337 abstract class VM extends ServiceObjectOwner { | 400 abstract class VM extends ServiceObjectOwner { |
338 @reflectable VM get vm => this; | 401 @reflectable VM get vm => this; |
339 @reflectable Isolate get isolate => null; | 402 @reflectable Isolate get isolate => null; |
340 | 403 |
| 404 // TODO(turnidge): The connection should not be stored in the VM object. |
| 405 bool get isDisconnected; |
| 406 |
341 // TODO(johnmccutchan): Ensure that isolates do not end up in _cache. | 407 // TODO(johnmccutchan): Ensure that isolates do not end up in _cache. |
342 Map<String,ServiceObject> _cache = new Map<String,ServiceObject>(); | 408 Map<String,ServiceObject> _cache = new Map<String,ServiceObject>(); |
343 final ObservableMap<String,Isolate> _isolateCache = | 409 final ObservableMap<String,Isolate> _isolateCache = |
344 new ObservableMap<String,Isolate>(); | 410 new ObservableMap<String,Isolate>(); |
345 | 411 |
346 @reflectable Iterable<Isolate> get isolates => _isolateCache.values; | 412 @reflectable Iterable<Isolate> get isolates => _isolateCache.values; |
347 | 413 |
348 @observable String version = 'unknown'; | 414 @observable String version = 'unknown'; |
349 @observable String targetCPU; | 415 @observable String targetCPU; |
350 @observable int architectureBits; | 416 @observable int architectureBits; |
351 @observable bool assertsEnabled = false; | 417 @observable bool assertsEnabled = false; |
352 @observable bool typeChecksEnabled = false; | 418 @observable bool typeChecksEnabled = false; |
353 @observable String pid = ''; | 419 @observable String pid = ''; |
354 @observable DateTime startTime; | 420 @observable DateTime startTime; |
355 @observable DateTime refreshTime; | 421 @observable DateTime refreshTime; |
356 @observable Duration get upTime => | 422 @observable Duration get upTime => |
357 (new DateTime.now().difference(startTime)); | 423 (new DateTime.now().difference(startTime)); |
358 | 424 |
359 VM() : super._empty(null) { | 425 VM() : super._empty(null) { |
360 name = 'vm'; | 426 name = 'vm'; |
361 vmName = 'vm'; | 427 vmName = 'vm'; |
362 _cache['vm'] = this; | 428 _cache['vm'] = this; |
363 update(toObservable({'id':'vm', 'type':'@VM'})); | 429 update(toObservable({'id':'vm', 'type':'@VM'})); |
364 } | 430 } |
365 | 431 |
366 final StreamController<ServiceException> exceptions = | |
367 new StreamController.broadcast(); | |
368 final StreamController<ServiceError> errors = | |
369 new StreamController.broadcast(); | |
370 final StreamController<ServiceEvent> events = | 432 final StreamController<ServiceEvent> events = |
371 new StreamController.broadcast(); | 433 new StreamController.broadcast(); |
372 | 434 |
373 void postServiceEvent(Map response, ByteData data) { | 435 void postServiceEvent(Map response, ByteData data) { |
374 var map = toObservable(response); | 436 var map = toObservable(response); |
375 assert(!map.containsKey('_data')); | 437 assert(!map.containsKey('_data')); |
376 if (data != null) { | 438 if (data != null) { |
377 map['_data'] = data; | 439 map['_data'] = data; |
378 } | 440 } |
379 if (map['type'] != 'ServiceEvent') { | 441 if (map['type'] != 'ServiceEvent') { |
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
453 // Note that this function does not reload the isolate if it found | 515 // Note that this function does not reload the isolate if it found |
454 // in the cache. | 516 // in the cache. |
455 Future<ServiceObject> getIsolate(String isolateId) { | 517 Future<ServiceObject> getIsolate(String isolateId) { |
456 if (!loaded) { | 518 if (!loaded) { |
457 // Trigger a VM load, then get the isolate. | 519 // Trigger a VM load, then get the isolate. |
458 return load().then((_) => getIsolate(isolateId)).catchError(_ignoreError); | 520 return load().then((_) => getIsolate(isolateId)).catchError(_ignoreError); |
459 } | 521 } |
460 return new Future.value(_isolateCache[isolateId]); | 522 return new Future.value(_isolateCache[isolateId]); |
461 } | 523 } |
462 | 524 |
463 Future<ObservableMap> _processMap(ObservableMap map) { | |
464 // Verify that the top level response is a service map. | |
465 if (!_isServiceMap(map)) { | |
466 return new Future.error( | |
467 new ServiceObject._fromMap(this, toObservable({ | |
468 'type': 'ServiceException', | |
469 'kind': 'ResponseFormatException', | |
470 'response': map, | |
471 'message': "Response is missing the 'type' field.", | |
472 }))); | |
473 } | |
474 // Preemptively capture ServiceError and ServiceExceptions. | |
475 if (map['type'] == 'ServiceError') { | |
476 return new Future.error(new ServiceObject._fromMap(this, map)); | |
477 } else if (map['type'] == 'ServiceException') { | |
478 return new Future.error(new ServiceObject._fromMap(this, map)); | |
479 } | |
480 // map is now guaranteed to be a non-error/exception ServiceObject. | |
481 return new Future.value(map); | |
482 } | |
483 | |
484 // Implemented in subclass. | 525 // Implemented in subclass. |
485 Future<Map> invokeRpcRaw(String method, Map params); | 526 Future<Map> invokeRpcRaw(String method, Map params); |
486 | 527 |
487 Future<ObservableMap> invokeRpcNoUpgrade(String method, Map params) { | 528 Future<ObservableMap> invokeRpcNoUpgrade(String method, Map params) { |
488 return invokeRpcRaw(method, params).then((Map response) { | 529 return invokeRpcRaw(method, params).then((Map response) { |
489 var map = toObservable(response); | 530 var map = toObservable(response); |
490 if (Tracer.current != null) { | 531 if (Tracer.current != null) { |
491 Tracer.current.trace("Received response for ${method}/${params}}", | 532 Tracer.current.trace("Received response for ${method}/${params}}", |
492 map:map); | 533 map:map); |
493 } | 534 } |
494 | 535 if (!_isServiceMap(map)) { |
495 // Check for ill-formed responses. | 536 var exception = |
496 return _processMap(map); | 537 new MalformedResponseRpcException( |
497 }).catchError((error) { | 538 "Response is missing the 'type' field", map); |
498 | 539 return new Future.error(exception); |
499 // ServiceError, forward to VM's ServiceError stream. | 540 } |
500 errors.add(error); | 541 return new Future.value(map); |
501 return new Future.error(error); | 542 }).catchError((e) { |
502 }, test: (e) => e is ServiceError).catchError((exception) { | 543 // Errors pass through. |
503 | 544 return new Future.error(e); |
504 // ServiceException, forward to VM's ServiceException stream. | 545 }); |
505 exceptions.add(exception); | |
506 return new Future.error(exception); | |
507 }, test: (e) => e is ServiceException); | |
508 } | 546 } |
509 | 547 |
510 Future<ServiceObject> invokeRpc(String method, Map params) { | 548 Future<ServiceObject> invokeRpc(String method, Map params) { |
511 return invokeRpcNoUpgrade(method, params).then((ObservableMap response) { | 549 return invokeRpcNoUpgrade(method, params).then((ObservableMap response) { |
512 var obj = new ServiceObject._fromMap(this, response); | 550 var obj = new ServiceObject._fromMap(this, response); |
513 if ((obj != null) && obj.canCache) { | 551 if ((obj != null) && obj.canCache) { |
514 String objId = obj.id; | 552 String objId = obj.id; |
515 _cache.putIfAbsent(objId, () => obj); | 553 _cache.putIfAbsent(objId, () => obj); |
516 } | 554 } |
517 return obj; | 555 return obj; |
(...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
613 Future get onConnect { | 651 Future get onConnect { |
614 if (_onConnect != null) { | 652 if (_onConnect != null) { |
615 return _onConnect; | 653 return _onConnect; |
616 } | 654 } |
617 _onConnect = new Future.value(this); | 655 _onConnect = new Future.value(this); |
618 return _onConnect; | 656 return _onConnect; |
619 } | 657 } |
620 // Only complete when requested. | 658 // Only complete when requested. |
621 Completer _onDisconnect = new Completer(); | 659 Completer _onDisconnect = new Completer(); |
622 Future get onDisconnect => _onDisconnect.future; | 660 Future get onDisconnect => _onDisconnect.future; |
| 661 bool get isDisconnected => _onDisconnect.isCompleted; |
623 | 662 |
624 Future<Map> invokeRpcRaw(String method, Map params) { | 663 Future<Map> invokeRpcRaw(String method, Map params) { |
625 if (params.isEmpty) { | 664 if (params.isEmpty) { |
626 params = null; | 665 params = null; |
627 } | 666 } |
628 var key = _canonicalizeUri(new Uri(path: method, queryParameters: params)); | 667 var key = _canonicalizeUri(new Uri(path: method, queryParameters: params)); |
629 var response = _responses[key]; | 668 var response = _responses[key]; |
630 if (response == null) { | 669 if (response == null) { |
631 return new Future.error({ | 670 return new Future.error(new FakeVMRpcException( |
632 'type': 'ServiceException', | 671 "Unable to find key '${key}' in cached response set")); |
633 'kind': 'NotContainedInResponses', | |
634 'key': key | |
635 }); | |
636 } | 672 } |
637 return new Future.value(response); | 673 return new Future.value(response); |
638 } | 674 } |
639 } | 675 } |
640 | 676 |
641 | 677 |
642 /// Snapshot in time of tag counters. | 678 /// Snapshot in time of tag counters. |
643 class TagProfileSnapshot { | 679 class TagProfileSnapshot { |
644 final double seconds; | 680 final double seconds; |
645 final List<int> counters; | 681 final List<int> counters; |
(...skipping 456 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1102 // Ignore GC events for now. | 1138 // Ignore GC events for now. |
1103 break; | 1139 break; |
1104 | 1140 |
1105 default: | 1141 default: |
1106 // Log unrecognized events. | 1142 // Log unrecognized events. |
1107 Logger.root.severe('Unrecognized event: $event'); | 1143 Logger.root.severe('Unrecognized event: $event'); |
1108 break; | 1144 break; |
1109 } | 1145 } |
1110 } | 1146 } |
1111 | 1147 |
1112 Future<ServiceObject> addBreakpoint(Script script, int line) { | 1148 Future<ServiceObject> addBreakpoint(Script script, int line) async { |
1113 // TODO(turnidge): Pass line as an int instead of a string. | 1149 // TODO(turnidge): Pass line as an int instead of a string. |
1114 Map params = { | 1150 try { |
1115 'scriptId': script.id, | 1151 Map params = { |
1116 'line': '$line', | 1152 'scriptId': script.id, |
1117 }; | 1153 'line': '$line', |
1118 return invokeRpc('addBreakpoint', params).then((result) { | 1154 }; |
1119 if (result is DartError) { | 1155 Breakpoint bpt = await invokeRpc('addBreakpoint', params); |
1120 return result; | |
1121 } | |
1122 Breakpoint bpt = result; | |
1123 if (bpt.resolved && | 1156 if (bpt.resolved && |
1124 script.loaded && | 1157 script.loaded && |
1125 script.tokenToLine(result.tokenPos) != line) { | 1158 script.tokenToLine(bpt.tokenPos) != line) { |
1126 // Unable to set a breakpoint at desired line. | 1159 // TODO(turnidge): Can this still happen? |
1127 script.lines[line - 1].possibleBpt = false; | 1160 script.getLine(line).possibleBpt = false; |
1128 } | 1161 } |
1129 return result; | 1162 return bpt; |
1130 }); | 1163 } on ServerRpcException catch(e) { |
| 1164 if (e.code == ServerRpcException.kNoBreakAtLine) { |
| 1165 // Unable to set a breakpoint at the desired line. |
| 1166 script.getLine(line).possibleBpt = false; |
| 1167 } |
| 1168 rethrow; |
| 1169 } |
1131 } | 1170 } |
1132 | 1171 |
1133 Future<ServiceObject> addBreakpointAtEntry(ServiceFunction function) { | 1172 Future<ServiceObject> addBreakpointAtEntry(ServiceFunction function) { |
1134 return invokeRpc('addBreakpointAtEntry', | 1173 return invokeRpc('addBreakpointAtEntry', |
1135 { 'functionId': function.id }); | 1174 { 'functionId': function.id }); |
1136 } | 1175 } |
1137 | 1176 |
1138 Future removeBreakpoint(Breakpoint bpt) { | 1177 Future removeBreakpoint(Breakpoint bpt) { |
1139 return invokeRpc('removeBreakpoint', | 1178 return invokeRpc('removeBreakpoint', |
1140 { 'breakpointId': bpt.id }); | 1179 { 'breakpointId': bpt.id }); |
1141 } | 1180 } |
1142 | 1181 |
1143 Future pause() { | 1182 Future pause() { |
1144 return invokeRpc('pause', {}).then((result) { | 1183 return invokeRpc('pause', {}); |
1145 if (result is DartError) { | |
1146 // TODO(turnidge): Handle this more gracefully. | |
1147 Logger.root.severe(result.message); | |
1148 } | |
1149 return result; | |
1150 }); | |
1151 } | 1184 } |
1152 | 1185 |
1153 Future resume() { | 1186 Future resume() { |
1154 return invokeRpc('resume', {}).then((result) { | 1187 return invokeRpc('resume', {}); |
1155 if (result is DartError) { | |
1156 // TODO(turnidge): Handle this more gracefully. | |
1157 Logger.root.severe(result.message); | |
1158 } | |
1159 return result; | |
1160 }); | |
1161 } | 1188 } |
1162 | 1189 |
1163 Future stepInto() { | 1190 Future stepInto() { |
1164 return invokeRpc('resume', {'step': 'into'}).then((result) { | 1191 return invokeRpc('resume', {'step': 'into'}); |
1165 if (result is DartError) { | |
1166 // TODO(turnidge): Handle this more gracefully. | |
1167 Logger.root.severe(result.message); | |
1168 } | |
1169 return result; | |
1170 }); | |
1171 } | 1192 } |
1172 | 1193 |
1173 Future stepOver() { | 1194 Future stepOver() { |
1174 return invokeRpc('resume', {'step': 'over'}).then((result) { | 1195 return invokeRpc('resume', {'step': 'over'}); |
1175 if (result is DartError) { | |
1176 // TODO(turnidge): Handle this more gracefully. | |
1177 Logger.root.severe(result.message); | |
1178 } | |
1179 return result; | |
1180 }); | |
1181 } | 1196 } |
1182 | 1197 |
1183 Future stepOut() { | 1198 Future stepOut() { |
1184 return invokeRpc('resume', {'step': 'out'}).then((result) { | 1199 return invokeRpc('resume', {'step': 'out'}); |
1185 if (result is DartError) { | |
1186 // TODO(turnidge): Handle this more gracefully. | |
1187 Logger.root.severe(result.message); | |
1188 } | |
1189 return result; | |
1190 }); | |
1191 } | 1200 } |
1192 | 1201 |
1193 Future setName(String newName) { | 1202 Future setName(String newName) { |
1194 Map params = { | 1203 return invokeRpc('setName', {'name': newName}); |
1195 'name': newName, | |
1196 }; | |
1197 return invokeRpc('setName', params); | |
1198 } | 1204 } |
1199 | 1205 |
1200 Future<ServiceMap> getStack() { | 1206 Future<ServiceMap> getStack() { |
1201 return invokeRpc('getStack', {}).then((result) { | 1207 return invokeRpc('getStack', {}); |
1202 if (result is DartError) { | |
1203 // TODO(turnidge): Handle this more gracefully. | |
1204 Logger.root.severe(result.message); | |
1205 } | |
1206 return result; | |
1207 }); | |
1208 } | 1208 } |
1209 | 1209 |
1210 Future<ServiceObject> eval(ServiceObject target, | 1210 Future<ServiceObject> eval(ServiceObject target, |
1211 String expression) { | 1211 String expression) { |
1212 Map params = { | 1212 Map params = { |
1213 'targetId': target.id, | 1213 'targetId': target.id, |
1214 'expression': expression, | 1214 'expression': expression, |
1215 }; | 1215 }; |
1216 return invokeRpc('eval', params); | 1216 return invokeRpc('eval', params); |
1217 } | 1217 } |
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1275 new ObservableMap<String, ServiceMetric>(); | 1275 new ObservableMap<String, ServiceMetric>(); |
1276 | 1276 |
1277 final ObservableMap<String, ServiceMetric> nativeMetrics = | 1277 final ObservableMap<String, ServiceMetric> nativeMetrics = |
1278 new ObservableMap<String, ServiceMetric>(); | 1278 new ObservableMap<String, ServiceMetric>(); |
1279 | 1279 |
1280 Future<ObservableMap<String, ServiceMetric>> _refreshMetrics( | 1280 Future<ObservableMap<String, ServiceMetric>> _refreshMetrics( |
1281 String metricType, | 1281 String metricType, |
1282 ObservableMap<String, ServiceMetric> metricsMap) { | 1282 ObservableMap<String, ServiceMetric> metricsMap) { |
1283 return invokeRpc('getIsolateMetricList', | 1283 return invokeRpc('getIsolateMetricList', |
1284 { 'type': metricType }).then((result) { | 1284 { 'type': metricType }).then((result) { |
1285 if (result is DartError) { | |
1286 // TODO(turnidge): Handle this more gracefully. | |
1287 Logger.root.severe(result.message); | |
1288 return null; | |
1289 } | |
1290 // Clear metrics map. | 1285 // Clear metrics map. |
1291 metricsMap.clear(); | 1286 metricsMap.clear(); |
1292 // Repopulate metrics map. | 1287 // Repopulate metrics map. |
1293 var metrics = result['metrics']; | 1288 var metrics = result['metrics']; |
1294 for (var metric in metrics) { | 1289 for (var metric in metrics) { |
1295 metricsMap[metric.id] = metric; | 1290 metricsMap[metric.id] = metric; |
1296 } | 1291 } |
1297 return metricsMap; | 1292 return metricsMap; |
1298 }); | 1293 }); |
1299 } | 1294 } |
(...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1390 message = map['message']; | 1385 message = map['message']; |
1391 exception = new ServiceObject._fromMap(owner, map['exception']); | 1386 exception = new ServiceObject._fromMap(owner, map['exception']); |
1392 stacktrace = new ServiceObject._fromMap(owner, map['stacktrace']); | 1387 stacktrace = new ServiceObject._fromMap(owner, map['stacktrace']); |
1393 name = 'DartError $kind'; | 1388 name = 'DartError $kind'; |
1394 vmName = name; | 1389 vmName = name; |
1395 } | 1390 } |
1396 | 1391 |
1397 String toString() => 'DartError($message)'; | 1392 String toString() => 'DartError($message)'; |
1398 } | 1393 } |
1399 | 1394 |
1400 /// A [ServiceError] is an error that was triggered in the service | |
1401 /// server or client. Errors are prorammer mistakes that could have | |
1402 /// been prevented, for example, requesting a non-existant path over the | |
1403 /// service. | |
1404 class ServiceError extends ServiceObject { | |
1405 ServiceError._empty(ServiceObjectOwner owner) : super._empty(owner); | |
1406 | |
1407 @observable String kind; | |
1408 @observable String message; | |
1409 | |
1410 void _update(ObservableMap map, bool mapIsRef) { | |
1411 _loaded = true; | |
1412 kind = map['kind']; | |
1413 message = map['message']; | |
1414 name = 'ServiceError $kind'; | |
1415 vmName = name; | |
1416 } | |
1417 | |
1418 String toString() => 'ServiceError($message)'; | |
1419 } | |
1420 | |
1421 /// A [ServiceException] is an exception that was triggered in the service | |
1422 /// server or client. Exceptions are events that should be handled, | |
1423 /// for example, an isolate went away or the connection to the VM was lost. | |
1424 class ServiceException extends ServiceObject { | |
1425 ServiceException._empty(ServiceObject owner) : super._empty(owner); | |
1426 | |
1427 @observable String kind; | |
1428 @observable String message; | |
1429 @observable dynamic response; | |
1430 | |
1431 void _update(ObservableMap map, bool mapIsRef) { | |
1432 kind = map['kind']; | |
1433 message = map['message']; | |
1434 response = map['response']; | |
1435 name = 'ServiceException $kind'; | |
1436 vmName = name; | |
1437 } | |
1438 | |
1439 String toString() => 'ServiceException($message)'; | |
1440 } | |
1441 | |
1442 /// A [ServiceEvent] is an asynchronous event notification from the vm. | 1395 /// A [ServiceEvent] is an asynchronous event notification from the vm. |
1443 class ServiceEvent extends ServiceObject { | 1396 class ServiceEvent extends ServiceObject { |
1444 /// The possible 'eventType' values. | 1397 /// The possible 'eventType' values. |
1445 static const kIsolateStart = 'IsolateStart'; | 1398 static const kIsolateStart = 'IsolateStart'; |
1446 static const kIsolateExit = 'IsolateExit'; | 1399 static const kIsolateExit = 'IsolateExit'; |
1447 static const kIsolateUpdate = 'IsolateUpdate'; | 1400 static const kIsolateUpdate = 'IsolateUpdate'; |
1448 static const kPauseStart = 'PauseStart'; | 1401 static const kPauseStart = 'PauseStart'; |
1449 static const kPauseExit = 'PauseExit'; | 1402 static const kPauseExit = 'PauseExit'; |
1450 static const kPauseBreakpoint = 'PauseBreakpoint'; | 1403 static const kPauseBreakpoint = 'PauseBreakpoint'; |
1451 static const kPauseInterrupted = 'PauseInterrupted'; | 1404 static const kPauseInterrupted = 'PauseInterrupted'; |
(...skipping 224 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1676 @observable int tokenPos; | 1629 @observable int tokenPos; |
1677 @observable int endTokenPos; | 1630 @observable int endTokenPos; |
1678 | 1631 |
1679 @observable ServiceMap error; | 1632 @observable ServiceMap error; |
1680 @observable int vmCid; | 1633 @observable int vmCid; |
1681 | 1634 |
1682 final Allocations newSpace = new Allocations(); | 1635 final Allocations newSpace = new Allocations(); |
1683 final Allocations oldSpace = new Allocations(); | 1636 final Allocations oldSpace = new Allocations(); |
1684 final AllocationCount promotedByLastNewGC = new AllocationCount(); | 1637 final AllocationCount promotedByLastNewGC = new AllocationCount(); |
1685 | 1638 |
1686 bool get hasNoAllocations => newSpace.empty && oldSpace.empty; | 1639 @observable bool get hasNoAllocations => newSpace.empty && oldSpace.empty; |
1687 | 1640 |
1688 @reflectable final fields = new ObservableList<Field>(); | 1641 @reflectable final fields = new ObservableList<Field>(); |
1689 @reflectable final functions = new ObservableList<ServiceFunction>(); | 1642 @reflectable final functions = new ObservableList<ServiceFunction>(); |
1690 | 1643 |
1691 @observable Class superclass; | 1644 @observable Class superclass; |
1692 @reflectable final interfaces = new ObservableList<Instance>(); | 1645 @reflectable final interfaces = new ObservableList<Instance>(); |
1693 @reflectable final subclasses = new ObservableList<Class>(); | 1646 @reflectable final subclasses = new ObservableList<Class>(); |
1694 | 1647 |
1695 bool get canCache => true; | 1648 bool get canCache => true; |
1696 bool get immutable => false; | 1649 bool get immutable => false; |
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1752 // Work-around Object not tracking its subclasses in the VM. | 1705 // Work-around Object not tracking its subclasses in the VM. |
1753 if (superclass != null && superclass.name == "Object") { | 1706 if (superclass != null && superclass.name == "Object") { |
1754 superclass._addSubclass(this); | 1707 superclass._addSubclass(this); |
1755 } | 1708 } |
1756 error = map['error']; | 1709 error = map['error']; |
1757 | 1710 |
1758 var allocationStats = map['allocationStats']; | 1711 var allocationStats = map['allocationStats']; |
1759 if (allocationStats != null) { | 1712 if (allocationStats != null) { |
1760 newSpace.update(allocationStats['new']); | 1713 newSpace.update(allocationStats['new']); |
1761 oldSpace.update(allocationStats['old']); | 1714 oldSpace.update(allocationStats['old']); |
| 1715 notifyPropertyChange(#hasNoAllocations, 0, 1); |
1762 promotedByLastNewGC.instances = allocationStats['promotedInstances']; | 1716 promotedByLastNewGC.instances = allocationStats['promotedInstances']; |
1763 promotedByLastNewGC.bytes = allocationStats['promotedBytes']; | 1717 promotedByLastNewGC.bytes = allocationStats['promotedBytes']; |
1764 } | 1718 } |
1765 } | 1719 } |
1766 | 1720 |
1767 void _addSubclass(Class subclass) { | 1721 void _addSubclass(Class subclass) { |
1768 if (subclasses.contains(subclass)) { | 1722 if (subclasses.contains(subclass)) { |
1769 return; | 1723 return; |
1770 } | 1724 } |
1771 subclasses.add(subclass); | 1725 subclasses.add(subclass); |
(...skipping 415 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2187 @observable Library library; | 2141 @observable Library library; |
2188 bool get canCache => true; | 2142 bool get canCache => true; |
2189 bool get immutable => true; | 2143 bool get immutable => true; |
2190 | 2144 |
2191 String _shortUrl; | 2145 String _shortUrl; |
2192 String _url; | 2146 String _url; |
2193 | 2147 |
2194 Script._empty(ServiceObjectOwner owner) : super._empty(owner); | 2148 Script._empty(ServiceObjectOwner owner) : super._empty(owner); |
2195 | 2149 |
2196 ScriptLine getLine(int line) { | 2150 ScriptLine getLine(int line) { |
| 2151 assert(_loaded); |
2197 assert(line >= 1); | 2152 assert(line >= 1); |
2198 return lines[line - lineOffset - 1]; | 2153 return lines[line - lineOffset - 1]; |
2199 } | 2154 } |
2200 | 2155 |
2201 /// This function maps a token position to a line number. | 2156 /// This function maps a token position to a line number. |
2202 int tokenToLine(int token) => _tokenToLine[token]; | 2157 int tokenToLine(int token) => _tokenToLine[token]; |
2203 Map _tokenToLine = {}; | 2158 Map _tokenToLine = {}; |
2204 | 2159 |
2205 /// This function maps a token position to a column number. | 2160 /// This function maps a token position to a column number. |
2206 int tokenToCol(int token) => _tokenToCol[token]; | 2161 int tokenToCol(int token) => _tokenToCol[token]; |
(...skipping 326 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2533 return Native; | 2488 return Native; |
2534 } else if (s == 'Dart') { | 2489 } else if (s == 'Dart') { |
2535 return Dart; | 2490 return Dart; |
2536 } else if (s == 'Collected') { | 2491 } else if (s == 'Collected') { |
2537 return Collected; | 2492 return Collected; |
2538 } else if (s == 'Tag') { | 2493 } else if (s == 'Tag') { |
2539 return Tag; | 2494 return Tag; |
2540 } else if (s == 'Stub') { | 2495 } else if (s == 'Stub') { |
2541 return Stub; | 2496 return Stub; |
2542 } | 2497 } |
2543 Logger.root.severe('Unrecognized code kind: $s'); | 2498 Logger.root.severe("Unrecognized code kind: '$s'"); |
2544 throw new FallThroughError(); | 2499 throw new FallThroughError(); |
2545 } | 2500 } |
2546 static const Collected = const CodeKind._internal('Collected'); | 2501 static const Collected = const CodeKind._internal('Collected'); |
2547 static const Dart = const CodeKind._internal('Dart'); | 2502 static const Dart = const CodeKind._internal('Dart'); |
2548 static const Native = const CodeKind._internal('Native'); | 2503 static const Native = const CodeKind._internal('Native'); |
2549 static const Stub = const CodeKind._internal('Stub'); | 2504 static const Stub = const CodeKind._internal('Stub'); |
2550 static const Tag = const CodeKind._internal('Tag'); | 2505 static const Tag = const CodeKind._internal('Tag'); |
2551 } | 2506 } |
2552 | 2507 |
2553 class CodeInlineInterval { | 2508 class CodeInlineInterval { |
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2607 } | 2562 } |
2608 // Load the script and then update descriptors. | 2563 // Load the script and then update descriptors. |
2609 script.load().then(_updateDescriptors); | 2564 script.load().then(_updateDescriptors); |
2610 }); | 2565 }); |
2611 return; | 2566 return; |
2612 } | 2567 } |
2613 // Load the script and then update descriptors. | 2568 // Load the script and then update descriptors. |
2614 function.script.load().then(_updateDescriptors); | 2569 function.script.load().then(_updateDescriptors); |
2615 } | 2570 } |
2616 | 2571 |
2617 /// Reload [this]. Returns a future which completes to [this] or | 2572 /// Reload [this]. Returns a future which completes to [this] or an |
2618 /// a [ServiceError]. | 2573 /// exception. |
2619 Future<ServiceObject> reload() { | 2574 Future<ServiceObject> reload() { |
2620 assert(kind != null); | 2575 assert(kind != null); |
2621 if (isDartCode) { | 2576 if (isDartCode) { |
2622 // We only reload Dart code. | 2577 // We only reload Dart code. |
2623 return super.reload(); | 2578 return super.reload(); |
2624 } | 2579 } |
2625 return new Future.value(this); | 2580 return new Future.value(this); |
2626 } | 2581 } |
2627 | 2582 |
2628 void _update(ObservableMap m, bool mapIsRef) { | 2583 void _update(ObservableMap m, bool mapIsRef) { |
(...skipping 372 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3001 var v = list[i]; | 2956 var v = list[i]; |
3002 if ((v is ObservableMap) && _isServiceMap(v)) { | 2957 if ((v is ObservableMap) && _isServiceMap(v)) { |
3003 list[i] = owner.getFromMap(v); | 2958 list[i] = owner.getFromMap(v); |
3004 } else if (v is ObservableList) { | 2959 } else if (v is ObservableList) { |
3005 _upgradeObservableList(v, owner); | 2960 _upgradeObservableList(v, owner); |
3006 } else if (v is ObservableMap) { | 2961 } else if (v is ObservableMap) { |
3007 _upgradeObservableMap(v, owner); | 2962 _upgradeObservableMap(v, owner); |
3008 } | 2963 } |
3009 } | 2964 } |
3010 } | 2965 } |
OLD | NEW |