Changeset 209062 in webkit
- Timestamp:
- Nov 28, 2016 11:08:09 PM (7 years ago)
- Location:
- trunk
- Files:
-
- 2 added
- 24 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/LayoutTests/ChangeLog
r209024 r209062 1 2016-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 1 15 2016-11-28 Ryan Haddad <ryanhaddad@apple.com> 2 16 -
trunk/Source/JavaScriptCore/ChangeLog
r209058 r209062 1 2016-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 1 68 2016-11-28 Darin Adler <darin@apple.com> 2 69 -
trunk/Source/JavaScriptCore/inspector/ScriptCallFrame.cpp
r199852 r209062 60 60 } 61 61 62 bool ScriptCallFrame::isNative() const 63 { 64 return m_scriptName == "[native code]"; 65 } 66 62 67 Ref<Inspector::Protocol::Console::CallFrame> ScriptCallFrame::buildInspectorObject() const 63 68 { -
trunk/Source/JavaScriptCore/inspector/ScriptCallFrame.h
r204479 r209062 51 51 52 52 bool isEqual(const ScriptCallFrame&) const; 53 bool isNative() const; 53 54 54 55 Ref<Inspector::Protocol::Console::CallFrame> buildInspectorObject() const; -
trunk/Source/JavaScriptCore/inspector/ScriptCallStack.cpp
r194428 r209062 78 78 for (size_t i = 0; i < m_frames.size(); ++i) { 79 79 const ScriptCallFrame& frame = m_frames[i]; 80 if ( frame.sourceURL() != "[native code]")80 if (!frame.isNative()) 81 81 return &frame; 82 82 } … … 107 107 } 108 108 109 Ref<Inspector::Protocol:: Console::StackTrace> ScriptCallStack::buildInspectorArray() const109 Ref<Inspector::Protocol::Array<Inspector::Protocol::Console::CallFrame>> ScriptCallStack::buildInspectorArray() const 110 110 { 111 auto frames = Inspector::Protocol:: Console::StackTrace::create();111 auto frames = Inspector::Protocol::Array<Inspector::Protocol::Console::CallFrame>::create(); 112 112 for (size_t i = 0; i < m_frames.size(); i++) 113 113 frames->addItem(m_frames.at(i).buildInspectorObject()); -
trunk/Source/JavaScriptCore/inspector/ScriptCallStack.h
r204479 r209062 58 58 bool isEqual(ScriptCallStack*) const; 59 59 60 Ref<Inspector::Protocol:: Console::StackTrace> buildInspectorArray() const;60 Ref<Inspector::Protocol::Array<Inspector::Protocol::Console::CallFrame>> buildInspectorArray() const; 61 61 62 62 private: -
trunk/Source/JavaScriptCore/inspector/agents/InspectorDebuggerAgent.cpp
r208755 r209062 38 38 #include "JSCInlines.h" 39 39 #include "RegularExpression.h" 40 #include "ScriptCallStackFactory.h" 40 41 #include "ScriptDebugServer.h" 41 42 #include "ScriptObject.h" … … 114 115 m_listener->debuggerWasDisabled(); 115 116 117 clearAsyncStackTraceData(); 118 116 119 m_pauseOnAssertionFailures = false; 117 120 … … 132 135 { 133 136 return m_scriptDebugServer.breakpointsActive(); 137 } 138 139 void 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(); 134 153 } 135 154 … … 194 213 } 195 214 215 RefPtr<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 196 249 void InspectorDebuggerAgent::handleConsoleAssert(const String& message) 197 250 { 198 251 if (m_pauseOnAssertionFailures) 199 252 breakProgram(DebuggerFrontendDispatcher::Reason::Assert, buildAssertPauseReason(message)); 253 } 254 255 void 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 274 void 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 283 void 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 301 void 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; 200 311 } 201 312 … … 883 994 m_enablePauseWhenIdle = false; 884 995 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); 886 1001 887 1002 m_javaScriptPauseScheduled = false; … … 986 1101 clearDebuggerBreakpointState(); 987 1102 1103 clearAsyncStackTraceData(); 1104 988 1105 m_frontendDispatcher->globalObjectCleared(); 989 1106 } … … 1013 1130 } 1014 1131 1132 void InspectorDebuggerAgent::clearAsyncStackTraceData() 1133 { 1134 m_asyncCallIdentifierToData.clear(); 1135 m_currentAsyncCallIdentifier = std::nullopt; 1136 } 1137 1138 void 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 1148 void 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 1015 1165 } // namespace Inspector -
trunk/Source/JavaScriptCore/inspector/agents/InspectorDebuggerAgent.h
r208725 r209062 36 36 #include "inspector/InspectorAgentBase.h" 37 37 #include "inspector/ScriptBreakpoint.h" 38 #include "inspector/ScriptCallStack.h" 38 39 #include "inspector/ScriptDebugListener.h" 39 40 #include <wtf/Forward.h> … … 49 50 class InspectorObject; 50 51 class ScriptDebugServer; 52 struct AsyncCallData; 51 53 typedef String ErrorString; 52 54 … … 64 66 void enable(ErrorString&) final; 65 67 void disable(ErrorString&) final; 68 void setAsyncStackTraceDepth(ErrorString&, int depth) final; 66 69 void setBreakpointsActive(ErrorString&, bool active) final; 67 70 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; … … 90 93 void handleConsoleAssert(const String& message); 91 94 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 92 100 void schedulePauseOnNextStatement(DebuggerFrontendDispatcher::Reason breakReason, RefPtr<InspectorObject>&& data); 93 101 void cancelPauseOnNextStatement(); … … 143 151 void clearBreakDetails(); 144 152 void clearExceptionValue(); 153 void clearAsyncStackTraceData(); 145 154 146 155 enum class ShouldDispatchResumed { No, WhenIdle, WhenContinued }; … … 154 163 bool breakpointActionsFromProtocol(ErrorString&, RefPtr<InspectorArray>& actions, BreakpointActions* result); 155 164 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 156 171 typedef HashMap<JSC::SourceID, Script> ScriptsMap; 157 172 typedef HashMap<String, Vector<JSC::BreakpointID>> BreakpointIdentifierToDebugServerBreakpointIDsMap; 158 173 typedef HashMap<String, RefPtr<InspectorObject>> BreakpointIdentifierToBreakpointMap; 159 174 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 }; 160 190 161 191 InjectedScriptManager& m_injectedScriptManager; … … 175 205 ShouldDispatchResumed m_conditionToDispatchResumed { ShouldDispatchResumed::No }; 176 206 bool m_enablePauseWhenIdle { false }; 207 HashMap<AsyncCallIdentifier, AsyncCallData> m_asyncCallIdentifierToData; 208 std::optional<AsyncCallIdentifier> m_currentAsyncCallIdentifier { std::nullopt }; 177 209 bool m_enabled { false }; 178 210 bool m_javaScriptPauseScheduled { false }; … … 181 213 bool m_pauseOnAssertionFailures { false }; 182 214 bool m_registeredIdleCallback { false }; 215 int m_asyncStackTraceDepth { 0 }; 183 216 }; 184 217 -
trunk/Source/JavaScriptCore/inspector/protocol/Console.json
r199852 r209062 17 17 { "name": "repeatCount", "type": "integer", "optional": true, "description": "Repeat count for repeated messages." }, 18 18 { "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." }, 20 20 { "name": "networkRequestId", "$ref": "Network.RequestId", "optional": true, "description": "Identifier of the network request associated with this message." } 21 21 ] … … 35 35 { 36 36 "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 ] 40 44 } 41 45 ], -
trunk/Source/JavaScriptCore/inspector/protocol/Debugger.json
r208725 r209062 135 135 "name": "disable", 136 136 "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 ] 137 144 }, 138 145 { … … 326 333 { "name": "callFrames", "type": "array", "items": { "$ref": "CallFrame" }, "description": "Call stack the virtual machine stopped on." }, 327 334 { "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." } 329 337 ], 330 338 "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 118 118 "properties": [ 119 119 { "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." }, 121 121 { "name": "url", "type": "string", "optional": true, "description": "Initiator URL, set for Parser type only." }, 122 122 { "name": "lineNumber", "type": "number", "optional": true, "description": "Initiator line number, set for Parser type only." } -
trunk/Source/WebCore/ChangeLog
r209061 r209062 1 2016-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 1 28 2016-11-28 Jiewen Tan <jiewen_tan@apple.com> 2 29 -
trunk/Source/WebCore/inspector/InspectorInstrumentation.cpp
r208985 r209062 84 84 static const char* const timerFiredEventName = "timerFired"; 85 85 86 enum AsyncCallType { 87 AsyncCallTypeRequestAnimationFrame, 88 AsyncCallTypeTimer, 89 }; 90 86 91 namespace { 87 92 static HashSet<InstrumentingAgents*>* s_instrumentingAgentsSet = nullptr; … … 89 94 90 95 int InspectorInstrumentation::s_frontendCounter = 0; 96 97 static 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 } 91 107 92 108 static Frame* frameForScriptExecutionContext(ScriptExecutionContext* context) … … 324 340 { 325 341 pauseOnNativeEventIfNeeded(instrumentingAgents, false, setTimerEventName, true); 342 didScheduleAsyncCall(instrumentingAgents, AsyncCallTypeTimer, timerId, context, singleShot); 343 326 344 if (InspectorTimelineAgent* timelineAgent = instrumentingAgents.inspectorTimelineAgent()) 327 345 timelineAgent->didInstallTimer(timerId, timeout, singleShot, frameForScriptExecutionContext(context)); … … 331 349 { 332 350 pauseOnNativeEventIfNeeded(instrumentingAgents, false, clearTimerEventName, true); 351 352 if (InspectorDebuggerAgent* debuggerAgent = instrumentingAgents.inspectorDebuggerAgent()) 353 debuggerAgent->didCancelAsyncCall(AsyncCallTypeTimer, timerId); 333 354 if (InspectorTimelineAgent* timelineAgent = instrumentingAgents.inspectorTimelineAgent()) 334 355 timelineAgent->didRemoveTimer(timerId, frameForScriptExecutionContext(context)); … … 424 445 pauseOnNativeEventIfNeeded(instrumentingAgents, false, timerFiredEventName, false); 425 446 447 if (InspectorDebuggerAgent* debuggerAgent = instrumentingAgents.inspectorDebuggerAgent()) 448 debuggerAgent->willDispatchAsyncCall(AsyncCallTypeTimer, timerId); 449 426 450 int timelineAgentId = 0; 427 451 if (InspectorTimelineAgent* timelineAgent = instrumentingAgents.inspectorTimelineAgent()) { … … 434 458 void InspectorInstrumentation::didFireTimerImpl(const InspectorInstrumentationCookie& cookie) 435 459 { 460 if (InspectorDebuggerAgent* debuggerAgent = cookie.instrumentingAgents()->inspectorDebuggerAgent()) 461 debuggerAgent->didDispatchAsyncCall(); 436 462 if (InspectorTimelineAgent* timelineAgent = retrieveTimelineAgent(cookie)) 437 463 timelineAgent->didFireTimer(); … … 1140 1166 { 1141 1167 pauseOnNativeEventIfNeeded(instrumentingAgents, false, requestAnimationFrameEventName, true); 1168 didScheduleAsyncCall(instrumentingAgents, AsyncCallTypeRequestAnimationFrame, callbackId, *frame->document(), true); 1142 1169 1143 1170 if (InspectorTimelineAgent* timelineAgent = instrumentingAgents.inspectorTimelineAgent()) … … 1149 1176 pauseOnNativeEventIfNeeded(instrumentingAgents, false, cancelAnimationFrameEventName, true); 1150 1177 1178 if (InspectorDebuggerAgent* debuggerAgent = instrumentingAgents.inspectorDebuggerAgent()) 1179 debuggerAgent->didCancelAsyncCall(AsyncCallTypeRequestAnimationFrame, callbackId); 1151 1180 if (InspectorTimelineAgent* timelineAgent = instrumentingAgents.inspectorTimelineAgent()) 1152 1181 timelineAgent->didCancelAnimationFrame(callbackId, frame); … … 1156 1185 { 1157 1186 pauseOnNativeEventIfNeeded(instrumentingAgents, false, animationFrameFiredEventName, false); 1187 1188 if (InspectorDebuggerAgent* debuggerAgent = instrumentingAgents.inspectorDebuggerAgent()) 1189 debuggerAgent->willDispatchAsyncCall(AsyncCallTypeRequestAnimationFrame, callbackId); 1158 1190 1159 1191 int timelineAgentId = 0; … … 1167 1199 void InspectorInstrumentation::didFireAnimationFrameImpl(const InspectorInstrumentationCookie& cookie) 1168 1200 { 1201 if (InspectorDebuggerAgent* debuggerAgent = cookie.instrumentingAgents()->inspectorDebuggerAgent()) 1202 debuggerAgent->didDispatchAsyncCall(); 1169 1203 if (InspectorTimelineAgent* timelineAgent = retrieveTimelineAgent(cookie)) 1170 1204 timelineAgent->didFireAnimationFrame(); -
trunk/Source/WebInspectorUI/ChangeLog
r208895 r209062 1 2016-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 1 72 2016-11-18 Matt Baker <mattbaker@apple.com> 2 73 -
trunk/Source/WebInspectorUI/Localizations/en.lproj/localizedStrings.js
r208783 r209062 43 43 localizedStrings["(Tail Call)"] = "(Tail Call)"; 44 44 localizedStrings["(anonymous function)"] = "(anonymous function)"; 45 localizedStrings["(async)"] = "(async)"; 45 46 localizedStrings["(many)"] = "(many)"; 46 47 localizedStrings["(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 53 53 this._allUncaughtExceptionsBreakpointEnabledSetting = new WebInspector.Setting("break-on-all-uncaught-exceptions", false); 54 54 this._assertionsBreakpointEnabledSetting = new WebInspector.Setting("break-on-assertions", false); 55 this._asyncStackTraceDepthSetting = new WebInspector.Setting("async-stack-trace-depth", 200); 55 56 56 57 let specialBreakpointLocation = new WebInspector.SourceCodeLocation(null, Infinity, Infinity); … … 94 95 if (DebuggerAgent.setPauseOnAssertions) 95 96 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); 96 101 97 102 this._ignoreBreakpointDisplayLocationDidChangeEvent = false; … … 278 283 } 279 284 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 280 301 pause() 281 302 { … … 485 506 DebuggerAgent.setPauseOnAssertions(this._assertionsBreakpointEnabledSetting.value); 486 507 DebuggerAgent.setPauseOnExceptions(this._breakOnExceptionsState); 508 DebuggerAgent.setAsyncStackTraceDepth(this._asyncStackTraceDepthSetting.value); 487 509 488 510 if (this.paused) … … 551 573 } 552 574 553 debuggerDidPause(target, callFramesPayload, reason, data )575 debuggerDidPause(target, callFramesPayload, reason, data, asyncStackTracePayload) 554 576 { 555 577 // Called from WebInspector.DebuggerObserver. … … 600 622 } 601 623 602 targetData.updateForPause(callFrames, pauseReason, pauseData); 624 let asyncStackTrace = WebInspector.StackTrace.fromPayload(target, asyncStackTracePayload); 625 targetData.updateForPause(callFrames, pauseReason, pauseData, asyncStackTrace); 603 626 604 627 // Pause other targets because at least one target has paused. -
trunk/Source/WebInspectorUI/UserInterface/Models/ConsoleMessage.js
r208304 r209062 26 26 WebInspector.ConsoleMessage = class ConsoleMessage extends WebInspector.Object 27 27 { 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) 29 29 { 30 30 super(); … … 50 50 this._parameters = parameters; 51 51 52 this._stackTrace = WebInspector.StackTrace.fromPayload(this._target, stackTrace || []); 52 callFrames = callFrames || []; 53 this._stackTrace = WebInspector.StackTrace.fromPayload(this._target, {callFrames}); 53 54 54 55 this._request = request; -
trunk/Source/WebInspectorUI/UserInterface/Models/DebuggerData.js
r208725 r209062 39 39 this._pauseData = null; 40 40 this._callFrames = []; 41 this._asyncStackTrace = null; 41 42 42 43 this._scriptIdMap = new Map; … … 54 55 get pauseData() { return this._pauseData; } 55 56 get callFrames() { return this._callFrames; } 57 get asyncStackTrace() { return this._asyncStackTrace; } 56 58 57 59 get scripts() … … 123 125 } 124 126 125 updateForPause(callFrames, pauseReason, pauseData )127 updateForPause(callFrames, pauseReason, pauseData, asyncStackTrace) 126 128 { 127 129 this._paused = true; … … 130 132 this._pauseData = pauseData; 131 133 this._callFrames = callFrames; 134 this._asyncStackTrace = asyncStackTrace; 132 135 133 136 // We paused, no need for auto-pausing. … … 142 145 this._pauseData = null; 143 146 this._callFrames = []; 147 this._asyncStackTrace = null; 144 148 145 149 // We resumed, but may be auto-pausing. -
trunk/Source/WebInspectorUI/UserInterface/Models/StackTrace.js
r208304 r209062 26 26 WebInspector.StackTrace = class StackTrace extends WebInspector.Object 27 27 { 28 constructor(callFrames )28 constructor(callFrames, topCallFrameIsBoundary) 29 29 { 30 30 super(); … … 33 33 34 34 this._callFrames = callFrames; 35 this._topCallFrameIsBoundary = topCallFrameIsBoundary || false; 36 this._parentStackTrace = null; 35 37 } 36 38 … … 39 41 static fromPayload(target, payload) 40 42 { 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; 43 59 } 44 60 45 61 static fromString(target, stack) 46 62 { 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}); 49 65 } 50 66 … … 152 168 return null; 153 169 } 170 171 get topCallFrameIsBoundary() { return this._topCallFrameIsBoundary; } 172 get parentStackTrace() { return this._parentStackTrace; } 154 173 }; -
trunk/Source/WebInspectorUI/UserInterface/Protocol/DebuggerObserver.js
r208304 r209062 64 64 } 65 65 66 paused(callFrames, reason, data )66 paused(callFrames, reason, data, asyncStackTrace) 67 67 { 68 WebInspector.debuggerManager.debuggerDidPause(this.target, callFrames, reason, data );68 WebInspector.debuggerManager.debuggerDidPause(this.target, callFrames, reason, data, asyncStackTrace); 69 69 } 70 70 -
trunk/Source/WebInspectorUI/UserInterface/Views/CallFrameTreeElement.css
r205930 r209062 44 44 fill: var(--selected-foreground-color); 45 45 } 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 26 26 WebInspector.CallFrameTreeElement = class CallFrameTreeElement extends WebInspector.GeneralTreeElement 27 27 { 28 constructor(callFrame )28 constructor(callFrame, isAsyncBoundaryCallFrame) 29 29 { 30 30 console.assert(callFrame instanceof WebInspector.CallFrame); … … 35 35 super(["call-frame", className], title, null, callFrame, false); 36 36 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; 45 48 } 46 49 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 } 49 57 } 50 58 -
trunk/Source/WebInspectorUI/UserInterface/Views/DebuggerSidebarPanel.js
r208746 r209062 629 629 activeCallFrameTreeElement.select(true, true); 630 630 } 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 } 631 661 } 632 662 … … 860 890 if (treeElement instanceof WebInspector.CallFrameTreeElement) { 861 891 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); 864 897 return; 865 898 } -
trunk/Source/WebInspectorUI/UserInterface/Views/Variables.css
r206005 r209062 54 54 --console-prompt-min-height: 30px; 55 55 56 --text-color-gray-medium: hsl(0, 0%, 50%); 56 57 --error-text-color: hsl(0, 86%, 47%); 57 58
Note: See TracChangeset
for help on using the changeset viewer.