Changeset 209062 in webkit


Ignore:
Timestamp:
Nov 28, 2016 11:08:09 PM (7 years ago)
Author:
Matt Baker
Message:

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.
Location:
trunk
Files:
2 added
24 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r209024 r209062  
     12016-11-28  Matt Baker  <mattbaker@apple.com>
     2
     3        Web Inspector: Debugger should have an option for showing asynchronous call stacks
     4        https://bugs.webkit.org/show_bug.cgi?id=163230
     5        <rdar://problem/28698683>
     6
     7        Reviewed by Joseph Pecoraro.
     8
     9        Add basic tests for async stack trace data included in Debugger.paused, and
     10        check that requestAnimationFrame, setTimeout, and setInterval are supported.
     11
     12        * inspector/debugger/async-stack-trace-expected.txt: Added.
     13        * inspector/debugger/async-stack-trace.html: Added.
     14
    1152016-11-28  Ryan Haddad  <ryanhaddad@apple.com>
    216
  • trunk/Source/JavaScriptCore/ChangeLog

    r209058 r209062  
     12016-11-28  Matt Baker  <mattbaker@apple.com>
     2
     3        Web Inspector: Debugger should have an option for showing asynchronous call stacks
     4        https://bugs.webkit.org/show_bug.cgi?id=163230
     5        <rdar://problem/28698683>
     6
     7        Reviewed by Joseph Pecoraro.
     8
     9        * inspector/ScriptCallFrame.cpp:
     10        (Inspector::ScriptCallFrame::isNative):
     11        Encapsulate check for native code source URL.
     12
     13        * inspector/ScriptCallFrame.h:
     14        * inspector/ScriptCallStack.cpp:
     15        (Inspector::ScriptCallStack::firstNonNativeCallFrame):
     16        (Inspector::ScriptCallStack::buildInspectorArray):
     17        * inspector/ScriptCallStack.h:
     18        Replace use of Console::StackTrace with Array<Console::CallFrame>.
     19
     20        * inspector/agents/InspectorDebuggerAgent.cpp:
     21        (Inspector::InspectorDebuggerAgent::disable):
     22        (Inspector::InspectorDebuggerAgent::setAsyncStackTraceDepth):
     23        Set number of async frames to store (including boundary frames).
     24        A value of zero disables recording of async call stacks.
     25
     26        (Inspector::InspectorDebuggerAgent::buildAsyncStackTrace):
     27        Helper function for building a linked list StackTraces.
     28        (Inspector::InspectorDebuggerAgent::didScheduleAsyncCall):
     29        Store a call stack for the script that scheduled the async call.
     30        If the call repeats (e.g. setInterval), the starting reference count is
     31        set to 1. This ensures that dereffing after dispatch won't clear the stack.
     32        If another async call is currently being dispatched, increment the
     33        AsyncCallData reference count for that call.
     34
     35        (Inspector::InspectorDebuggerAgent::didCancelAsyncCall):
     36        Decrement the reference count for the canceled call.
     37
     38        (Inspector::InspectorDebuggerAgent::willDispatchAsyncCall):
     39        Set the identifier for the async callback currently being dispatched,
     40        so that if the debugger pauses during dispatch a stack trace can be
     41        associated with the pause location. If an async call is already being
     42        dispatched, which could be the case when a script schedules an async
     43        call in a nested runloop, do nothing.
     44
     45        (Inspector::InspectorDebuggerAgent::didDispatchAsyncCall):
     46        Decrement the reference count for the canceled call.
     47        (Inspector::InspectorDebuggerAgent::didPause):
     48        If a stored stack trace exists for this location, convert to a protocol
     49        object and send to the frontend.
     50
     51        (Inspector::InspectorDebuggerAgent::didClearGlobalObject):
     52        (Inspector::InspectorDebuggerAgent::clearAsyncStackTraceData):
     53        (Inspector::InspectorDebuggerAgent::refAsyncCallData):
     54        Increment AsyncCallData reference count.
     55        (Inspector::InspectorDebuggerAgent::derefAsyncCallData):
     56        Decrement AsyncCallData reference count. If zero, deref its parent
     57        (if it exists) and remove the AsyncCallData entry.
     58
     59        * inspector/agents/InspectorDebuggerAgent.h:
     60
     61        * inspector/protocol/Console.json:
     62        * inspector/protocol/Network.json:
     63        Replace use of Console.StackTrace with array of Console.CallFrame.
     64
     65        * inspector/protocol/Debugger.json:
     66        New protocol command and event data.
     67
    1682016-11-28  Darin Adler  <darin@apple.com>
    269
  • trunk/Source/JavaScriptCore/inspector/ScriptCallFrame.cpp

    r199852 r209062  
    6060}
    6161
     62bool ScriptCallFrame::isNative() const
     63{
     64    return m_scriptName == "[native code]";
     65}
     66
    6267Ref<Inspector::Protocol::Console::CallFrame> ScriptCallFrame::buildInspectorObject() const
    6368{
  • trunk/Source/JavaScriptCore/inspector/ScriptCallFrame.h

    r204479 r209062  
    5151
    5252    bool isEqual(const ScriptCallFrame&) const;
     53    bool isNative() const;
    5354
    5455    Ref<Inspector::Protocol::Console::CallFrame> buildInspectorObject() const;
  • trunk/Source/JavaScriptCore/inspector/ScriptCallStack.cpp

    r194428 r209062  
    7878    for (size_t i = 0; i < m_frames.size(); ++i) {
    7979        const ScriptCallFrame& frame = m_frames[i];
    80         if (frame.sourceURL() != "[native code]")
     80        if (!frame.isNative())
    8181            return &frame;
    8282    }
     
    107107}
    108108
    109 Ref<Inspector::Protocol::Console::StackTrace> ScriptCallStack::buildInspectorArray() const
     109Ref<Inspector::Protocol::Array<Inspector::Protocol::Console::CallFrame>> ScriptCallStack::buildInspectorArray() const
    110110{
    111     auto frames = Inspector::Protocol::Console::StackTrace::create();
     111    auto frames = Inspector::Protocol::Array<Inspector::Protocol::Console::CallFrame>::create();
    112112    for (size_t i = 0; i < m_frames.size(); i++)
    113113        frames->addItem(m_frames.at(i).buildInspectorObject());
  • trunk/Source/JavaScriptCore/inspector/ScriptCallStack.h

    r204479 r209062  
    5858    bool isEqual(ScriptCallStack*) const;
    5959
    60     Ref<Inspector::Protocol::Console::StackTrace> buildInspectorArray() const;
     60    Ref<Inspector::Protocol::Array<Inspector::Protocol::Console::CallFrame>> buildInspectorArray() const;
    6161
    6262private:
  • trunk/Source/JavaScriptCore/inspector/agents/InspectorDebuggerAgent.cpp

    r208755 r209062  
    3838#include "JSCInlines.h"
    3939#include "RegularExpression.h"
     40#include "ScriptCallStackFactory.h"
    4041#include "ScriptDebugServer.h"
    4142#include "ScriptObject.h"
     
    114115        m_listener->debuggerWasDisabled();
    115116
     117    clearAsyncStackTraceData();
     118
    116119    m_pauseOnAssertionFailures = false;
    117120
     
    132135{
    133136    return m_scriptDebugServer.breakpointsActive();
     137}
     138
     139void InspectorDebuggerAgent::setAsyncStackTraceDepth(ErrorString& errorString, int depth)
     140{
     141    if (m_asyncStackTraceDepth == depth)
     142        return;
     143
     144    if (depth < 0) {
     145        errorString = ASCIILiteral("depth must be a positive number.");
     146        return;
     147    }
     148
     149    m_asyncStackTraceDepth = depth;
     150
     151    if (!m_asyncStackTraceDepth)
     152        clearAsyncStackTraceData();
    134153}
    135154
     
    194213}
    195214
     215RefPtr<Inspector::Protocol::Console::StackTrace> InspectorDebuggerAgent::buildAsyncStackTrace(const AsyncCallIdentifier& identifier)
     216{
     217    RefPtr<Inspector::Protocol::Console::StackTrace> topStackTrace;
     218    RefPtr<Inspector::Protocol::Console::StackTrace> previousStackTrace;
     219
     220    auto iterator = m_asyncCallIdentifierToData.find(identifier);
     221    auto end = m_asyncCallIdentifierToData.end();
     222    while (iterator != end) {
     223        const auto& callData = iterator->value;
     224        ASSERT(callData.callStack && callData.callStack->size());
     225        if (!callData.callStack || !callData.callStack->size())
     226            break;
     227
     228        RefPtr<Inspector::Protocol::Console::StackTrace> stackTrace = Inspector::Protocol::Console::StackTrace::create()
     229            .setCallFrames(callData.callStack->buildInspectorArray())
     230            .release();
     231
     232        if (callData.callStack->at(0).isNative())
     233            stackTrace->setTopCallFrameIsBoundary(true);
     234        if (!topStackTrace)
     235            topStackTrace = stackTrace;
     236        if (previousStackTrace)
     237            previousStackTrace->setParentStackTrace(stackTrace);
     238
     239        if (!callData.parentAsyncCallIdentifier)
     240            break;
     241
     242        previousStackTrace = stackTrace;
     243        iterator = m_asyncCallIdentifierToData.find(callData.parentAsyncCallIdentifier.value());
     244    }
     245
     246    return topStackTrace;
     247}
     248
    196249void InspectorDebuggerAgent::handleConsoleAssert(const String& message)
    197250{
    198251    if (m_pauseOnAssertionFailures)
    199252        breakProgram(DebuggerFrontendDispatcher::Reason::Assert, buildAssertPauseReason(message));
     253}
     254
     255void InspectorDebuggerAgent::didScheduleAsyncCall(JSC::ExecState* exec, int asyncCallType, int callbackIdentifier, bool singleShot)
     256{
     257    if (!m_asyncStackTraceDepth)
     258        return;
     259
     260    if (!m_scriptDebugServer.breakpointsActive())
     261        return;
     262
     263    RefPtr<ScriptCallStack> callStack = createScriptCallStack(exec, m_asyncStackTraceDepth);
     264    ASSERT(callStack && callStack->size());
     265    if (!callStack || !callStack->size())
     266        return;
     267
     268    if (m_currentAsyncCallIdentifier)
     269        refAsyncCallData(m_currentAsyncCallIdentifier.value());
     270
     271    m_asyncCallIdentifierToData.set(std::make_pair(asyncCallType, callbackIdentifier), AsyncCallData(callStack, m_currentAsyncCallIdentifier, singleShot));
     272}
     273
     274void InspectorDebuggerAgent::didCancelAsyncCall(int asyncCallType, int callbackIdentifier)
     275{
     276    if (!m_asyncStackTraceDepth)
     277        return;
     278
     279    const auto asyncCallIdentifier = std::make_pair(asyncCallType, callbackIdentifier);
     280    derefAsyncCallData(asyncCallIdentifier);
     281}
     282
     283void InspectorDebuggerAgent::willDispatchAsyncCall(int asyncCallType, int callbackIdentifier)
     284{
     285    if (!m_asyncStackTraceDepth)
     286        return;
     287
     288    if (m_currentAsyncCallIdentifier)
     289        return;
     290
     291    // A call can be scheduled before the Inspector is opened, or while async stack
     292    // traces are disabled. If no call data exists, do nothing.
     293    auto asyncCallIdentifier = std::make_pair(asyncCallType, callbackIdentifier);
     294    if (!m_asyncCallIdentifierToData.contains(asyncCallIdentifier))
     295        return;
     296
     297    m_currentAsyncCallIdentifier = WTFMove(asyncCallIdentifier);
     298    refAsyncCallData(asyncCallIdentifier);
     299}
     300
     301void InspectorDebuggerAgent::didDispatchAsyncCall()
     302{
     303    if (!m_asyncStackTraceDepth)
     304        return;
     305
     306    if (!m_currentAsyncCallIdentifier)
     307        return;
     308
     309    derefAsyncCallData(m_currentAsyncCallIdentifier.value());
     310    m_currentAsyncCallIdentifier = std::nullopt;
    200311}
    201312
     
    883994    m_enablePauseWhenIdle = false;
    884995
    885     m_frontendDispatcher->paused(currentCallFrames(injectedScript), m_breakReason, m_breakAuxData);
     996    RefPtr<Inspector::Protocol::Console::StackTrace> asyncStackTrace;
     997    if (m_currentAsyncCallIdentifier)
     998        asyncStackTrace = buildAsyncStackTrace(m_currentAsyncCallIdentifier.value());
     999
     1000    m_frontendDispatcher->paused(currentCallFrames(injectedScript), m_breakReason, m_breakAuxData, asyncStackTrace);
    8861001
    8871002    m_javaScriptPauseScheduled = false;
     
    9861101    clearDebuggerBreakpointState();
    9871102
     1103    clearAsyncStackTraceData();
     1104
    9881105    m_frontendDispatcher->globalObjectCleared();
    9891106}
     
    10131130}
    10141131
     1132void InspectorDebuggerAgent::clearAsyncStackTraceData()
     1133{
     1134    m_asyncCallIdentifierToData.clear();
     1135    m_currentAsyncCallIdentifier = std::nullopt;
     1136}
     1137
     1138void InspectorDebuggerAgent::refAsyncCallData(const AsyncCallIdentifier& identifier)
     1139{
     1140    auto iterator = m_asyncCallIdentifierToData.find(identifier);
     1141    ASSERT(iterator != m_asyncCallIdentifierToData.end());
     1142    if (iterator == m_asyncCallIdentifierToData.end())
     1143        return;
     1144
     1145    iterator->value.referenceCount++;
     1146}
     1147
     1148void InspectorDebuggerAgent::derefAsyncCallData(const AsyncCallIdentifier& identifier)
     1149{
     1150    auto iterator = m_asyncCallIdentifierToData.find(identifier);
     1151    ASSERT(iterator != m_asyncCallIdentifierToData.end());
     1152    if (iterator == m_asyncCallIdentifierToData.end())
     1153        return;
     1154
     1155    auto& asyncCallData = iterator->value;
     1156    asyncCallData.referenceCount--;
     1157    if (asyncCallData.referenceCount)
     1158        return;
     1159
     1160    if (asyncCallData.parentAsyncCallIdentifier)
     1161        derefAsyncCallData(asyncCallData.parentAsyncCallIdentifier.value());
     1162    m_asyncCallIdentifierToData.remove(identifier);
     1163}
     1164
    10151165} // namespace Inspector
  • trunk/Source/JavaScriptCore/inspector/agents/InspectorDebuggerAgent.h

    r208725 r209062  
    3636#include "inspector/InspectorAgentBase.h"
    3737#include "inspector/ScriptBreakpoint.h"
     38#include "inspector/ScriptCallStack.h"
    3839#include "inspector/ScriptDebugListener.h"
    3940#include <wtf/Forward.h>
     
    4950class InspectorObject;
    5051class ScriptDebugServer;
     52struct AsyncCallData;
    5153typedef String ErrorString;
    5254
     
    6466    void enable(ErrorString&) final;
    6567    void disable(ErrorString&) final;
     68    void setAsyncStackTraceDepth(ErrorString&, int depth) final;
    6669    void setBreakpointsActive(ErrorString&, bool active) final;
    6770    void setBreakpointByUrl(ErrorString&, int lineNumber, const String* optionalURL, const String* optionalURLRegex, const int* optionalColumnNumber, const Inspector::InspectorObject* options, Inspector::Protocol::Debugger::BreakpointId*, RefPtr<Inspector::Protocol::Array<Inspector::Protocol::Debugger::Location>>& locations) final;
     
    9093    void handleConsoleAssert(const String& message);
    9194
     95    void didScheduleAsyncCall(JSC::ExecState*, int asyncCallType, int callbackIdentifier, bool singleShot);
     96    void didCancelAsyncCall(int asyncCallType, int callbackIdentifier);
     97    void willDispatchAsyncCall(int asyncCallType, int callbackIdentifier);
     98    void didDispatchAsyncCall();
     99
    92100    void schedulePauseOnNextStatement(DebuggerFrontendDispatcher::Reason breakReason, RefPtr<InspectorObject>&& data);
    93101    void cancelPauseOnNextStatement();
     
    143151    void clearBreakDetails();
    144152    void clearExceptionValue();
     153    void clearAsyncStackTraceData();
    145154
    146155    enum class ShouldDispatchResumed { No, WhenIdle, WhenContinued };
     
    154163    bool breakpointActionsFromProtocol(ErrorString&, RefPtr<InspectorArray>& actions, BreakpointActions* result);
    155164
     165    typedef std::pair<int, int> AsyncCallIdentifier;
     166
     167    RefPtr<Inspector::Protocol::Console::StackTrace> buildAsyncStackTrace(const AsyncCallIdentifier&);
     168    void refAsyncCallData(const AsyncCallIdentifier&);
     169    void derefAsyncCallData(const AsyncCallIdentifier&);
     170
    156171    typedef HashMap<JSC::SourceID, Script> ScriptsMap;
    157172    typedef HashMap<String, Vector<JSC::BreakpointID>> BreakpointIdentifierToDebugServerBreakpointIDsMap;
    158173    typedef HashMap<String, RefPtr<InspectorObject>> BreakpointIdentifierToBreakpointMap;
    159174    typedef HashMap<JSC::BreakpointID, String> DebugServerBreakpointIDToBreakpointIdentifier;
     175
     176    struct AsyncCallData {
     177        AsyncCallData(RefPtr<ScriptCallStack> callStack, std::optional<AsyncCallIdentifier> parentAsyncCallIdentifier, bool singleShot)
     178            : callStack(callStack)
     179            , parentAsyncCallIdentifier(parentAsyncCallIdentifier)
     180            , referenceCount(singleShot ? 0 : 1)
     181        {
     182        }
     183
     184        AsyncCallData() = default;
     185
     186        RefPtr<ScriptCallStack> callStack;
     187        std::optional<AsyncCallIdentifier> parentAsyncCallIdentifier { std::nullopt };
     188        unsigned referenceCount { 0 };
     189    };
    160190
    161191    InjectedScriptManager& m_injectedScriptManager;
     
    175205    ShouldDispatchResumed m_conditionToDispatchResumed { ShouldDispatchResumed::No };
    176206    bool m_enablePauseWhenIdle { false };
     207    HashMap<AsyncCallIdentifier, AsyncCallData> m_asyncCallIdentifierToData;
     208    std::optional<AsyncCallIdentifier> m_currentAsyncCallIdentifier { std::nullopt };
    177209    bool m_enabled { false };
    178210    bool m_javaScriptPauseScheduled { false };
     
    181213    bool m_pauseOnAssertionFailures { false };
    182214    bool m_registeredIdleCallback { false };
     215    int m_asyncStackTraceDepth { 0 };
    183216};
    184217
  • trunk/Source/JavaScriptCore/inspector/protocol/Console.json

    r199852 r209062  
    1717                { "name": "repeatCount", "type": "integer", "optional": true, "description": "Repeat count for repeated messages." },
    1818                { "name": "parameters", "type": "array", "items": { "$ref": "Runtime.RemoteObject" }, "optional": true, "description": "Message parameters in case of the formatted message." },
    19                 { "name": "stackTrace", "$ref": "StackTrace", "optional": true, "description": "JavaScript stack trace for assertions and error messages." },
     19                { "name": "stackTrace", "type": "array", "items": { "$ref": "CallFrame" }, "optional": true, "description": "JavaScript stack trace for assertions and error messages." },
    2020                { "name": "networkRequestId", "$ref": "Network.RequestId", "optional": true, "description": "Identifier of the network request associated with this message." }
    2121            ]
     
    3535        {
    3636            "id": "StackTrace",
    37             "type": "array",
    38             "items": { "$ref": "CallFrame" },
    39             "description": "Call frames for assertions or error messages."
     37            "description": "Call frames for async function calls, console assertions, and error messages.",
     38            "type": "object",
     39            "properties": [
     40                { "name": "callFrames", "type": "array", "items": { "$ref": "CallFrame" } },
     41                { "name": "topCallFrameIsBoundary", "type": "boolean", "optional": true, "description": "Whether the first item in <code>callFrames</code> is the native function that scheduled the asynchronous operation (e.g. setTimeout)." },
     42                { "name": "parentStackTrace", "$ref": "StackTrace", "optional": true, "description": "Parent StackTrace." }
     43            ]
    4044        }
    4145    ],
  • trunk/Source/JavaScriptCore/inspector/protocol/Debugger.json

    r208725 r209062  
    135135            "name": "disable",
    136136            "description": "Disables debugger for given page."
     137        },
     138        {
     139            "name": "setAsyncStackTraceDepth",
     140            "description": "Set the async stack trace depth for the page. A value of zero disables recording of async stack traces.",
     141            "parameters": [
     142                { "name": "depth", "type": "integer", "description": "Async stack trace depth." }
     143            ]
    137144        },
    138145        {
     
    326333                { "name": "callFrames", "type": "array", "items": { "$ref": "CallFrame" }, "description": "Call stack the virtual machine stopped on." },
    327334                { "name": "reason", "type": "string", "enum": ["XHR", "DOM", "EventListener", "exception", "assert", "CSPViolation", "DebuggerStatement", "Breakpoint", "PauseOnNextStatement", "other"], "description": "Pause reason." },
    328                 { "name": "data", "type": "object", "optional": true, "description": "Object containing break-specific auxiliary properties." }
     335                { "name": "data", "type": "object", "optional": true, "description": "Object containing break-specific auxiliary properties." },
     336                { "name": "asyncStackTrace", "$ref": "Console.StackTrace", "optional": true, "description": "Linked list of asynchronous StackTraces." }
    329337            ],
    330338            "description": "Fired when the virtual machine stopped on breakpoint or exception or any other stop criteria."
  • trunk/Source/JavaScriptCore/inspector/protocol/Network.json

    r208520 r209062  
    118118            "properties": [
    119119                { "name": "type", "type": "string", "enum": ["parser", "script", "other"], "description": "Type of this initiator." },
    120                 { "name": "stackTrace", "$ref": "Console.StackTrace", "optional": true, "description": "Initiator JavaScript stack trace, set for Script only." },
     120                { "name": "stackTrace", "type": "array", "items": { "$ref": "Console.CallFrame" }, "optional": true, "description": "Initiator JavaScript stack trace, set for Script only." },
    121121                { "name": "url", "type": "string", "optional": true, "description": "Initiator URL, set for Parser type only." },
    122122                { "name": "lineNumber", "type": "number", "optional": true, "description": "Initiator line number, set for Parser type only." }
  • trunk/Source/WebCore/ChangeLog

    r209061 r209062  
     12016-11-28  Matt Baker  <mattbaker@apple.com>
     2
     3        Web Inspector: Debugger should have an option for showing asynchronous call stacks
     4        https://bugs.webkit.org/show_bug.cgi?id=163230
     5        <rdar://problem/28698683>
     6
     7        Reviewed by Joseph Pecoraro.
     8
     9        Test: inspector/debugger/async-stack-trace.html
     10
     11        * inspector/InspectorInstrumentation.cpp:
     12        (WebCore::didScheduleAsyncCall):
     13        Helper function used by by instrumentation hooks. Informs the debugger
     14        agent that an asynchronous call was scheduled for the current script
     15        execution state.
     16
     17        (WebCore::InspectorInstrumentation::didInstallTimerImpl):
     18        (WebCore::InspectorInstrumentation::didRemoveTimerImpl):
     19        (WebCore::InspectorInstrumentation::willFireTimerImpl):
     20        (WebCore::InspectorInstrumentation::didFireTimerImpl):
     21        Asynchronous stack trace plumbing for timers (setTimeout, setInterval).
     22        (WebCore::InspectorInstrumentation::didRequestAnimationFrameImpl):
     23        (WebCore::InspectorInstrumentation::didCancelAnimationFrameImpl):
     24        (WebCore::InspectorInstrumentation::willFireAnimationFrameImpl):
     25        (WebCore::InspectorInstrumentation::didFireAnimationFrameImpl):
     26        Asynchronous stack trace plumbing for requestAnimationFrame.
     27
    1282016-11-28  Jiewen Tan  <jiewen_tan@apple.com>
    229
  • trunk/Source/WebCore/inspector/InspectorInstrumentation.cpp

    r208985 r209062  
    8484static const char* const timerFiredEventName = "timerFired";
    8585
     86enum AsyncCallType {
     87    AsyncCallTypeRequestAnimationFrame,
     88    AsyncCallTypeTimer,
     89};
     90
    8691namespace {
    8792static HashSet<InstrumentingAgents*>* s_instrumentingAgentsSet = nullptr;
     
    8994
    9095int InspectorInstrumentation::s_frontendCounter = 0;
     96
     97static void didScheduleAsyncCall(InstrumentingAgents& instrumentingAgents, AsyncCallType type, int callbackId, ScriptExecutionContext& context, bool singleShot)
     98{
     99    if (InspectorDebuggerAgent* debuggerAgent = instrumentingAgents.inspectorDebuggerAgent()) {
     100        JSC::ExecState* scriptState = context.execState();
     101        if (!scriptState)
     102            return;
     103
     104        debuggerAgent->didScheduleAsyncCall(scriptState, type, callbackId, singleShot);
     105    }
     106}
    91107
    92108static Frame* frameForScriptExecutionContext(ScriptExecutionContext* context)
     
    324340{
    325341    pauseOnNativeEventIfNeeded(instrumentingAgents, false, setTimerEventName, true);
     342    didScheduleAsyncCall(instrumentingAgents, AsyncCallTypeTimer, timerId, context, singleShot);
     343
    326344    if (InspectorTimelineAgent* timelineAgent = instrumentingAgents.inspectorTimelineAgent())
    327345        timelineAgent->didInstallTimer(timerId, timeout, singleShot, frameForScriptExecutionContext(context));
     
    331349{
    332350    pauseOnNativeEventIfNeeded(instrumentingAgents, false, clearTimerEventName, true);
     351
     352    if (InspectorDebuggerAgent* debuggerAgent = instrumentingAgents.inspectorDebuggerAgent())
     353        debuggerAgent->didCancelAsyncCall(AsyncCallTypeTimer, timerId);
    333354    if (InspectorTimelineAgent* timelineAgent = instrumentingAgents.inspectorTimelineAgent())
    334355        timelineAgent->didRemoveTimer(timerId, frameForScriptExecutionContext(context));
     
    424445    pauseOnNativeEventIfNeeded(instrumentingAgents, false, timerFiredEventName, false);
    425446
     447    if (InspectorDebuggerAgent* debuggerAgent = instrumentingAgents.inspectorDebuggerAgent())
     448        debuggerAgent->willDispatchAsyncCall(AsyncCallTypeTimer, timerId);
     449
    426450    int timelineAgentId = 0;
    427451    if (InspectorTimelineAgent* timelineAgent = instrumentingAgents.inspectorTimelineAgent()) {
     
    434458void InspectorInstrumentation::didFireTimerImpl(const InspectorInstrumentationCookie& cookie)
    435459{
     460    if (InspectorDebuggerAgent* debuggerAgent = cookie.instrumentingAgents()->inspectorDebuggerAgent())
     461        debuggerAgent->didDispatchAsyncCall();
    436462    if (InspectorTimelineAgent* timelineAgent = retrieveTimelineAgent(cookie))
    437463        timelineAgent->didFireTimer();
     
    11401166{
    11411167    pauseOnNativeEventIfNeeded(instrumentingAgents, false, requestAnimationFrameEventName, true);
     1168    didScheduleAsyncCall(instrumentingAgents, AsyncCallTypeRequestAnimationFrame, callbackId, *frame->document(), true);
    11421169
    11431170    if (InspectorTimelineAgent* timelineAgent = instrumentingAgents.inspectorTimelineAgent())
     
    11491176    pauseOnNativeEventIfNeeded(instrumentingAgents, false, cancelAnimationFrameEventName, true);
    11501177
     1178    if (InspectorDebuggerAgent* debuggerAgent = instrumentingAgents.inspectorDebuggerAgent())
     1179        debuggerAgent->didCancelAsyncCall(AsyncCallTypeRequestAnimationFrame, callbackId);
    11511180    if (InspectorTimelineAgent* timelineAgent = instrumentingAgents.inspectorTimelineAgent())
    11521181        timelineAgent->didCancelAnimationFrame(callbackId, frame);
     
    11561185{
    11571186    pauseOnNativeEventIfNeeded(instrumentingAgents, false, animationFrameFiredEventName, false);
     1187
     1188    if (InspectorDebuggerAgent* debuggerAgent = instrumentingAgents.inspectorDebuggerAgent())
     1189        debuggerAgent->willDispatchAsyncCall(AsyncCallTypeRequestAnimationFrame, callbackId);
    11581190
    11591191    int timelineAgentId = 0;
     
    11671199void InspectorInstrumentation::didFireAnimationFrameImpl(const InspectorInstrumentationCookie& cookie)
    11681200{
     1201    if (InspectorDebuggerAgent* debuggerAgent = cookie.instrumentingAgents()->inspectorDebuggerAgent())
     1202        debuggerAgent->didDispatchAsyncCall();
    11691203    if (InspectorTimelineAgent* timelineAgent = retrieveTimelineAgent(cookie))
    11701204        timelineAgent->didFireAnimationFrame();
  • trunk/Source/WebInspectorUI/ChangeLog

    r208895 r209062  
     12016-11-28  Matt Baker  <mattbaker@apple.com>
     2
     3        Web Inspector: Debugger should have an option for showing asynchronous call stacks
     4        https://bugs.webkit.org/show_bug.cgi?id=163230
     5        <rdar://problem/28698683>
     6
     7        Reviewed by Joseph Pecoraro.
     8
     9        * Localizations/en.lproj/localizedStrings.js:
     10        New string for generic async call stack boundary label: "(async)".
     11
     12        * UserInterface/Controllers/DebuggerManager.js:
     13        Create async stack depth setting and set default depth.
     14        (WebInspector.DebuggerManager.prototype.get asyncStackTraceDepth):
     15        (WebInspector.DebuggerManager.prototype.set asyncStackTraceDepth):
     16        Make async stack depth setting accessible to the frontend.
     17        (WebInspector.DebuggerManager.prototype.initializeTarget):
     18        Set async stack depth value on the target.
     19        (WebInspector.DebuggerManager.prototype.debuggerDidPause):
     20        Plumbing for the async stack trace payload.
     21
     22        * UserInterface/Models/ConsoleMessage.js:
     23        (WebInspector.ConsoleMessage):
     24        Updated for new StackTrace.fromPayload use.
     25
     26        * UserInterface/Models/DebuggerData.js:
     27        (WebInspector.DebuggerData):
     28        (WebInspector.DebuggerData.prototype.get asyncStackTrace):
     29        (WebInspector.DebuggerData.prototype.updateForPause):
     30        (WebInspector.DebuggerData.prototype.updateForResume):
     31        More plumbing.
     32
     33        * UserInterface/Models/StackTrace.js:
     34        Update frontend model for use as new protocol object Console.StackTrace,
     35        which was previously an alias for a simple array of Console.CallFrames.
     36
     37        (WebInspector.StackTrace):
     38        (WebInspector.StackTrace.fromPayload):
     39        (WebInspector.StackTrace.fromString):
     40        (WebInspector.StackTrace.prototype.get topCallFrameIsBoundary):
     41        (WebInspector.StackTrace.prototype.get parentStackTrace):
     42
     43        * UserInterface/Protocol/DebuggerObserver.js:
     44        (WebInspector.DebuggerObserver.prototype.paused):
     45        More plumbing.
     46
     47        * UserInterface/Views/CallFrameTreeElement.css:
     48        (.tree-outline .item.call-frame.async-boundary):
     49        Use default cursor since boundary element is not selectable.
     50        (.tree-outline .item.call-frame.async-boundary .icon):
     51        (.tree-outline .item.call-frame.async-boundary::before,):
     52        (.tree-outline .item.call-frame.async-boundary::after):
     53        (.tree-outline .item.call-frame.async-boundary::before):
     54        Dimmed text and divider line styles for boundary element.
     55
     56        * UserInterface/Views/CallFrameTreeElement.js:
     57        (WebInspector.CallFrameTreeElement):
     58        Add a flag denoting whether the call frame is an async call trace
     59        boundary, and set styles accordingly.
     60
     61        * UserInterface/Views/DebuggerSidebarPanel.js:
     62        Set async stack trace depth, if supported.
     63        (WebInspector.DebuggerSidebarPanel.prototype._updateSingleThreadCallStacks):
     64        Add call frames for async stack traces to the call stack TreeOutline.
     65        (WebInspector.DebuggerSidebarPanel.prototype._treeSelectionDidChange):
     66        Ensure that async call frames cannot become the active call frame.
     67
     68        * UserInterface/Views/Variables.css:
     69        (:root):
     70        Add --text-color-gray-medium, for dimmed text in async boundary element.
     71
    1722016-11-18  Matt Baker  <mattbaker@apple.com>
    273
  • trunk/Source/WebInspectorUI/Localizations/en.lproj/localizedStrings.js

    r208783 r209062  
    4343localizedStrings["(Tail Call)"] = "(Tail Call)";
    4444localizedStrings["(anonymous function)"] = "(anonymous function)";
     45localizedStrings["(async)"] = "(async)";
    4546localizedStrings["(many)"] = "(many)";
    4647localizedStrings["(modify the boxes below to add a value)"] = "(modify the boxes below to add a value)";
  • trunk/Source/WebInspectorUI/UserInterface/Controllers/DebuggerManager.js

    r208725 r209062  
    5353        this._allUncaughtExceptionsBreakpointEnabledSetting = new WebInspector.Setting("break-on-all-uncaught-exceptions", false);
    5454        this._assertionsBreakpointEnabledSetting = new WebInspector.Setting("break-on-assertions", false);
     55        this._asyncStackTraceDepthSetting = new WebInspector.Setting("async-stack-trace-depth", 200);
    5556
    5657        let specialBreakpointLocation = new WebInspector.SourceCodeLocation(null, Infinity, Infinity);
     
    9495        if (DebuggerAgent.setPauseOnAssertions)
    9596            DebuggerAgent.setPauseOnAssertions(this._assertionsBreakpointEnabledSetting.value);
     97
     98        // COMPATIBILITY (iOS 10): Debugger.setAsyncStackTraceDepth did not exist yet.
     99        if (DebuggerAgent.setAsyncStackTraceDepth)
     100            DebuggerAgent.setAsyncStackTraceDepth(this._asyncStackTraceDepthSetting.value);
    96101
    97102        this._ignoreBreakpointDisplayLocationDidChangeEvent = false;
     
    278283    }
    279284
     285    get asyncStackTraceDepth()
     286    {
     287        return this._asyncStackTraceDepthSetting.value;
     288    }
     289
     290    set asyncStackTraceDepth(x)
     291    {
     292        if (this._asyncStackTraceDepthSetting.value === x)
     293            return;
     294
     295        this._asyncStackTraceDepthSetting.value = x;
     296
     297        for (let target of WebInspector.targets)
     298            target.DebuggerAgent.setAsyncStackTraceDepth(this._asyncStackTraceDepthSetting.value);
     299    }
     300
    280301    pause()
    281302    {
     
    485506        DebuggerAgent.setPauseOnAssertions(this._assertionsBreakpointEnabledSetting.value);
    486507        DebuggerAgent.setPauseOnExceptions(this._breakOnExceptionsState);
     508        DebuggerAgent.setAsyncStackTraceDepth(this._asyncStackTraceDepthSetting.value);
    487509
    488510        if (this.paused)
     
    551573    }
    552574
    553     debuggerDidPause(target, callFramesPayload, reason, data)
     575    debuggerDidPause(target, callFramesPayload, reason, data, asyncStackTracePayload)
    554576    {
    555577        // Called from WebInspector.DebuggerObserver.
     
    600622        }
    601623
    602         targetData.updateForPause(callFrames, pauseReason, pauseData);
     624        let asyncStackTrace = WebInspector.StackTrace.fromPayload(target, asyncStackTracePayload);
     625        targetData.updateForPause(callFrames, pauseReason, pauseData, asyncStackTrace);
    603626
    604627        // Pause other targets because at least one target has paused.
  • trunk/Source/WebInspectorUI/UserInterface/Models/ConsoleMessage.js

    r208304 r209062  
    2626WebInspector.ConsoleMessage = class ConsoleMessage extends WebInspector.Object
    2727{
    28     constructor(target, source, level, message, type, url, line, column, repeatCount, parameters, stackTrace, request)
     28    constructor(target, source, level, message, type, url, line, column, repeatCount, parameters, callFrames, request)
    2929    {
    3030        super();
     
    5050        this._parameters = parameters;
    5151
    52         this._stackTrace = WebInspector.StackTrace.fromPayload(this._target, stackTrace || []);
     52        callFrames = callFrames || [];
     53        this._stackTrace = WebInspector.StackTrace.fromPayload(this._target, {callFrames});
    5354
    5455        this._request = request;
  • trunk/Source/WebInspectorUI/UserInterface/Models/DebuggerData.js

    r208725 r209062  
    3939        this._pauseData = null;
    4040        this._callFrames = [];
     41        this._asyncStackTrace = null;
    4142
    4243        this._scriptIdMap = new Map;
     
    5455    get pauseData() { return this._pauseData; }
    5556    get callFrames() { return this._callFrames; }
     57    get asyncStackTrace() { return this._asyncStackTrace; }
    5658
    5759    get scripts()
     
    123125    }
    124126
    125     updateForPause(callFrames, pauseReason, pauseData)
     127    updateForPause(callFrames, pauseReason, pauseData, asyncStackTrace)
    126128    {
    127129        this._paused = true;
     
    130132        this._pauseData = pauseData;
    131133        this._callFrames = callFrames;
     134        this._asyncStackTrace = asyncStackTrace;
    132135
    133136        // We paused, no need for auto-pausing.
     
    142145        this._pauseData = null;
    143146        this._callFrames = [];
     147        this._asyncStackTrace = null;
    144148
    145149        // We resumed, but may be auto-pausing.
  • trunk/Source/WebInspectorUI/UserInterface/Models/StackTrace.js

    r208304 r209062  
    2626WebInspector.StackTrace = class StackTrace extends WebInspector.Object
    2727{
    28     constructor(callFrames)
     28    constructor(callFrames, topCallFrameIsBoundary)
    2929    {
    3030        super();
     
    3333
    3434        this._callFrames = callFrames;
     35        this._topCallFrameIsBoundary = topCallFrameIsBoundary || false;
     36        this._parentStackTrace = null;
    3537    }
    3638
     
    3941    static fromPayload(target, payload)
    4042    {
    41         let callFrames = payload.map((x) => WebInspector.CallFrame.fromPayload(target, x));
    42         return new WebInspector.StackTrace(callFrames);
     43        let result = null;
     44        let previousStackTrace = null;
     45
     46        while (payload) {
     47            let callFrames = payload.callFrames.map((x) => WebInspector.CallFrame.fromPayload(target, x));
     48            let stackTrace = new WebInspector.StackTrace(callFrames, payload.topCallFrameIsBoundary);
     49            if (!result)
     50                result = stackTrace;
     51            if (previousStackTrace)
     52                previousStackTrace._parentStackTrace = stackTrace;
     53
     54            previousStackTrace = stackTrace;
     55            payload = payload.parentStackTrace;
     56        }
     57
     58        return result;
    4359    }
    4460
    4561    static fromString(target, stack)
    4662    {
    47         let payload = WebInspector.StackTrace._parseStackTrace(stack);
    48         return WebInspector.StackTrace.fromPayload(target, payload);
     63        let callFrames = WebInspector.StackTrace._parseStackTrace(stack);
     64        return WebInspector.StackTrace.fromPayload(target, {callFrames});
    4965    }
    5066
     
    152168        return null;
    153169    }
     170
     171    get topCallFrameIsBoundary() { return this._topCallFrameIsBoundary; }
     172    get parentStackTrace() { return this._parentStackTrace; }
    154173};
  • trunk/Source/WebInspectorUI/UserInterface/Protocol/DebuggerObserver.js

    r208304 r209062  
    6464    }
    6565
    66     paused(callFrames, reason, data)
     66    paused(callFrames, reason, data, asyncStackTrace)
    6767    {
    68         WebInspector.debuggerManager.debuggerDidPause(this.target, callFrames, reason, data);
     68        WebInspector.debuggerManager.debuggerDidPause(this.target, callFrames, reason, data, asyncStackTrace);
    6969    }
    7070
  • trunk/Source/WebInspectorUI/UserInterface/Views/CallFrameTreeElement.css

    r205930 r209062  
    4444    fill: var(--selected-foreground-color);
    4545}
     46
     47.tree-outline .item.call-frame.async-boundary {
     48    cursor: default;
     49    color: var(--text-color-gray-medium);
     50    padding-left: 0;
     51}
     52
     53.tree-outline .item.call-frame.async-boundary .icon {
     54    float: none;
     55    display: inline-block;
     56    margin-left: 0 !important;
     57}
     58
     59.tree-outline .item.call-frame.async-boundary::before,
     60.tree-outline .item.call-frame.async-boundary::after {
     61    content: "";
     62    display: inline-block;
     63    height: 0;
     64    margin-top: 2px;
     65    vertical-align: middle;
     66    border-bottom: solid 0.5px var(--border-color);
     67}
     68
     69.tree-outline .item.call-frame.async-boundary::after {
     70    width: 100%;
     71    margin-left: 2px;
     72}
     73
     74.tree-outline .item.call-frame.async-boundary::before {
     75    width: 20px;
     76    margin-right: 2px;
     77}
  • trunk/Source/WebInspectorUI/UserInterface/Views/CallFrameTreeElement.js

    r205930 r209062  
    2626WebInspector.CallFrameTreeElement = class CallFrameTreeElement extends WebInspector.GeneralTreeElement
    2727{
    28     constructor(callFrame)
     28    constructor(callFrame, isAsyncBoundaryCallFrame)
    2929    {
    3030        console.assert(callFrame instanceof WebInspector.CallFrame);
     
    3535        super(["call-frame", className], title, null, callFrame, false);
    3636
    37         if (!callFrame.nativeCode && callFrame.sourceCodeLocation) {
    38             let displayScriptURL = callFrame.sourceCodeLocation.displaySourceCode.url;
    39             if (displayScriptURL) {
    40                 this.subtitle = document.createElement("span");
    41                 callFrame.sourceCodeLocation.populateLiveDisplayLocationString(this.subtitle, "textContent");
    42                 // Set the tooltip on the entire tree element in onattach, once the element is created.
    43                 this.tooltipHandledSeparately = true;
    44             }
     37        this._callFrame = callFrame;
     38        this._isActiveCallFrame = false;
     39
     40         if (isAsyncBoundaryCallFrame) {
     41            this.addClassName("async-boundary");
     42            this.selectable = false;
     43         }
     44
     45        if (this._callFrame.nativeCode || !this._callFrame.sourceCodeLocation) {
     46            this.subtitle = "";
     47            return;
    4548        }
    4649
    47         this._callFrame = callFrame;
    48         this._isActiveCallFrame = false;
     50        let displayScriptURL = this._callFrame.sourceCodeLocation.displaySourceCode.url;
     51        if (displayScriptURL) {
     52            this.subtitle = document.createElement("span");
     53            this._callFrame.sourceCodeLocation.populateLiveDisplayLocationString(this.subtitle, "textContent");
     54            // Set the tooltip on the entire tree element in onattach, once the element is created.
     55            this.tooltipHandledSeparately = true;
     56        }
    4957    }
    5058
  • trunk/Source/WebInspectorUI/UserInterface/Views/DebuggerSidebarPanel.js

    r208746 r209062  
    629629                activeCallFrameTreeElement.select(true, true);
    630630        }
     631
     632        if (!targetData.asyncStackTrace)
     633            return;
     634
     635        let currentStackTrace = targetData.asyncStackTrace;
     636        while (currentStackTrace) {
     637            console.assert(currentStackTrace.callFrames.length, "StackTrace should have non-empty call frames array.");
     638            if (!currentStackTrace.callFrames.length)
     639                break;
     640
     641            let boundaryCallFrame;
     642            if (currentStackTrace.topCallFrameIsBoundary) {
     643                boundaryCallFrame = currentStackTrace.callFrames[0];
     644                console.assert(boundaryCallFrame.nativeCode && !boundaryCallFrame.sourceCodeLocation);
     645            } else {
     646                // Create a generic native CallFrame for the asynchronous boundary.
     647                const functionName = WebInspector.UIString("(async)");
     648                const nativeCode = true;
     649                boundaryCallFrame = new WebInspector.CallFrame(null, null, null, functionName, null, null, nativeCode);
     650            }
     651
     652            const isAsyncBoundaryCallFrame = true;
     653            this._singleThreadCallStackTreeOutline.appendChild(new WebInspector.CallFrameTreeElement(boundaryCallFrame, isAsyncBoundaryCallFrame));
     654
     655            let startIndex = currentStackTrace.topCallFrameIsBoundary ? 1 : 0;
     656            for (let i = startIndex; i < currentStackTrace.callFrames.length; ++i)
     657                this._singleThreadCallStackTreeOutline.appendChild(new WebInspector.CallFrameTreeElement(currentStackTrace.callFrames[i]));
     658
     659            currentStackTrace = currentStackTrace.parentStackTrace;
     660        }
    631661    }
    632662
     
    860890        if (treeElement instanceof WebInspector.CallFrameTreeElement) {
    861891            let callFrame = treeElement.callFrame;
    862             WebInspector.debuggerManager.activeCallFrame = callFrame;
    863             WebInspector.showSourceCodeLocation(callFrame.sourceCodeLocation);
     892            if (callFrame.id)
     893                WebInspector.debuggerManager.activeCallFrame = callFrame;
     894
     895            if (callFrame.sourceCodeLocation)
     896                WebInspector.showSourceCodeLocation(callFrame.sourceCodeLocation);
    864897            return;
    865898        }
  • trunk/Source/WebInspectorUI/UserInterface/Views/Variables.css

    r206005 r209062  
    5454    --console-prompt-min-height: 30px;
    5555
     56    --text-color-gray-medium: hsl(0, 0%, 50%);
    5657    --error-text-color: hsl(0, 86%, 47%);
    5758
Note: See TracChangeset for help on using the changeset viewer.