Chromium Code Reviews| 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..b71550424d7e48b1cff8430873a2a3e4ffaaafab 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 |
| ], |
| + 'sane-async-stacks': [ |
|
rmacnak
2017/02/08 18:34:18
"causal" to match the vm flag
Cutch
2017/02/09 22:45:50
Done.
|
| + _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('sane-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('sane-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); |