Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(420)

Side by Side Diff: runtime/observatory/lib/src/service/object.dart

Issue 1699153002: Add step OverAwait to service protocol (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Created 4 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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 // Some value smaller than the object ring, so requesting a large array 7 // Some value smaller than the object ring, so requesting a large array
8 // doesn't result in an expired ref because the elements lapped it in the 8 // doesn't result in an expired ref because the elements lapped it in the
9 // object ring. 9 // object ring.
10 const int kDefaultFieldLimit = 100; 10 const int kDefaultFieldLimit = 100;
(...skipping 1559 matching lines...) Expand 10 before | Expand all | Expand 10 after
1570 } 1570 }
1571 1571
1572 Future stepInto() { 1572 Future stepInto() {
1573 return invokeRpc('resume', {'step': 'Into'}); 1573 return invokeRpc('resume', {'step': 'Into'});
1574 } 1574 }
1575 1575
1576 Future stepOver() { 1576 Future stepOver() {
1577 return invokeRpc('resume', {'step': 'Over'}); 1577 return invokeRpc('resume', {'step': 'Over'});
1578 } 1578 }
1579 1579
1580 Future stepOverAwait() {
1581 return invokeRpc('resume', {'step': 'OverAwait'});
1582 }
1583
1580 Future stepOut() { 1584 Future stepOut() {
1581 return invokeRpc('resume', {'step': 'Out'}); 1585 return invokeRpc('resume', {'step': 'Out'});
1582 } 1586 }
1583 1587
1584 1588
1585 static const int kFirstResume = 0; 1589 static const int kUIFuture = 0;
1586 static const int kSecondResume = 1; 1590 static const int kTestFuture = 1;
1587 /// result[kFirstResume] completes after the inital resume. The UI should 1591 /// result[kUIFuture] completes after the inital resume. The UI should
1588 /// wait on this future because some other breakpoint may be hit before the 1592 /// wait on this future because some other breakpoint may be hit before the
1589 /// async continuation. 1593 /// async continuation.
1590 /// result[kSecondResume] completes after the second resume. Tests should 1594 /// result[kTestFuture] completes after the second resume. Tests should
1591 /// wait on this future to avoid confusing the pause event at the 1595 /// wait on this future to avoid confusing the pause event at the
1592 /// state-machine switch with the pause event after the state-machine switch. 1596 /// state-machine switch with the pause event after the state-machine switch.
1593 Future<List<Future>> asyncStepOver() async { 1597 Future<List<Future>> asyncStepOver() async {
1594 final Completer firstResume = new Completer(); 1598 final Completer breakpointAdded = new Completer();
1595 final Completer secondResume = new Completer(); 1599 final Completer breakpointRemoved = new Completer();
rmacnak 2016/02/16 21:21:58 It would make more sense for the tests to wait for
Cutch 2016/02/17 18:24:21 Event sequence is now: - kBreapointAdded (#1). -
1596 final List<Future> result = [firstResume.future, secondResume.future]; 1600 final List<Future> result =
1601 [breakpointAdded.future, breakpointRemoved.future];
1597 StreamSubscription subscription; 1602 StreamSubscription subscription;
1598 1603
1599 // Inner error handling function. 1604 // Cancel the subscription.
1600 handleError(error) { 1605 cancelSubscription() {
1601 if (subscription != null) { 1606 if (subscription != null) {
1602 subscription.cancel(); 1607 subscription.cancel();
1603 subscription = null; 1608 subscription = null;
1604 } 1609 }
1605 firstResume.completeError(error);
1606 secondResume.completeError(error);
1607 } 1610 }
1608 1611
1609 if ((pauseEvent == null) || 1612 // Complete futures with with error.
1610 (pauseEvent.kind != ServiceEvent.kPauseBreakpoint) || 1613 completeError(error) {
1611 (pauseEvent.asyncContinuation == null)) { 1614 if (!breakpointAdded.isCompleted) {
1612 handleError(new Exception("No async continuation available")); 1615 breakpointAdded.completeError(error);
1613 } else { 1616 }
1614 Instance continuation = pauseEvent.asyncContinuation; 1617 if (!breakpointRemoved.isCompleted) {
1615 assert(continuation.isClosure); 1618 breakpointRemoved.completeError(error);
1619 }
1620 }
1616 1621
1617 // Add breakpoint at continuation. 1622 // Subscribe to the debugger event stream.
1618 Breakpoint continuationBpt; 1623 Stream stream;
1619 try { 1624 try {
1620 continuationBpt = await addBreakOnActivation(continuation); 1625 stream = await vm.getEventStream(VM.kDebugStream);
1621 } catch (e) { 1626 } catch (e) {
1622 handleError(e); 1627 completeError(e);
1623 return result; 1628 return result;
1629 }
1630
1631 Breakpoint syntheticBreakpoint;
1632
1633 subscription = stream.listen((ServiceEvent event) async {
1634 // Synthetic breakpoint add event for this isolate.
1635 bool isAdd = (event.kind == ServiceEvent.kBreakpointAdded) &&
1636 (event.breakpoint.isSyntheticAsync) &&
1637 (event.owner == this);
1638 // Synthetic breakpoint remove event.
1639 bool isRemove = (event.kind == ServiceEvent.kBreakpointRemoved) &&
1640 (syntheticBreakpoint != null) &&
1641 (event.breakpoint == syntheticBreakpoint);
1642 if (isAdd) {
1643 syntheticBreakpoint = event.breakpoint;
1644 breakpointAdded.complete(this);
1645 } else if (isRemove) {
1646 breakpointRemoved.complete(this);
1647 // We are finished, cancel the subscription.
1648 cancelSubscription();
1624 } 1649 }
1650 });
1625 1651
1626 // Subscribe to the debugger event stream. 1652 // Issue the step OverAwait command.
1627 Stream stream; 1653 try {
1628 try { 1654 await isolate.stepOverAwait();
1629 stream = await vm.getEventStream(VM.kDebugStream); 1655 } catch (e) {
1630 } catch (e) { 1656 // This can fail when another client issued the same resume command
1631 handleError(e); 1657 // or another client has moved the isolate forward.
1632 return result; 1658 cancelSubscription();
1633 } 1659 completeError(e);
1660 }
1634 1661
1635 Completer onResume = firstResume;
1636 subscription = stream.listen((ServiceEvent event) async {
1637 if ((event.kind == ServiceEvent.kPauseBreakpoint) &&
1638 (event.breakpoint == continuationBpt)) {
1639 // We are stopped before state-machine dispatch:
1640 // 1) Remove the continuation breakpoint.
1641 // 2) step over.
1642 // reach user code.
1643 await removeBreakpoint(continuationBpt);
1644 onResume = secondResume;
1645 stepOver().catchError(handleError);
1646 } else if (event.kind == ServiceEvent.kResume) {
1647 // We've resumed.
1648 if (onResume == secondResume) {
1649 // This is our second resume, cancel our subscription to the debug
1650 // stream.
1651 subscription.cancel();
1652 subscription = null;
1653 }
1654 // Complete onResume and clear it.
1655 if (onResume != null) {
1656 onResume.complete(this);
1657 onResume = null;
1658 }
1659 }
1660 });
1661
1662 // Call resume, which will eventually cause us to hit continuationBpt.
1663 resume().catchError(handleError);
1664 }
1665 return result; 1662 return result;
1666 } 1663 }
1667 1664
1668 Future setName(String newName) { 1665 Future setName(String newName) {
1669 return invokeRpc('setName', {'name': newName}); 1666 return invokeRpc('setName', {'name': newName});
1670 } 1667 }
1671 1668
1672 Future setExceptionPauseMode(String mode) { 1669 Future setExceptionPauseMode(String mode) {
1673 return invokeRpc('setExceptionPauseMode', {'mode': mode}); 1670 return invokeRpc('setExceptionPauseMode', {'mode': mode});
1674 } 1671 }
(...skipping 233 matching lines...) Expand 10 before | Expand all | Expand 10 after
1908 kind = kConnectionClosed; 1905 kind = kConnectionClosed;
1909 } 1906 }
1910 1907
1911 @observable String kind; 1908 @observable String kind;
1912 @observable DateTime timestamp; 1909 @observable DateTime timestamp;
1913 @observable Breakpoint breakpoint; 1910 @observable Breakpoint breakpoint;
1914 @observable Frame topFrame; 1911 @observable Frame topFrame;
1915 @observable String extensionRPC; 1912 @observable String extensionRPC;
1916 @observable Instance exception; 1913 @observable Instance exception;
1917 @observable Instance asyncContinuation; 1914 @observable Instance asyncContinuation;
1918 @observable bool atAsyncJump; 1915 @observable bool atAsyncJump;
rmacnak 2016/02/16 21:21:58 Don't need atAsyncJump anymore.
Cutch 2016/02/17 18:24:21 Removed this and asyncContinuation.
1916 @observable bool atAwait;
1919 @observable ServiceObject inspectee; 1917 @observable ServiceObject inspectee;
1920 @observable ByteData data; 1918 @observable ByteData data;
1921 @observable int count; 1919 @observable int count;
1922 @observable String reason; 1920 @observable String reason;
1923 @observable String exceptions; 1921 @observable String exceptions;
1924 @observable String bytesAsString; 1922 @observable String bytesAsString;
1925 @observable Map logRecord; 1923 @observable Map logRecord;
1926 @observable String extensionKind; 1924 @observable String extensionKind;
1927 @observable Map extensionData; 1925 @observable Map extensionData;
1928 1926
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
1963 topFrame = map['topFrame']; 1961 topFrame = map['topFrame'];
1964 if (map['exception'] != null) { 1962 if (map['exception'] != null) {
1965 exception = map['exception']; 1963 exception = map['exception'];
1966 } 1964 }
1967 if (map['_asyncContinuation'] != null) { 1965 if (map['_asyncContinuation'] != null) {
1968 asyncContinuation = map['_asyncContinuation']; 1966 asyncContinuation = map['_asyncContinuation'];
1969 atAsyncJump = map['_atAsyncJump']; 1967 atAsyncJump = map['_atAsyncJump'];
1970 } else { 1968 } else {
1971 atAsyncJump = false; 1969 atAsyncJump = false;
1972 } 1970 }
1971 if (map['atAwait'] != null) {
1972 atAwait = true;
1973 } else {
1974 atAwait = false;
1975 }
1973 if (map['inspectee'] != null) { 1976 if (map['inspectee'] != null) {
1974 inspectee = map['inspectee']; 1977 inspectee = map['inspectee'];
1975 } 1978 }
1976 if (map['_data'] != null) { 1979 if (map['_data'] != null) {
1977 data = map['_data']; 1980 data = map['_data'];
1978 } 1981 }
1979 if (map['chunkIndex'] != null) { 1982 if (map['chunkIndex'] != null) {
1980 chunkIndex = map['chunkIndex']; 1983 chunkIndex = map['chunkIndex'];
1981 } 1984 }
1982 if (map['chunkCount'] != null) { 1985 if (map['chunkCount'] != null) {
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after
2033 2036
2034 // Either SourceLocation or UnresolvedSourceLocation. 2037 // Either SourceLocation or UnresolvedSourceLocation.
2035 @observable Location location; 2038 @observable Location location;
2036 2039
2037 // The breakpoint is in a file which is not yet loaded. 2040 // The breakpoint is in a file which is not yet loaded.
2038 @observable bool latent; 2041 @observable bool latent;
2039 2042
2040 // The breakpoint has been assigned to a final source location. 2043 // The breakpoint has been assigned to a final source location.
2041 @observable bool resolved; 2044 @observable bool resolved;
2042 2045
2046 // The breakpoint was synthetically created as part of an 'OverAWait' resume
2047 // request.
2048 @observable bool isSyntheticAsync;
2049
2043 void _update(ObservableMap map, bool mapIsRef) { 2050 void _update(ObservableMap map, bool mapIsRef) {
2044 _loaded = true; 2051 _loaded = true;
2045 _upgradeCollection(map, owner); 2052 _upgradeCollection(map, owner);
2046 2053
2047 var newNumber = map['breakpointNumber']; 2054 var newNumber = map['breakpointNumber'];
2048 // number never changes. 2055 // number never changes.
2049 assert((number == null) || (number == newNumber)); 2056 assert((number == null) || (number == newNumber));
2050 number = newNumber; 2057 number = newNumber;
2051 resolved = map['resolved']; 2058 resolved = map['resolved'];
2052 2059
2053 var oldLocation = location; 2060 var oldLocation = location;
2054 var newLocation = map['location']; 2061 var newLocation = map['location'];
2055 if (oldLocation is UnresolvedSourceLocation && 2062 if (oldLocation is UnresolvedSourceLocation &&
2056 newLocation is SourceLocation) { 2063 newLocation is SourceLocation) {
2057 // Breakpoint has been resolved. Remove old breakpoint. 2064 // Breakpoint has been resolved. Remove old breakpoint.
2058 var oldScript = oldLocation.script; 2065 var oldScript = oldLocation.script;
2059 if (oldScript != null && oldScript.loaded) { 2066 if (oldScript != null && oldScript.loaded) {
2060 oldScript._removeBreakpoint(this); 2067 oldScript._removeBreakpoint(this);
2061 } 2068 }
2062 } 2069 }
2063 location = newLocation; 2070 location = newLocation;
2064 var newScript = location.script; 2071 var newScript = location.script;
2065 if (newScript != null && newScript.loaded) { 2072 if (newScript != null && newScript.loaded) {
2066 newScript._addBreakpoint(this); 2073 newScript._addBreakpoint(this);
2067 } 2074 }
2068 2075
2076 isSyntheticAsync = map['isSyntheticAsyncBreakpoint'] != null;
2077
2069 assert(resolved || location is UnresolvedSourceLocation); 2078 assert(resolved || location is UnresolvedSourceLocation);
2070 } 2079 }
2071 2080
2072 void remove() { 2081 void remove() {
2073 // Remove any references to this breakpoint. It has been removed. 2082 // Remove any references to this breakpoint. It has been removed.
2074 location.script._removeBreakpoint(this); 2083 location.script._removeBreakpoint(this);
2075 if ((isolate.pauseEvent != null) && 2084 if ((isolate.pauseEvent != null) &&
2076 (isolate.pauseEvent.breakpoint != null) && 2085 (isolate.pauseEvent.breakpoint != null) &&
2077 (isolate.pauseEvent.breakpoint.id == id)) { 2086 (isolate.pauseEvent.breakpoint.id == id)) {
2078 isolate.pauseEvent.breakpoint = null; 2087 isolate.pauseEvent.breakpoint = null;
2079 } 2088 }
2080 } 2089 }
2081 2090
2082 String toString() { 2091 String toString() {
2083 if (number != null) { 2092 if (number != null) {
2084 return 'Breakpoint ${number} at ${location})'; 2093 if (isSyntheticAsync) {
2094 return 'Async Synthetic Breakpoint ${number} at ${location}';
2095 } else {
2096 return 'Breakpoint ${number} at ${location}';
2097 }
2085 } else { 2098 } else {
2086 return 'Uninitialized breakpoint'; 2099 return 'Uninitialized breakpoint';
2087 } 2100 }
2088 } 2101 }
2089 } 2102 }
2090 2103
2091 2104
2092 class LibraryDependency { 2105 class LibraryDependency {
2093 @reflectable final bool isImport; 2106 @reflectable final bool isImport;
2094 @reflectable final bool isDeferred; 2107 @reflectable final bool isDeferred;
(...skipping 1957 matching lines...) Expand 10 before | Expand all | Expand 10 after
4052 var v = list[i]; 4065 var v = list[i];
4053 if ((v is ObservableMap) && _isServiceMap(v)) { 4066 if ((v is ObservableMap) && _isServiceMap(v)) {
4054 list[i] = owner.getFromMap(v); 4067 list[i] = owner.getFromMap(v);
4055 } else if (v is ObservableList) { 4068 } else if (v is ObservableList) {
4056 _upgradeObservableList(v, owner); 4069 _upgradeObservableList(v, owner);
4057 } else if (v is ObservableMap) { 4070 } else if (v is ObservableMap) {
4058 _upgradeObservableMap(v, owner); 4071 _upgradeObservableMap(v, owner);
4059 } 4072 }
4060 } 4073 }
4061 } 4074 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698