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'; |
} |