| Index: runtime/observatory/lib/src/service/object.dart
|
| diff --git a/runtime/observatory/lib/src/service/object.dart b/runtime/observatory/lib/src/service/object.dart
|
| index bd76e67d0caa9d24a4791ee05345935b0b0feb5e..78b67659cb2d5cb5c10f6de89740e658d846127e 100644
|
| --- a/runtime/observatory/lib/src/service/object.dart
|
| +++ b/runtime/observatory/lib/src/service/object.dart
|
| @@ -1577,92 +1577,12 @@ class Isolate extends ServiceObjectOwner {
|
| return invokeRpc('resume', {'step': 'Over'});
|
| }
|
|
|
| - Future stepOut() {
|
| - return invokeRpc('resume', {'step': 'Out'});
|
| + Future stepOverAsyncSuspension() {
|
| + return invokeRpc('resume', {'step': 'OverAsyncSuspension'});
|
| }
|
|
|
| -
|
| - static const int kFirstResume = 0;
|
| - static const int kSecondResume = 1;
|
| - /// result[kFirstResume] completes after the inital resume. The UI should
|
| - /// wait on this future because some other breakpoint may be hit before the
|
| - /// async continuation.
|
| - /// result[kSecondResume] completes after the second resume. Tests should
|
| - /// wait on this future to avoid confusing the pause event at the
|
| - /// state-machine switch with the pause event after the state-machine switch.
|
| - Future<List<Future>> asyncStepOver() async {
|
| - final Completer firstResume = new Completer();
|
| - final Completer secondResume = new Completer();
|
| - final List<Future> result = [firstResume.future, secondResume.future];
|
| - StreamSubscription subscription;
|
| -
|
| - // Inner error handling function.
|
| - handleError(error) {
|
| - if (subscription != null) {
|
| - subscription.cancel();
|
| - subscription = null;
|
| - }
|
| - firstResume.completeError(error);
|
| - secondResume.completeError(error);
|
| - }
|
| -
|
| - if ((pauseEvent == null) ||
|
| - (pauseEvent.kind != ServiceEvent.kPauseBreakpoint) ||
|
| - (pauseEvent.asyncContinuation == null)) {
|
| - handleError(new Exception("No async continuation available"));
|
| - } else {
|
| - Instance continuation = pauseEvent.asyncContinuation;
|
| - assert(continuation.isClosure);
|
| -
|
| - // Add breakpoint at continuation.
|
| - Breakpoint continuationBpt;
|
| - try {
|
| - continuationBpt = await addBreakOnActivation(continuation);
|
| - } catch (e) {
|
| - handleError(e);
|
| - return result;
|
| - }
|
| -
|
| - // Subscribe to the debugger event stream.
|
| - Stream stream;
|
| - try {
|
| - stream = await vm.getEventStream(VM.kDebugStream);
|
| - } catch (e) {
|
| - handleError(e);
|
| - return result;
|
| - }
|
| -
|
| - Completer onResume = firstResume;
|
| - subscription = stream.listen((ServiceEvent event) async {
|
| - if ((event.kind == ServiceEvent.kPauseBreakpoint) &&
|
| - (event.breakpoint == continuationBpt)) {
|
| - // We are stopped before state-machine dispatch:
|
| - // 1) Remove the continuation breakpoint.
|
| - // 2) step over.
|
| - // reach user code.
|
| - await removeBreakpoint(continuationBpt);
|
| - onResume = secondResume;
|
| - stepOver().catchError(handleError);
|
| - } else if (event.kind == ServiceEvent.kResume) {
|
| - // We've resumed.
|
| - if (onResume == secondResume) {
|
| - // This is our second resume, cancel our subscription to the debug
|
| - // stream.
|
| - subscription.cancel();
|
| - subscription = null;
|
| - }
|
| - // Complete onResume and clear it.
|
| - if (onResume != null) {
|
| - onResume.complete(this);
|
| - onResume = null;
|
| - }
|
| - }
|
| - });
|
| -
|
| - // Call resume, which will eventually cause us to hit continuationBpt.
|
| - resume().catchError(handleError);
|
| - }
|
| - return result;
|
| + Future stepOut() {
|
| + return invokeRpc('resume', {'step': 'Out'});
|
| }
|
|
|
| Future setName(String newName) {
|
| @@ -1914,8 +1834,7 @@ class ServiceEvent extends ServiceObject {
|
| @observable Frame topFrame;
|
| @observable String extensionRPC;
|
| @observable Instance exception;
|
| - @observable Instance asyncContinuation;
|
| - @observable bool atAsyncJump;
|
| + @observable bool atAsyncSuspension;
|
| @observable ServiceObject inspectee;
|
| @observable ByteData data;
|
| @observable int count;
|
| @@ -1964,12 +1883,7 @@ class ServiceEvent extends ServiceObject {
|
| if (map['exception'] != null) {
|
| exception = map['exception'];
|
| }
|
| - if (map['_asyncContinuation'] != null) {
|
| - asyncContinuation = map['_asyncContinuation'];
|
| - atAsyncJump = map['_atAsyncJump'];
|
| - } else {
|
| - atAsyncJump = false;
|
| - }
|
| + atAsyncSuspension = map['atAsyncSuspension'] != null;
|
| if (map['inspectee'] != null) {
|
| inspectee = map['inspectee'];
|
| }
|
| @@ -2040,6 +1954,10 @@ class Breakpoint extends ServiceObject {
|
| // The breakpoint has been assigned to a final source location.
|
| @observable bool resolved;
|
|
|
| + // The breakpoint was synthetically created as part of an
|
| + // 'OverAsyncContinuation' resume request.
|
| + @observable bool isSyntheticAsyncContinuation;
|
| +
|
| void _update(ObservableMap map, bool mapIsRef) {
|
| _loaded = true;
|
| _upgradeCollection(map, owner);
|
| @@ -2066,6 +1984,8 @@ class Breakpoint extends ServiceObject {
|
| newScript._addBreakpoint(this);
|
| }
|
|
|
| + isSyntheticAsyncContinuation = map['isSyntheticAsyncContinuation'] != null;
|
| +
|
| assert(resolved || location is UnresolvedSourceLocation);
|
| }
|
|
|
| @@ -2081,7 +2001,11 @@ class Breakpoint extends ServiceObject {
|
|
|
| String toString() {
|
| if (number != null) {
|
| - return 'Breakpoint ${number} at ${location})';
|
| + if (isSyntheticAsyncContinuation) {
|
| + return 'Synthetic Async Continuation Breakpoint ${number}';
|
| + } else {
|
| + return 'Breakpoint ${number} at ${location}';
|
| + }
|
| } else {
|
| return 'Uninitialized breakpoint';
|
| }
|
|
|