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 // 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 Loading... |
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 stepOverAsyncContinuation() { |
| 1581 return invokeRpc('resume', {'step': 'OverAsyncContinuation'}); |
| 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 kResumeFuture = 0; |
1586 static const int kSecondResume = 1; | 1590 static const int kPauseFuture = 1; |
1587 /// result[kFirstResume] completes after the inital resume. The UI should | 1591 /// result[kResumeFuture] 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[kPauseFuture] completes when the isolate is paused after the |
1591 /// wait on this future to avoid confusing the pause event at the | 1595 /// await. Tests should wait on this future to know that we've completed |
1592 /// state-machine switch with the pause event after the state-machine switch. | 1596 /// the OverAWait. |
1593 Future<List<Future>> asyncStepOver() async { | 1597 Future<List<Future>> asyncStepOver() async { |
1594 final Completer firstResume = new Completer(); | 1598 final Completer resumedAfterSyntheticBreakpointAdded = new Completer(); |
1595 final Completer secondResume = new Completer(); | 1599 final Completer pausedAtSyntheticBreakpoint = new Completer(); |
1596 final List<Future> result = [firstResume.future, secondResume.future]; | 1600 final List<Future> result = |
| 1601 [resumedAfterSyntheticBreakpointAdded.future, |
| 1602 pausedAtSyntheticBreakpoint.future]; |
1597 StreamSubscription subscription; | 1603 StreamSubscription subscription; |
1598 | 1604 |
1599 // Inner error handling function. | 1605 // Cancel the subscription. |
1600 handleError(error) { | 1606 cancelSubscription() { |
1601 if (subscription != null) { | 1607 if (subscription != null) { |
1602 subscription.cancel(); | 1608 subscription.cancel(); |
1603 subscription = null; | 1609 subscription = null; |
1604 } | 1610 } |
1605 firstResume.completeError(error); | |
1606 secondResume.completeError(error); | |
1607 } | 1611 } |
1608 | 1612 |
1609 if ((pauseEvent == null) || | 1613 // Complete futures with with error. |
1610 (pauseEvent.kind != ServiceEvent.kPauseBreakpoint) || | 1614 completeError(error) { |
1611 (pauseEvent.asyncContinuation == null)) { | 1615 if (!resumedAfterSyntheticBreakpointAdded.isCompleted) { |
1612 handleError(new Exception("No async continuation available")); | 1616 resumedAfterSyntheticBreakpointAdded.completeError(error); |
1613 } else { | 1617 } |
1614 Instance continuation = pauseEvent.asyncContinuation; | 1618 if (!pausedAtSyntheticBreakpoint.isCompleted) { |
1615 assert(continuation.isClosure); | 1619 pausedAtSyntheticBreakpoint.completeError(error); |
| 1620 } |
| 1621 } |
1616 | 1622 |
1617 // Add breakpoint at continuation. | 1623 // Subscribe to the debugger event stream. |
1618 Breakpoint continuationBpt; | 1624 Stream stream; |
1619 try { | 1625 try { |
1620 continuationBpt = await addBreakOnActivation(continuation); | 1626 stream = await vm.getEventStream(VM.kDebugStream); |
1621 } catch (e) { | 1627 } catch (e) { |
1622 handleError(e); | 1628 completeError(e); |
1623 return result; | 1629 return result; |
| 1630 } |
| 1631 |
| 1632 Breakpoint syntheticBreakpoint; |
| 1633 |
| 1634 subscription = stream.listen((ServiceEvent event) async { |
| 1635 // Synthetic breakpoint add event. This is the first event we will |
| 1636 // receive. |
| 1637 bool isAdd = (event.kind == ServiceEvent.kBreakpointAdded) && |
| 1638 (event.breakpoint.isSyntheticAsyncContinuation) && |
| 1639 (event.owner == this); |
| 1640 // Resume after synthetic breakpoint added. This is the second event |
| 1641 // we will recieve. |
| 1642 bool isResume = (event.kind == ServiceEvent.kResume) && |
| 1643 (syntheticBreakpoint != null) && |
| 1644 (event.owner == this); |
| 1645 // Paused at synthetic breakpoint. This is the third event we will |
| 1646 // receive. |
| 1647 bool isPaused = (event.kind == ServiceEvent.kPauseBreakpoint) && |
| 1648 (syntheticBreakpoint != null) && |
| 1649 (event.breakpoint == syntheticBreakpoint); |
| 1650 if (isAdd) { |
| 1651 syntheticBreakpoint = event.breakpoint; |
| 1652 } else if (isResume) { |
| 1653 resumedAfterSyntheticBreakpointAdded.complete(this); |
| 1654 } else if (isPaused) { |
| 1655 pausedAtSyntheticBreakpoint.complete(this); |
| 1656 syntheticBreakpoint = null; |
| 1657 cancelSubscription(); |
1624 } | 1658 } |
| 1659 }); |
1625 | 1660 |
1626 // Subscribe to the debugger event stream. | 1661 // Issue the step OverAwait command. |
1627 Stream stream; | 1662 try { |
1628 try { | 1663 await isolate.stepOverAsyncContinuation(); |
1629 stream = await vm.getEventStream(VM.kDebugStream); | 1664 } catch (e) { |
1630 } catch (e) { | 1665 // This can fail when another client issued the same resume command |
1631 handleError(e); | 1666 // or another client has moved the isolate forward. |
1632 return result; | 1667 cancelSubscription(); |
1633 } | 1668 completeError(e); |
| 1669 } |
1634 | 1670 |
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; | 1671 return result; |
1666 } | 1672 } |
1667 | 1673 |
1668 Future setName(String newName) { | 1674 Future setName(String newName) { |
1669 return invokeRpc('setName', {'name': newName}); | 1675 return invokeRpc('setName', {'name': newName}); |
1670 } | 1676 } |
1671 | 1677 |
1672 Future setExceptionPauseMode(String mode) { | 1678 Future setExceptionPauseMode(String mode) { |
1673 return invokeRpc('setExceptionPauseMode', {'mode': mode}); | 1679 return invokeRpc('setExceptionPauseMode', {'mode': mode}); |
1674 } | 1680 } |
(...skipping 232 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1907 ServiceEvent.connectionClosed(this.reason) : super._empty(null) { | 1913 ServiceEvent.connectionClosed(this.reason) : super._empty(null) { |
1908 kind = kConnectionClosed; | 1914 kind = kConnectionClosed; |
1909 } | 1915 } |
1910 | 1916 |
1911 @observable String kind; | 1917 @observable String kind; |
1912 @observable DateTime timestamp; | 1918 @observable DateTime timestamp; |
1913 @observable Breakpoint breakpoint; | 1919 @observable Breakpoint breakpoint; |
1914 @observable Frame topFrame; | 1920 @observable Frame topFrame; |
1915 @observable String extensionRPC; | 1921 @observable String extensionRPC; |
1916 @observable Instance exception; | 1922 @observable Instance exception; |
1917 @observable Instance asyncContinuation; | 1923 @observable bool atAsyncContinuation; |
1918 @observable bool atAsyncJump; | |
1919 @observable ServiceObject inspectee; | 1924 @observable ServiceObject inspectee; |
1920 @observable ByteData data; | 1925 @observable ByteData data; |
1921 @observable int count; | 1926 @observable int count; |
1922 @observable String reason; | 1927 @observable String reason; |
1923 @observable String exceptions; | 1928 @observable String exceptions; |
1924 @observable String bytesAsString; | 1929 @observable String bytesAsString; |
1925 @observable Map logRecord; | 1930 @observable Map logRecord; |
1926 @observable String extensionKind; | 1931 @observable String extensionKind; |
1927 @observable Map extensionData; | 1932 @observable Map extensionData; |
1928 | 1933 |
(...skipping 28 matching lines...) Expand all Loading... |
1957 breakpoint = pauseBpts[0]; | 1962 breakpoint = pauseBpts[0]; |
1958 } | 1963 } |
1959 } | 1964 } |
1960 if (map['extensionRPC'] != null) { | 1965 if (map['extensionRPC'] != null) { |
1961 extensionRPC = map['extensionRPC']; | 1966 extensionRPC = map['extensionRPC']; |
1962 } | 1967 } |
1963 topFrame = map['topFrame']; | 1968 topFrame = map['topFrame']; |
1964 if (map['exception'] != null) { | 1969 if (map['exception'] != null) { |
1965 exception = map['exception']; | 1970 exception = map['exception']; |
1966 } | 1971 } |
1967 if (map['_asyncContinuation'] != null) { | 1972 atAsyncContinuation = map['atAsyncContinuation'] != null; |
1968 asyncContinuation = map['_asyncContinuation']; | |
1969 atAsyncJump = map['_atAsyncJump']; | |
1970 } else { | |
1971 atAsyncJump = false; | |
1972 } | |
1973 if (map['inspectee'] != null) { | 1973 if (map['inspectee'] != null) { |
1974 inspectee = map['inspectee']; | 1974 inspectee = map['inspectee']; |
1975 } | 1975 } |
1976 if (map['_data'] != null) { | 1976 if (map['_data'] != null) { |
1977 data = map['_data']; | 1977 data = map['_data']; |
1978 } | 1978 } |
1979 if (map['chunkIndex'] != null) { | 1979 if (map['chunkIndex'] != null) { |
1980 chunkIndex = map['chunkIndex']; | 1980 chunkIndex = map['chunkIndex']; |
1981 } | 1981 } |
1982 if (map['chunkCount'] != null) { | 1982 if (map['chunkCount'] != null) { |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2033 | 2033 |
2034 // Either SourceLocation or UnresolvedSourceLocation. | 2034 // Either SourceLocation or UnresolvedSourceLocation. |
2035 @observable Location location; | 2035 @observable Location location; |
2036 | 2036 |
2037 // The breakpoint is in a file which is not yet loaded. | 2037 // The breakpoint is in a file which is not yet loaded. |
2038 @observable bool latent; | 2038 @observable bool latent; |
2039 | 2039 |
2040 // The breakpoint has been assigned to a final source location. | 2040 // The breakpoint has been assigned to a final source location. |
2041 @observable bool resolved; | 2041 @observable bool resolved; |
2042 | 2042 |
| 2043 // The breakpoint was synthetically created as part of an |
| 2044 // 'OverAsyncContinuation' resume request. |
| 2045 @observable bool isSyntheticAsyncContinuation; |
| 2046 |
2043 void _update(ObservableMap map, bool mapIsRef) { | 2047 void _update(ObservableMap map, bool mapIsRef) { |
2044 _loaded = true; | 2048 _loaded = true; |
2045 _upgradeCollection(map, owner); | 2049 _upgradeCollection(map, owner); |
2046 | 2050 |
2047 var newNumber = map['breakpointNumber']; | 2051 var newNumber = map['breakpointNumber']; |
2048 // number never changes. | 2052 // number never changes. |
2049 assert((number == null) || (number == newNumber)); | 2053 assert((number == null) || (number == newNumber)); |
2050 number = newNumber; | 2054 number = newNumber; |
2051 resolved = map['resolved']; | 2055 resolved = map['resolved']; |
2052 | 2056 |
2053 var oldLocation = location; | 2057 var oldLocation = location; |
2054 var newLocation = map['location']; | 2058 var newLocation = map['location']; |
2055 if (oldLocation is UnresolvedSourceLocation && | 2059 if (oldLocation is UnresolvedSourceLocation && |
2056 newLocation is SourceLocation) { | 2060 newLocation is SourceLocation) { |
2057 // Breakpoint has been resolved. Remove old breakpoint. | 2061 // Breakpoint has been resolved. Remove old breakpoint. |
2058 var oldScript = oldLocation.script; | 2062 var oldScript = oldLocation.script; |
2059 if (oldScript != null && oldScript.loaded) { | 2063 if (oldScript != null && oldScript.loaded) { |
2060 oldScript._removeBreakpoint(this); | 2064 oldScript._removeBreakpoint(this); |
2061 } | 2065 } |
2062 } | 2066 } |
2063 location = newLocation; | 2067 location = newLocation; |
2064 var newScript = location.script; | 2068 var newScript = location.script; |
2065 if (newScript != null && newScript.loaded) { | 2069 if (newScript != null && newScript.loaded) { |
2066 newScript._addBreakpoint(this); | 2070 newScript._addBreakpoint(this); |
2067 } | 2071 } |
2068 | 2072 |
| 2073 isSyntheticAsyncContinuation = map['isSyntheticAsyncContinuation'] != null; |
| 2074 |
2069 assert(resolved || location is UnresolvedSourceLocation); | 2075 assert(resolved || location is UnresolvedSourceLocation); |
2070 } | 2076 } |
2071 | 2077 |
2072 void remove() { | 2078 void remove() { |
2073 // Remove any references to this breakpoint. It has been removed. | 2079 // Remove any references to this breakpoint. It has been removed. |
2074 location.script._removeBreakpoint(this); | 2080 location.script._removeBreakpoint(this); |
2075 if ((isolate.pauseEvent != null) && | 2081 if ((isolate.pauseEvent != null) && |
2076 (isolate.pauseEvent.breakpoint != null) && | 2082 (isolate.pauseEvent.breakpoint != null) && |
2077 (isolate.pauseEvent.breakpoint.id == id)) { | 2083 (isolate.pauseEvent.breakpoint.id == id)) { |
2078 isolate.pauseEvent.breakpoint = null; | 2084 isolate.pauseEvent.breakpoint = null; |
2079 } | 2085 } |
2080 } | 2086 } |
2081 | 2087 |
2082 String toString() { | 2088 String toString() { |
2083 if (number != null) { | 2089 if (number != null) { |
2084 return 'Breakpoint ${number} at ${location})'; | 2090 if (isSyntheticAsyncContinuation) { |
| 2091 return 'Synthetic Async Continuation Breakpoint ${number}'; |
| 2092 } else { |
| 2093 return 'Breakpoint ${number} at ${location}'; |
| 2094 } |
2085 } else { | 2095 } else { |
2086 return 'Uninitialized breakpoint'; | 2096 return 'Uninitialized breakpoint'; |
2087 } | 2097 } |
2088 } | 2098 } |
2089 } | 2099 } |
2090 | 2100 |
2091 | 2101 |
2092 class LibraryDependency { | 2102 class LibraryDependency { |
2093 @reflectable final bool isImport; | 2103 @reflectable final bool isImport; |
2094 @reflectable final bool isDeferred; | 2104 @reflectable final bool isDeferred; |
(...skipping 1957 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4052 var v = list[i]; | 4062 var v = list[i]; |
4053 if ((v is ObservableMap) && _isServiceMap(v)) { | 4063 if ((v is ObservableMap) && _isServiceMap(v)) { |
4054 list[i] = owner.getFromMap(v); | 4064 list[i] = owner.getFromMap(v); |
4055 } else if (v is ObservableList) { | 4065 } else if (v is ObservableList) { |
4056 _upgradeObservableList(v, owner); | 4066 _upgradeObservableList(v, owner); |
4057 } else if (v is ObservableMap) { | 4067 } else if (v is ObservableMap) { |
4058 _upgradeObservableMap(v, owner); | 4068 _upgradeObservableMap(v, owner); |
4059 } | 4069 } |
4060 } | 4070 } |
4061 } | 4071 } |
OLD | NEW |