| 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 |