| Index: runtime/observatory/lib/src/elements/debugger.dart
|
| diff --git a/runtime/observatory/lib/src/elements/debugger.dart b/runtime/observatory/lib/src/elements/debugger.dart
|
| index a2253fc034db789ab6fb4e5e0035d48e13865f73..94f47adcc532c48747f5dfe32aab806262472e11 100644
|
| --- a/runtime/observatory/lib/src/elements/debugger.dart
|
| +++ b/runtime/observatory/lib/src/elements/debugger.dart
|
| @@ -604,6 +604,11 @@ class SetCommand extends DebuggerCommand {
|
| _setUpIsDown,
|
| (debugger, _) => debugger.upIsDown
|
| ],
|
| + 'causal-async-stacks': [
|
| + _boolValues,
|
| + _setSaneAsyncStacks,
|
| + (debugger, _) => debugger.saneAsyncStacks
|
| + ],
|
| };
|
|
|
| static Future _setBreakOnException(debugger, name, value) async {
|
| @@ -625,6 +630,16 @@ class SetCommand extends DebuggerCommand {
|
| debugger.console.print('${name} = ${value}');
|
| }
|
|
|
| + static Future _setSaneAsyncStacks(debugger, name, value) async {
|
| + if (value == 'true') {
|
| + debugger.saneAsyncStacks = true;
|
| + } else {
|
| + debugger.saneAsyncStacks = false;
|
| + }
|
| + debugger.refreshStack();
|
| + debugger.console.print('${name} = ${value}');
|
| + }
|
| +
|
| Future run(List<String> args) async {
|
| if (args.length == 0) {
|
| for (var name in _options.keys) {
|
| @@ -1381,6 +1396,17 @@ class ObservatoryDebugger extends Debugger {
|
|
|
| bool _upIsDown;
|
|
|
| + bool get saneAsyncStacks => _saneAsyncStacks;
|
| + void set saneAsyncStacks(bool value) {
|
| + settings.set('causal-async-stacks', value);
|
| + _saneAsyncStacks = value;
|
| + }
|
| +
|
| + bool _saneAsyncStacks;
|
| +
|
| + static const String kAsyncCausalStackFrames = 'asyncCausalFrames';
|
| + static const String kStackFrames = 'frames';
|
| +
|
| void upFrame(int count) {
|
| if (_upIsDown) {
|
| currentFrame += count;
|
| @@ -1397,7 +1423,33 @@ class ObservatoryDebugger extends Debugger {
|
| }
|
| }
|
|
|
| - int get stackDepth => stack['frames'].length;
|
| + int get stackDepth {
|
| + if (saneAsyncStacks) {
|
| + var asyncCausalStackFrames = stack[kAsyncCausalStackFrames];
|
| + var stackFrames = stack[kStackFrames];
|
| + if (asyncCausalStackFrames == null) {
|
| + // No causal frames.
|
| + return stackFrames.length;
|
| + }
|
| + return asyncCausalStackFrames.length;
|
| + } else {
|
| + return stack[kStackFrames].length;
|
| + }
|
| + }
|
| +
|
| + List get stackFrames {
|
| + if (saneAsyncStacks) {
|
| + var asyncCausalStackFrames = stack[kAsyncCausalStackFrames];
|
| + var stackFrames = stack[kStackFrames];
|
| + if (asyncCausalStackFrames == null) {
|
| + // No causal frames.
|
| + return stackFrames ?? [];
|
| + }
|
| + return asyncCausalStackFrames;
|
| + } else {
|
| + return stack[kStackFrames] ?? [];
|
| + }
|
| + }
|
|
|
| static final _history = [''];
|
|
|
| @@ -1434,6 +1486,7 @@ class ObservatoryDebugger extends Debugger {
|
|
|
| void _loadSettings() {
|
| _upIsDown = settings.get('up-is-down');
|
| + _saneAsyncStacks = settings.get('causal-async-stacks') ?? true;
|
| }
|
|
|
| S.VM get vm => page.app.vm;
|
| @@ -2257,7 +2310,13 @@ class DebuggerStackElement extends HtmlElement implements Renderable {
|
|
|
| void updateStackFrames(S.ServiceMap newStack) {
|
| List frameElements = _frameList.children;
|
| - List newFrames = newStack['frames'];
|
| + List newFrames;
|
| + if (_debugger.saneAsyncStacks &&
|
| + (newStack[ObservatoryDebugger.kAsyncCausalStackFrames] != null)) {
|
| + newFrames = newStack[ObservatoryDebugger.kAsyncCausalStackFrames];
|
| + } else {
|
| + newFrames = newStack[ObservatoryDebugger.kStackFrames];
|
| + }
|
|
|
| // Remove any frames whose functions don't match, starting from
|
| // bottom of stack.
|
| @@ -2385,7 +2444,11 @@ class DebuggerFrameElement extends HtmlElement implements Renderable {
|
| bool _expanded = false;
|
|
|
| void setCurrent(bool value) {
|
| - _frame.function.load().then((func) {
|
| + Future load =
|
| + (_frame.function != null) ?
|
| + _frame.function.load() :
|
| + new Future.value(null);
|
| + load.then((func) {
|
| _current = value;
|
| if (_current) {
|
| _expand();
|
| @@ -2438,6 +2501,18 @@ class DebuggerFrameElement extends HtmlElement implements Renderable {
|
| } else {
|
| classes.remove('current');
|
| }
|
| + if ((_frame.kind == M.FrameKind.asyncSuspensionMarker) ||
|
| + (_frame.kind == M.FrameKind.asyncCausal)) {
|
| + classes.add('causalFrame');
|
| + }
|
| + if (_frame.kind == M.FrameKind.asyncSuspensionMarker) {
|
| + final content = <Element>[
|
| + new SpanElement()
|
| + ..children = _createMarkerHeader(_frame.marker)
|
| + ];
|
| + children = content;
|
| + return;
|
| + }
|
| ButtonElement expandButton;
|
| final content = <Element>[
|
| expandButton = new ButtonElement()
|
| @@ -2540,6 +2615,24 @@ class DebuggerFrameElement extends HtmlElement implements Renderable {
|
| children = content;
|
| }
|
|
|
| + List<Element> _createMarkerHeader(String marker) {
|
| + final content = [
|
| + new DivElement()
|
| + ..classes = ['frameSummaryText']
|
| + ..children = [
|
| + new DivElement()
|
| + ..classes = ['frameId']
|
| + ..text = 'Frame ${_frame.index}',
|
| + new SpanElement()..text = '$marker',
|
| + ]
|
| + ];
|
| + return [
|
| + new DivElement()
|
| + ..classes = ['frameSummary']
|
| + ..children = content
|
| + ];
|
| + }
|
| +
|
| List<Element> _createHeader() {
|
| final content = [
|
| new DivElement()
|
| @@ -2584,6 +2677,12 @@ class DebuggerFrameElement extends HtmlElement implements Renderable {
|
| }
|
|
|
| bool matchFrame(S.Frame newFrame) {
|
| + if (newFrame.kind != _frame.kind) {
|
| + return false;
|
| + }
|
| + if (newFrame.function == null) {
|
| + return frame.function == null;
|
| + }
|
| return (newFrame.function.id == _frame.function.id &&
|
| newFrame.location.script.id ==
|
| frame.location.script.id);
|
|
|