Web Inspector: Debugger should have an option for showing asynchronous call stacks
authormattbaker@apple.com <mattbaker@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 29 Nov 2016 07:08:09 +0000 (07:08 +0000)
committermattbaker@apple.com <mattbaker@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 29 Nov 2016 07:08:09 +0000 (07:08 +0000)
commit51561f49d3a7a7c3b9b2a9785d992567bbbab8cc
treeb7ac8aefca028fb4d14cfcf78a483f69a3c5ceda
parent31c0d7573aaed700bb28568483877aaa767daa9d
Web Inspector: Debugger should have an option for showing asynchronous call stacks
https://bugs.webkit.org/show_bug.cgi?id=163230
<rdar://problem/28698683>

Reviewed by Joseph Pecoraro.

Source/JavaScriptCore:

* inspector/ScriptCallFrame.cpp:
(Inspector::ScriptCallFrame::isNative):
Encapsulate check for native code source URL.

* inspector/ScriptCallFrame.h:
* inspector/ScriptCallStack.cpp:
(Inspector::ScriptCallStack::firstNonNativeCallFrame):
(Inspector::ScriptCallStack::buildInspectorArray):
* inspector/ScriptCallStack.h:
Replace use of Console::StackTrace with Array<Console::CallFrame>.

* inspector/agents/InspectorDebuggerAgent.cpp:
(Inspector::InspectorDebuggerAgent::disable):
(Inspector::InspectorDebuggerAgent::setAsyncStackTraceDepth):
Set number of async frames to store (including boundary frames).
A value of zero disables recording of async call stacks.

(Inspector::InspectorDebuggerAgent::buildAsyncStackTrace):
Helper function for building a linked list StackTraces.
(Inspector::InspectorDebuggerAgent::didScheduleAsyncCall):
Store a call stack for the script that scheduled the async call.
If the call repeats (e.g. setInterval), the starting reference count is
set to 1. This ensures that dereffing after dispatch won't clear the stack.
If another async call is currently being dispatched, increment the
AsyncCallData reference count for that call.

(Inspector::InspectorDebuggerAgent::didCancelAsyncCall):
Decrement the reference count for the canceled call.

(Inspector::InspectorDebuggerAgent::willDispatchAsyncCall):
Set the identifier for the async callback currently being dispatched,
so that if the debugger pauses during dispatch a stack trace can be
associated with the pause location. If an async call is already being
dispatched, which could be the case when a script schedules an async
call in a nested runloop, do nothing.

(Inspector::InspectorDebuggerAgent::didDispatchAsyncCall):
Decrement the reference count for the canceled call.
(Inspector::InspectorDebuggerAgent::didPause):
If a stored stack trace exists for this location, convert to a protocol
object and send to the frontend.

(Inspector::InspectorDebuggerAgent::didClearGlobalObject):
(Inspector::InspectorDebuggerAgent::clearAsyncStackTraceData):
(Inspector::InspectorDebuggerAgent::refAsyncCallData):
Increment AsyncCallData reference count.
(Inspector::InspectorDebuggerAgent::derefAsyncCallData):
Decrement AsyncCallData reference count. If zero, deref its parent
(if it exists) and remove the AsyncCallData entry.

* inspector/agents/InspectorDebuggerAgent.h:

* inspector/protocol/Console.json:
* inspector/protocol/Network.json:
Replace use of Console.StackTrace with array of Console.CallFrame.

* inspector/protocol/Debugger.json:
New protocol command and event data.

Source/WebCore:

Test: inspector/debugger/async-stack-trace.html

* inspector/InspectorInstrumentation.cpp:
(WebCore::didScheduleAsyncCall):
Helper function used by by instrumentation hooks. Informs the debugger
agent that an asynchronous call was scheduled for the current script
execution state.

(WebCore::InspectorInstrumentation::didInstallTimerImpl):
(WebCore::InspectorInstrumentation::didRemoveTimerImpl):
(WebCore::InspectorInstrumentation::willFireTimerImpl):
(WebCore::InspectorInstrumentation::didFireTimerImpl):
Asynchronous stack trace plumbing for timers (setTimeout, setInterval).
(WebCore::InspectorInstrumentation::didRequestAnimationFrameImpl):
(WebCore::InspectorInstrumentation::didCancelAnimationFrameImpl):
(WebCore::InspectorInstrumentation::willFireAnimationFrameImpl):
(WebCore::InspectorInstrumentation::didFireAnimationFrameImpl):
Asynchronous stack trace plumbing for requestAnimationFrame.

Source/WebInspectorUI:

* Localizations/en.lproj/localizedStrings.js:
New string for generic async call stack boundary label: "(async)".

* UserInterface/Controllers/DebuggerManager.js:
Create async stack depth setting and set default depth.
(WebInspector.DebuggerManager.prototype.get asyncStackTraceDepth):
(WebInspector.DebuggerManager.prototype.set asyncStackTraceDepth):
Make async stack depth setting accessible to the frontend.
(WebInspector.DebuggerManager.prototype.initializeTarget):
Set async stack depth value on the target.
(WebInspector.DebuggerManager.prototype.debuggerDidPause):
Plumbing for the async stack trace payload.

* UserInterface/Models/ConsoleMessage.js:
(WebInspector.ConsoleMessage):
Updated for new StackTrace.fromPayload use.

* UserInterface/Models/DebuggerData.js:
(WebInspector.DebuggerData):
(WebInspector.DebuggerData.prototype.get asyncStackTrace):
(WebInspector.DebuggerData.prototype.updateForPause):
(WebInspector.DebuggerData.prototype.updateForResume):
More plumbing.

* UserInterface/Models/StackTrace.js:
Update frontend model for use as new protocol object Console.StackTrace,
which was previously an alias for a simple array of Console.CallFrames.

(WebInspector.StackTrace):
(WebInspector.StackTrace.fromPayload):
(WebInspector.StackTrace.fromString):
(WebInspector.StackTrace.prototype.get topCallFrameIsBoundary):
(WebInspector.StackTrace.prototype.get parentStackTrace):

* UserInterface/Protocol/DebuggerObserver.js:
(WebInspector.DebuggerObserver.prototype.paused):
More plumbing.

* UserInterface/Views/CallFrameTreeElement.css:
(.tree-outline .item.call-frame.async-boundary):
Use default cursor since boundary element is not selectable.
(.tree-outline .item.call-frame.async-boundary .icon):
(.tree-outline .item.call-frame.async-boundary::before,):
(.tree-outline .item.call-frame.async-boundary::after):
(.tree-outline .item.call-frame.async-boundary::before):
Dimmed text and divider line styles for boundary element.

* UserInterface/Views/CallFrameTreeElement.js:
(WebInspector.CallFrameTreeElement):
Add a flag denoting whether the call frame is an async call trace
boundary, and set styles accordingly.

* UserInterface/Views/DebuggerSidebarPanel.js:
Set async stack trace depth, if supported.
(WebInspector.DebuggerSidebarPanel.prototype._updateSingleThreadCallStacks):
Add call frames for async stack traces to the call stack TreeOutline.
(WebInspector.DebuggerSidebarPanel.prototype._treeSelectionDidChange):
Ensure that async call frames cannot become the active call frame.

* UserInterface/Views/Variables.css:
(:root):
Add --text-color-gray-medium, for dimmed text in async boundary element.

LayoutTests:

Add basic tests for async stack trace data included in Debugger.paused, and
check that requestAnimationFrame, setTimeout, and setInterval are supported.

* inspector/debugger/async-stack-trace-expected.txt: Added.
* inspector/debugger/async-stack-trace.html: Added.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@209062 268f45cc-cd09-0410-ab3c-d52691b4dbfc
26 files changed:
LayoutTests/ChangeLog
LayoutTests/inspector/debugger/async-stack-trace-expected.txt [new file with mode: 0644]
LayoutTests/inspector/debugger/async-stack-trace.html [new file with mode: 0644]
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/inspector/ScriptCallFrame.cpp
Source/JavaScriptCore/inspector/ScriptCallFrame.h
Source/JavaScriptCore/inspector/ScriptCallStack.cpp
Source/JavaScriptCore/inspector/ScriptCallStack.h
Source/JavaScriptCore/inspector/agents/InspectorDebuggerAgent.cpp
Source/JavaScriptCore/inspector/agents/InspectorDebuggerAgent.h
Source/JavaScriptCore/inspector/protocol/Console.json
Source/JavaScriptCore/inspector/protocol/Debugger.json
Source/JavaScriptCore/inspector/protocol/Network.json
Source/WebCore/ChangeLog
Source/WebCore/inspector/InspectorInstrumentation.cpp
Source/WebInspectorUI/ChangeLog
Source/WebInspectorUI/Localizations/en.lproj/localizedStrings.js
Source/WebInspectorUI/UserInterface/Controllers/DebuggerManager.js
Source/WebInspectorUI/UserInterface/Models/ConsoleMessage.js
Source/WebInspectorUI/UserInterface/Models/DebuggerData.js
Source/WebInspectorUI/UserInterface/Models/StackTrace.js
Source/WebInspectorUI/UserInterface/Protocol/DebuggerObserver.js
Source/WebInspectorUI/UserInterface/Views/CallFrameTreeElement.css
Source/WebInspectorUI/UserInterface/Views/CallFrameTreeElement.js
Source/WebInspectorUI/UserInterface/Views/DebuggerSidebarPanel.js
Source/WebInspectorUI/UserInterface/Views/Variables.css