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): Checking 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; |
518 }); | 556 }); |
519 } | 557 } |
520 | 558 |
521 Future<ObservableMap> _fetchDirect() { | 559 Future<ObservableMap> _fetchDirect() { |
| 560 print("FETCH DIRECT VM"); |
522 return invokeRpcNoUpgrade('getVM', {}); | 561 return invokeRpcNoUpgrade('getVM', {}); |
523 } | 562 } |
524 | 563 |
525 Future<ServiceObject> getFlagList() { | 564 Future<ServiceObject> getFlagList() { |
526 return invokeRpc('getFlagList', {}); | 565 return invokeRpc('getFlagList', {}); |
527 } | 566 } |
528 | 567 |
529 /// Force the VM to disconnect. | 568 /// Force the VM to disconnect. |
530 void disconnect(); | 569 void disconnect(); |
531 /// Completes when the VM first connects. | 570 /// Completes when the VM first connects. |
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
610 Future get onConnect { | 649 Future get onConnect { |
611 if (_onConnect != null) { | 650 if (_onConnect != null) { |
612 return _onConnect; | 651 return _onConnect; |
613 } | 652 } |
614 _onConnect = new Future.value(this); | 653 _onConnect = new Future.value(this); |
615 return _onConnect; | 654 return _onConnect; |
616 } | 655 } |
617 // Only complete when requested. | 656 // Only complete when requested. |
618 Completer _onDisconnect = new Completer(); | 657 Completer _onDisconnect = new Completer(); |
619 Future get onDisconnect => _onDisconnect.future; | 658 Future get onDisconnect => _onDisconnect.future; |
| 659 bool get isDisconnected => _onDisconnect.isCompleted; |
620 | 660 |
621 Future<Map> invokeRpcRaw(String method, Map params) { | 661 Future<Map> invokeRpcRaw(String method, Map params) { |
622 if (params.isEmpty) { | 662 if (params.isEmpty) { |
623 params = null; | 663 params = null; |
624 } | 664 } |
625 var key = _canonicalizeUri(new Uri(path: method, queryParameters: params)); | 665 var key = _canonicalizeUri(new Uri(path: method, queryParameters: params)); |
626 var response = _responses[key]; | 666 var response = _responses[key]; |
627 if (response == null) { | 667 if (response == null) { |
628 return new Future.error({ | 668 return new Future.error(new FakeVMRpcException( |
629 'type': 'ServiceException', | 669 "Unable to find key '${key}' in cached response set")); |
630 'kind': 'NotContainedInResponses', | |
631 'key': key | |
632 }); | |
633 } | 670 } |
634 return new Future.value(response); | 671 return new Future.value(response); |
635 } | 672 } |
636 } | 673 } |
637 | 674 |
638 | 675 |
639 /// Snapshot in time of tag counters. | 676 /// Snapshot in time of tag counters. |
640 class TagProfileSnapshot { | 677 class TagProfileSnapshot { |
641 final double seconds; | 678 final double seconds; |
642 final List<int> counters; | 679 final List<int> counters; |
(...skipping 456 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1099 // Ignore GC events for now. | 1136 // Ignore GC events for now. |
1100 break; | 1137 break; |
1101 | 1138 |
1102 default: | 1139 default: |
1103 // Log unrecognized events. | 1140 // Log unrecognized events. |
1104 Logger.root.severe('Unrecognized event: $event'); | 1141 Logger.root.severe('Unrecognized event: $event'); |
1105 break; | 1142 break; |
1106 } | 1143 } |
1107 } | 1144 } |
1108 | 1145 |
1109 Future<ServiceObject> addBreakpoint(Script script, int line) { | 1146 Future<ServiceObject> addBreakpoint(Script script, int line) async { |
1110 // TODO(turnidge): Pass line as an int instead of a string. | 1147 // TODO(turnidge): Pass line as an int instead of a string. |
1111 Map params = { | 1148 try { |
1112 'scriptId': script.id, | 1149 Map params = { |
1113 'line': '$line', | 1150 'scriptId': script.id, |
1114 }; | 1151 'line': '$line', |
1115 return invokeRpc('addBreakpoint', params).then((result) { | 1152 }; |
1116 if (result is DartError) { | 1153 Breakpoint bpt = await invokeRpc('addBreakpoint', params); |
1117 return result; | |
1118 } | |
1119 Breakpoint bpt = result; | |
1120 if (bpt.resolved && | 1154 if (bpt.resolved && |
1121 script.loaded && | 1155 script.loaded && |
1122 script.tokenToLine(result.tokenPos) != line) { | 1156 script.tokenToLine(bpt.tokenPos) != line) { |
1123 // Unable to set a breakpoint at desired line. | 1157 // TODO(turnidge): Can this still happen? |
1124 script.lines[line - 1].possibleBpt = false; | 1158 script.getLine(line).possibleBpt = false; |
1125 } | 1159 } |
1126 return result; | 1160 return bpt; |
1127 }); | 1161 } on ServerRpcException catch(e) { |
| 1162 if (e.code == ServerRpcException.kNoBreakAtLine) { |
| 1163 // Unable to set a breakpoint at the desired line. |
| 1164 script.getLine(line).possibleBpt = false; |
| 1165 } |
| 1166 rethrow; |
| 1167 } |
1128 } | 1168 } |
1129 | 1169 |
1130 Future<ServiceObject> addBreakpointAtEntry(ServiceFunction function) { | 1170 Future<ServiceObject> addBreakpointAtEntry(ServiceFunction function) { |
1131 return invokeRpc('addBreakpointAtEntry', | 1171 return invokeRpc('addBreakpointAtEntry', |
1132 { 'functionId': function.id }); | 1172 { 'functionId': function.id }); |
1133 } | 1173 } |
1134 | 1174 |
1135 Future removeBreakpoint(Breakpoint bpt) { | 1175 Future removeBreakpoint(Breakpoint bpt) { |
1136 return invokeRpc('removeBreakpoint', | 1176 return invokeRpc('removeBreakpoint', |
1137 { 'breakpointId': bpt.id }); | 1177 { 'breakpointId': bpt.id }); |
1138 } | 1178 } |
1139 | 1179 |
1140 Future pause() { | 1180 Future pause() { |
1141 return invokeRpc('pause', {}).then((result) { | 1181 return invokeRpc('pause', {}); |
1142 if (result is DartError) { | |
1143 // TODO(turnidge): Handle this more gracefully. | |
1144 Logger.root.severe(result.message); | |
1145 } | |
1146 return result; | |
1147 }); | |
1148 } | 1182 } |
1149 | 1183 |
1150 Future resume() { | 1184 Future resume() { |
1151 return invokeRpc('resume', {}).then((result) { | 1185 return invokeRpc('resume', {}); |
1152 if (result is DartError) { | |
1153 // TODO(turnidge): Handle this more gracefully. | |
1154 Logger.root.severe(result.message); | |
1155 } | |
1156 return result; | |
1157 }); | |
1158 } | 1186 } |
1159 | 1187 |
1160 Future stepInto() { | 1188 Future stepInto() { |
1161 return invokeRpc('resume', {'step': 'into'}).then((result) { | 1189 return invokeRpc('resume', {'step': 'into'}); |
1162 if (result is DartError) { | |
1163 // TODO(turnidge): Handle this more gracefully. | |
1164 Logger.root.severe(result.message); | |
1165 } | |
1166 return result; | |
1167 }); | |
1168 } | 1190 } |
1169 | 1191 |
1170 Future stepOver() { | 1192 Future stepOver() { |
1171 return invokeRpc('resume', {'step': 'over'}).then((result) { | 1193 return invokeRpc('resume', {'step': 'over'}); |
1172 if (result is DartError) { | |
1173 // TODO(turnidge): Handle this more gracefully. | |
1174 Logger.root.severe(result.message); | |
1175 } | |
1176 return result; | |
1177 }); | |
1178 } | 1194 } |
1179 | 1195 |
1180 Future stepOut() { | 1196 Future stepOut() { |
1181 return invokeRpc('resume', {'step': 'out'}).then((result) { | 1197 return invokeRpc('resume', {'step': 'out'}); |
1182 if (result is DartError) { | |
1183 // TODO(turnidge): Handle this more gracefully. | |
1184 Logger.root.severe(result.message); | |
1185 } | |
1186 return result; | |
1187 }); | |
1188 } | 1198 } |
1189 | 1199 |
1190 Future setName(String newName) { | 1200 Future setName(String newName) { |
1191 Map params = { | 1201 return invokeRpc('setName', {'name': newName}); |
1192 'name': newName, | |
1193 }; | |
1194 return invokeRpc('setName', params); | |
1195 } | 1202 } |
1196 | 1203 |
1197 Future<ServiceMap> getStack() { | 1204 Future<ServiceMap> getStack() { |
1198 return invokeRpc('getStack', {}).then((result) { | 1205 return invokeRpc('getStack', {}); |
1199 if (result is DartError) { | |
1200 // TODO(turnidge): Handle this more gracefully. | |
1201 Logger.root.severe(result.message); | |
1202 } | |
1203 return result; | |
1204 }); | |
1205 } | 1206 } |
1206 | 1207 |
1207 Future<ServiceObject> eval(ServiceObject target, | 1208 Future<ServiceObject> eval(ServiceObject target, |
1208 String expression) { | 1209 String expression) { |
1209 Map params = { | 1210 Map params = { |
1210 'targetId': target.id, | 1211 'targetId': target.id, |
1211 'expression': expression, | 1212 'expression': expression, |
1212 }; | 1213 }; |
1213 return invokeRpc('eval', params); | 1214 return invokeRpc('eval', params); |
1214 } | 1215 } |
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1272 new ObservableMap<String, ServiceMetric>(); | 1273 new ObservableMap<String, ServiceMetric>(); |
1273 | 1274 |
1274 final ObservableMap<String, ServiceMetric> nativeMetrics = | 1275 final ObservableMap<String, ServiceMetric> nativeMetrics = |
1275 new ObservableMap<String, ServiceMetric>(); | 1276 new ObservableMap<String, ServiceMetric>(); |
1276 | 1277 |
1277 Future<ObservableMap<String, ServiceMetric>> _refreshMetrics( | 1278 Future<ObservableMap<String, ServiceMetric>> _refreshMetrics( |
1278 String metricType, | 1279 String metricType, |
1279 ObservableMap<String, ServiceMetric> metricsMap) { | 1280 ObservableMap<String, ServiceMetric> metricsMap) { |
1280 return invokeRpc('getIsolateMetricList', | 1281 return invokeRpc('getIsolateMetricList', |
1281 { 'type': metricType }).then((result) { | 1282 { 'type': metricType }).then((result) { |
1282 if (result is DartError) { | |
1283 // TODO(turnidge): Handle this more gracefully. | |
1284 Logger.root.severe(result.message); | |
1285 return null; | |
1286 } | |
1287 // Clear metrics map. | 1283 // Clear metrics map. |
1288 metricsMap.clear(); | 1284 metricsMap.clear(); |
1289 // Repopulate metrics map. | 1285 // Repopulate metrics map. |
1290 var metrics = result['metrics']; | 1286 var metrics = result['metrics']; |
1291 for (var metric in metrics) { | 1287 for (var metric in metrics) { |
1292 metricsMap[metric.id] = metric; | 1288 metricsMap[metric.id] = metric; |
1293 } | 1289 } |
1294 return metricsMap; | 1290 return metricsMap; |
1295 }); | 1291 }); |
1296 } | 1292 } |
(...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1387 message = map['message']; | 1383 message = map['message']; |
1388 exception = new ServiceObject._fromMap(owner, map['exception']); | 1384 exception = new ServiceObject._fromMap(owner, map['exception']); |
1389 stacktrace = new ServiceObject._fromMap(owner, map['stacktrace']); | 1385 stacktrace = new ServiceObject._fromMap(owner, map['stacktrace']); |
1390 name = 'DartError $kind'; | 1386 name = 'DartError $kind'; |
1391 vmName = name; | 1387 vmName = name; |
1392 } | 1388 } |
1393 | 1389 |
1394 String toString() => 'DartError($message)'; | 1390 String toString() => 'DartError($message)'; |
1395 } | 1391 } |
1396 | 1392 |
1397 /// A [ServiceError] is an error that was triggered in the service | |
1398 /// server or client. Errors are prorammer mistakes that could have | |
1399 /// been prevented, for example, requesting a non-existant path over the | |
1400 /// service. | |
1401 class ServiceError extends ServiceObject { | |
1402 ServiceError._empty(ServiceObjectOwner owner) : super._empty(owner); | |
1403 | |
1404 @observable String kind; | |
1405 @observable String message; | |
1406 | |
1407 void _update(ObservableMap map, bool mapIsRef) { | |
1408 _loaded = true; | |
1409 kind = map['kind']; | |
1410 message = map['message']; | |
1411 name = 'ServiceError $kind'; | |
1412 vmName = name; | |
1413 } | |
1414 | |
1415 String toString() => 'ServiceError($message)'; | |
1416 } | |
1417 | |
1418 /// A [ServiceException] is an exception that was triggered in the service | |
1419 /// server or client. Exceptions are events that should be handled, | |
1420 /// for example, an isolate went away or the connection to the VM was lost. | |
1421 class ServiceException extends ServiceObject { | |
1422 ServiceException._empty(ServiceObject owner) : super._empty(owner); | |
1423 | |
1424 @observable String kind; | |
1425 @observable String message; | |
1426 @observable dynamic response; | |
1427 | |
1428 void _update(ObservableMap map, bool mapIsRef) { | |
1429 kind = map['kind']; | |
1430 message = map['message']; | |
1431 response = map['response']; | |
1432 name = 'ServiceException $kind'; | |
1433 vmName = name; | |
1434 } | |
1435 | |
1436 String toString() => 'ServiceException($message)'; | |
1437 } | |
1438 | |
1439 /// A [ServiceEvent] is an asynchronous event notification from the vm. | 1393 /// A [ServiceEvent] is an asynchronous event notification from the vm. |
1440 class ServiceEvent extends ServiceObject { | 1394 class ServiceEvent extends ServiceObject { |
1441 /// The possible 'eventType' values. | 1395 /// The possible 'eventType' values. |
1442 static const kIsolateStart = 'IsolateStart'; | 1396 static const kIsolateStart = 'IsolateStart'; |
1443 static const kIsolateExit = 'IsolateExit'; | 1397 static const kIsolateExit = 'IsolateExit'; |
1444 static const kIsolateUpdate = 'IsolateUpdate'; | 1398 static const kIsolateUpdate = 'IsolateUpdate'; |
1445 static const kPauseStart = 'PauseStart'; | 1399 static const kPauseStart = 'PauseStart'; |
1446 static const kPauseExit = 'PauseExit'; | 1400 static const kPauseExit = 'PauseExit'; |
1447 static const kPauseBreakpoint = 'PauseBreakpoint'; | 1401 static const kPauseBreakpoint = 'PauseBreakpoint'; |
1448 static const kPauseInterrupted = 'PauseInterrupted'; | 1402 static const kPauseInterrupted = 'PauseInterrupted'; |
(...skipping 15 matching lines...) Expand all Loading... |
1464 | 1418 |
1465 @observable String eventType; | 1419 @observable String eventType; |
1466 @observable Breakpoint breakpoint; | 1420 @observable Breakpoint breakpoint; |
1467 @observable ServiceMap topFrame; | 1421 @observable ServiceMap topFrame; |
1468 @observable ServiceMap exception; | 1422 @observable ServiceMap exception; |
1469 @observable ServiceObject inspectee; | 1423 @observable ServiceObject inspectee; |
1470 @observable ByteData data; | 1424 @observable ByteData data; |
1471 @observable int count; | 1425 @observable int count; |
1472 @observable String reason; | 1426 @observable String reason; |
1473 | 1427 |
| 1428 @observable bool get isPauseEvent { |
| 1429 return (eventType == kPauseStart || |
| 1430 eventType == kPauseExit || |
| 1431 eventType == kPauseBreakpoint || |
| 1432 eventType == kPauseInterrupted || |
| 1433 eventType == kPauseException); |
| 1434 } |
| 1435 |
1474 void _update(ObservableMap map, bool mapIsRef) { | 1436 void _update(ObservableMap map, bool mapIsRef) { |
1475 _loaded = true; | 1437 _loaded = true; |
1476 _upgradeCollection(map, owner); | 1438 _upgradeCollection(map, owner); |
1477 assert(map['isolate'] == null || owner == map['isolate']); | 1439 assert(map['isolate'] == null || owner == map['isolate']); |
1478 eventType = map['eventType']; | 1440 eventType = map['eventType']; |
| 1441 notifyPropertyChange(#isPauseEvent, 0, 1); |
1479 name = 'ServiceEvent $eventType'; | 1442 name = 'ServiceEvent $eventType'; |
1480 vmName = name; | 1443 vmName = name; |
1481 if (map['breakpoint'] != null) { | 1444 if (map['breakpoint'] != null) { |
1482 breakpoint = map['breakpoint']; | 1445 breakpoint = map['breakpoint']; |
1483 } | 1446 } |
1484 if (map['topFrame'] != null) { | 1447 if (map['topFrame'] != null) { |
1485 topFrame = map['topFrame']; | 1448 topFrame = map['topFrame']; |
1486 } | 1449 } |
1487 if (map['exception'] != null) { | 1450 if (map['exception'] != null) { |
1488 exception = map['exception']; | 1451 exception = map['exception']; |
(...skipping 184 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1673 @observable int tokenPos; | 1636 @observable int tokenPos; |
1674 @observable int endTokenPos; | 1637 @observable int endTokenPos; |
1675 | 1638 |
1676 @observable ServiceMap error; | 1639 @observable ServiceMap error; |
1677 @observable int vmCid; | 1640 @observable int vmCid; |
1678 | 1641 |
1679 final Allocations newSpace = new Allocations(); | 1642 final Allocations newSpace = new Allocations(); |
1680 final Allocations oldSpace = new Allocations(); | 1643 final Allocations oldSpace = new Allocations(); |
1681 final AllocationCount promotedByLastNewGC = new AllocationCount(); | 1644 final AllocationCount promotedByLastNewGC = new AllocationCount(); |
1682 | 1645 |
1683 bool get hasNoAllocations => newSpace.empty && oldSpace.empty; | 1646 @observable bool get hasNoAllocations => newSpace.empty && oldSpace.empty; |
1684 | 1647 |
1685 @reflectable final fields = new ObservableList<Field>(); | 1648 @reflectable final fields = new ObservableList<Field>(); |
1686 @reflectable final functions = new ObservableList<ServiceFunction>(); | 1649 @reflectable final functions = new ObservableList<ServiceFunction>(); |
1687 | 1650 |
1688 @observable Class superclass; | 1651 @observable Class superclass; |
1689 @reflectable final interfaces = new ObservableList<Instance>(); | 1652 @reflectable final interfaces = new ObservableList<Instance>(); |
1690 @reflectable final subclasses = new ObservableList<Class>(); | 1653 @reflectable final subclasses = new ObservableList<Class>(); |
1691 | 1654 |
1692 bool get canCache => true; | 1655 bool get canCache => true; |
1693 bool get immutable => false; | 1656 bool get immutable => false; |
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1749 // Work-around Object not tracking its subclasses in the VM. | 1712 // Work-around Object not tracking its subclasses in the VM. |
1750 if (superclass != null && superclass.name == "Object") { | 1713 if (superclass != null && superclass.name == "Object") { |
1751 superclass._addSubclass(this); | 1714 superclass._addSubclass(this); |
1752 } | 1715 } |
1753 error = map['error']; | 1716 error = map['error']; |
1754 | 1717 |
1755 var allocationStats = map['allocationStats']; | 1718 var allocationStats = map['allocationStats']; |
1756 if (allocationStats != null) { | 1719 if (allocationStats != null) { |
1757 newSpace.update(allocationStats['new']); | 1720 newSpace.update(allocationStats['new']); |
1758 oldSpace.update(allocationStats['old']); | 1721 oldSpace.update(allocationStats['old']); |
| 1722 notifyPropertyChange(#hasNoAllocations, 0, 1); |
1759 promotedByLastNewGC.instances = allocationStats['promotedInstances']; | 1723 promotedByLastNewGC.instances = allocationStats['promotedInstances']; |
1760 promotedByLastNewGC.bytes = allocationStats['promotedBytes']; | 1724 promotedByLastNewGC.bytes = allocationStats['promotedBytes']; |
1761 } | 1725 } |
1762 } | 1726 } |
1763 | 1727 |
1764 void _addSubclass(Class subclass) { | 1728 void _addSubclass(Class subclass) { |
1765 if (subclasses.contains(subclass)) { | 1729 if (subclasses.contains(subclass)) { |
1766 return; | 1730 return; |
1767 } | 1731 } |
1768 subclasses.add(subclass); | 1732 subclasses.add(subclass); |
(...skipping 436 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2205 @observable Library library; | 2169 @observable Library library; |
2206 bool get canCache => true; | 2170 bool get canCache => true; |
2207 bool get immutable => true; | 2171 bool get immutable => true; |
2208 | 2172 |
2209 String _shortUrl; | 2173 String _shortUrl; |
2210 String _url; | 2174 String _url; |
2211 | 2175 |
2212 Script._empty(ServiceObjectOwner owner) : super._empty(owner); | 2176 Script._empty(ServiceObjectOwner owner) : super._empty(owner); |
2213 | 2177 |
2214 ScriptLine getLine(int line) { | 2178 ScriptLine getLine(int line) { |
| 2179 assert(_loaded); |
2215 assert(line >= 1); | 2180 assert(line >= 1); |
2216 return lines[line - lineOffset - 1]; | 2181 return lines[line - lineOffset - 1]; |
2217 } | 2182 } |
2218 | 2183 |
2219 /// This function maps a token position to a line number. | 2184 /// This function maps a token position to a line number. |
2220 int tokenToLine(int token) => _tokenToLine[token]; | 2185 int tokenToLine(int token) => _tokenToLine[token]; |
2221 Map _tokenToLine = {}; | 2186 Map _tokenToLine = {}; |
2222 | 2187 |
2223 /// This function maps a token position to a column number. | 2188 /// This function maps a token position to a column number. |
2224 int tokenToCol(int token) => _tokenToCol[token]; | 2189 int tokenToCol(int token) => _tokenToCol[token]; |
(...skipping 440 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2665 return Native; | 2630 return Native; |
2666 } else if (s == 'Dart') { | 2631 } else if (s == 'Dart') { |
2667 return Dart; | 2632 return Dart; |
2668 } else if (s == 'Collected') { | 2633 } else if (s == 'Collected') { |
2669 return Collected; | 2634 return Collected; |
2670 } else if (s == 'Tag') { | 2635 } else if (s == 'Tag') { |
2671 return Tag; | 2636 return Tag; |
2672 } else if (s == 'Stub') { | 2637 } else if (s == 'Stub') { |
2673 return Stub; | 2638 return Stub; |
2674 } | 2639 } |
2675 Logger.root.severe('Unrecognized code kind: $s'); | 2640 Logger.root.severe("Unrecognized code kind: '$s'"); |
2676 throw new FallThroughError(); | 2641 throw new FallThroughError(); |
2677 } | 2642 } |
2678 static const Collected = const CodeKind._internal('Collected'); | 2643 static const Collected = const CodeKind._internal('Collected'); |
2679 static const Dart = const CodeKind._internal('Dart'); | 2644 static const Dart = const CodeKind._internal('Dart'); |
2680 static const Native = const CodeKind._internal('Native'); | 2645 static const Native = const CodeKind._internal('Native'); |
2681 static const Stub = const CodeKind._internal('Stub'); | 2646 static const Stub = const CodeKind._internal('Stub'); |
2682 static const Tag = const CodeKind._internal('Tag'); | 2647 static const Tag = const CodeKind._internal('Tag'); |
2683 } | 2648 } |
2684 | 2649 |
2685 class CodeInlineInterval { | 2650 class CodeInlineInterval { |
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2739 } | 2704 } |
2740 // Load the script and then update descriptors. | 2705 // Load the script and then update descriptors. |
2741 script.load().then(_updateDescriptors); | 2706 script.load().then(_updateDescriptors); |
2742 }); | 2707 }); |
2743 return; | 2708 return; |
2744 } | 2709 } |
2745 // Load the script and then update descriptors. | 2710 // Load the script and then update descriptors. |
2746 function.script.load().then(_updateDescriptors); | 2711 function.script.load().then(_updateDescriptors); |
2747 } | 2712 } |
2748 | 2713 |
2749 /// Reload [this]. Returns a future which completes to [this] or | 2714 /// Reload [this]. Returns a future which completes to [this] or an |
2750 /// a [ServiceError]. | 2715 /// exception. |
2751 Future<ServiceObject> reload() { | 2716 Future<ServiceObject> reload() { |
2752 assert(kind != null); | 2717 assert(kind != null); |
2753 if (isDartCode) { | 2718 if (isDartCode) { |
2754 // We only reload Dart code. | 2719 // We only reload Dart code. |
2755 return super.reload(); | 2720 return super.reload(); |
2756 } | 2721 } |
2757 return new Future.value(this); | 2722 return new Future.value(this); |
2758 } | 2723 } |
2759 | 2724 |
2760 void _update(ObservableMap m, bool mapIsRef) { | 2725 void _update(ObservableMap m, bool mapIsRef) { |
(...skipping 372 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3133 var v = list[i]; | 3098 var v = list[i]; |
3134 if ((v is ObservableMap) && _isServiceMap(v)) { | 3099 if ((v is ObservableMap) && _isServiceMap(v)) { |
3135 list[i] = owner.getFromMap(v); | 3100 list[i] = owner.getFromMap(v); |
3136 } else if (v is ObservableList) { | 3101 } else if (v is ObservableList) { |
3137 _upgradeObservableList(v, owner); | 3102 _upgradeObservableList(v, owner); |
3138 } else if (v is ObservableMap) { | 3103 } else if (v is ObservableMap) { |
3139 _upgradeObservableMap(v, owner); | 3104 _upgradeObservableMap(v, owner); |
3140 } | 3105 } |
3141 } | 3106 } |
3142 } | 3107 } |
OLD | NEW |