Diff
Modified: trunk/LayoutTests/ChangeLog (220298 => 220299)
--- trunk/LayoutTests/ChangeLog 2017-08-04 22:03:54 UTC (rev 220298)
+++ trunk/LayoutTests/ChangeLog 2017-08-04 22:12:40 UTC (rev 220299)
@@ -1,3 +1,18 @@
+2017-08-04 Matt Baker <[email protected]>
+
+ Web Inspector: capture async stack trace when workers/main context posts a message
+ https://bugs.webkit.org/show_bug.cgi?id=167084
+ <rdar://problem/30033673>
+
+ Reviewed by Brian Burg.
+
+ Add a test to check for asynchronous stack trace data when the debugger
+ pauses inside a MessageEvent handler.
+
+ * inspector/debugger/async-stack-trace-expected.txt:
+ * inspector/debugger/async-stack-trace.html:
+ * inspector/debugger/resources/postMessage-echo.html: Added.
+
2017-08-04 Chris Dumez <[email protected]>
LayoutTest imported/w3c/web-platform-tests/beacon/beacon-basic-string.html is a flaky failure (harness timeout)
Modified: trunk/LayoutTests/inspector/debugger/async-stack-trace-expected.txt (220298 => 220299)
--- trunk/LayoutTests/inspector/debugger/async-stack-trace-expected.txt 2017-08-04 22:03:54 UTC (rev 220298)
+++ trunk/LayoutTests/inspector/debugger/async-stack-trace-expected.txt 2017-08-04 22:12:40 UTC (rev 220299)
@@ -1,6 +1,9 @@
+CONSOLE MESSAGE: line 55: Unable to post message to http://example.com. Recipient has origin .
+
Tests for async stack traces.
+
== Running test suite: AsyncStackTrace
-- Running test case: CheckAsyncStackTrace.RequestAnimationFrame
PAUSE #1
@@ -76,6 +79,21 @@
4: --- addEventListener ---
5: [F] testAddEventListener
6: [P] Global Code
+
+-- Running test case: CheckAsyncStackTrace.PostMessage
+PAUSE #1
+CALL STACK:
+0: [F] pauseThenFinishTest
+1: [F] postMessageFired
+ASYNC CALL STACK:
+2: --- postMessage ---
+3: [F] messageReceived
+4: --- postMessage ---
+5: [F] testPostMessage
+6: [P] Global Code
+
+-- Running test case: ShouldNotPauseForFailedPostMessage
+PASS: Should not pause for failed post message.
-- Running test setup.
Save DebuggerManager.asyncStackTraceDepth
Modified: trunk/LayoutTests/inspector/debugger/async-stack-trace.html (220298 => 220299)
--- trunk/LayoutTests/inspector/debugger/async-stack-trace.html 2017-08-04 22:03:54 UTC (rev 220298)
+++ trunk/LayoutTests/inspector/debugger/async-stack-trace.html 2017-08-04 22:12:40 UTC (rev 220299)
@@ -50,6 +50,23 @@
document.body.click();
}
+function testPostMessage(targetOrigin = "*") {
+ let childFrame = document.getElementById("postMessageTestFrame");
+ childFrame.contentWindow.postMessage("<message>", targetOrigin);
+
+ window.addEventListener("message", function postMessageFired() {
+ window.removeEventListener("message", postMessageFired);
+ pauseThenFinishTest();
+ });
+}
+
+function testFailPostMessage() {
+ testPostMessage("http://example.com");
+ setTimeout(() => {
+ TestPage.dispatchEventToFrontend("AfterTestFunction");
+ }, 0);
+}
+
function recursiveCallThenTest(testFunction, depth) {
if (depth) {
recursiveCallThenTest(testFunction, depth - 1);
@@ -79,16 +96,17 @@
name: `CheckAsyncStackTrace.${name}`,
test(resolve, reject) {
let pauseCount = 0;
- function handlePaused() {
+ function debuggerPaused() {
InspectorTest.log(`PAUSE #${++pauseCount}`);
logActiveStackTrace();
WI.debuggerManager.resume();
}
- WI.debuggerManager.addEventListener(WI.DebuggerManager.Event.Paused, handlePaused);
+ WI.debuggerManager.addEventListener(WI.DebuggerManager.Event.Paused, debuggerPaused);
- InspectorTest.singleFireEventListener("AfterTestFunction", () => {
- WI.debuggerManager.removeEventListener(WI.DebuggerManager.Event.Paused, handlePaused);
+ InspectorTest.awaitEvent("AfterTestFunction")
+ .then(() => {
+ WI.debuggerManager.removeEventListener(WI.DebuggerManager.Event.Paused, debuggerPaused);
resolve();
});
@@ -103,7 +121,30 @@
addSimpleTestCase("ChainedRequestAnimationFrame", "testChainedRequestAnimationFrame()");
addSimpleTestCase("ReferenceCounting", "testReferenceCounting()");
addSimpleTestCase("AddEventListener", "testAddEventListener()");
+ addSimpleTestCase("PostMessage", "testPostMessage()");
+ suite.addTestCase({
+ name: "ShouldNotPauseForFailedPostMessage",
+ test(resolve, reject) {
+ function debuggerPaused() {
+ WI.debuggerManager.resume();
+ InspectorTest.fail("Should not pause.");
+ reject();
+ }
+
+ WI.debuggerManager.addEventListener(WI.DebuggerManager.Event.Paused, debuggerPaused);
+
+ InspectorTest.awaitEvent("AfterTestFunction")
+ .then(() => {
+ WI.debuggerManager.removeEventListener(WI.DebuggerManager.Event.Paused, debuggerPaused);
+ InspectorTest.pass("Should not pause for failed post message.");
+ resolve();
+ });
+
+ InspectorTest.evaluateInPage("testFailPostMessage()");
+ }
+ });
+
function setup(resolve) {
InspectorTest.log("Save DebuggerManager.asyncStackTraceDepth");
this.savedCallStackDepth = WI.debuggerManager.asyncStackTraceDepth;
@@ -190,5 +231,6 @@
</head>
<body _onload_="runTest()">
<p>Tests for async stack traces.</p>
+<iframe id="postMessageTestFrame" src=""
</body>
</html>
Added: trunk/LayoutTests/inspector/debugger/resources/postMessage-echo.html (0 => 220299)
--- trunk/LayoutTests/inspector/debugger/resources/postMessage-echo.html (rev 0)
+++ trunk/LayoutTests/inspector/debugger/resources/postMessage-echo.html 2017-08-04 22:12:40 UTC (rev 220299)
@@ -0,0 +1,6 @@
+<script>
+window.addEventListener("message", function messageReceived(event) {
+ let echo = `iFrame postMessage echo: ${event.data}`;
+ parent.postMessage(echo, "*");
+});
+</script>
Modified: trunk/LayoutTests/inspector/dom-debugger/dom-breakpoints.html (220298 => 220299)
--- trunk/LayoutTests/inspector/dom-debugger/dom-breakpoints.html 2017-08-04 22:03:54 UTC (rev 220298)
+++ trunk/LayoutTests/inspector/dom-debugger/dom-breakpoints.html 2017-08-04 22:12:40 UTC (rev 220299)
@@ -36,18 +36,6 @@
resolve();
}
- function awaitEvaluateInPage(_expression_) {
- return new Promise((resolve, reject) => {
- InspectorTest.log("Wait for evaluate in page to return.");
- InspectorTest.evaluateInPage(_expression_, (error) => {
- if (error)
- reject(error);
-
- resolve();
- });
- });
- }
-
function rejectOnPause() {
return new Promise((resolve, reject) => {
WI.debuggerManager.awaitEvent(WI.DebuggerManager.Event.Paused)
Modified: trunk/Source/_javascript_Core/ChangeLog (220298 => 220299)
--- trunk/Source/_javascript_Core/ChangeLog 2017-08-04 22:03:54 UTC (rev 220298)
+++ trunk/Source/_javascript_Core/ChangeLog 2017-08-04 22:12:40 UTC (rev 220299)
@@ -1,3 +1,14 @@
+2017-08-04 Matt Baker <[email protected]>
+
+ Web Inspector: capture async stack trace when workers/main context posts a message
+ https://bugs.webkit.org/show_bug.cgi?id=167084
+ <rdar://problem/30033673>
+
+ Reviewed by Brian Burg.
+
+ * inspector/agents/InspectorDebuggerAgent.h:
+ Add `PostMessage` async call type.
+
2017-08-04 Mark Lam <[email protected]>
Move DFG::OSRExitCompiler methods into DFG::OSRExit [step 1].
Modified: trunk/Source/_javascript_Core/inspector/agents/InspectorDebuggerAgent.h (220298 => 220299)
--- trunk/Source/_javascript_Core/inspector/agents/InspectorDebuggerAgent.h 2017-08-04 22:03:54 UTC (rev 220298)
+++ trunk/Source/_javascript_Core/inspector/agents/InspectorDebuggerAgent.h 2017-08-04 22:12:40 UTC (rev 220299)
@@ -94,6 +94,7 @@
enum class AsyncCallType {
DOMTimer,
EventListener,
+ PostMessage,
RequestAnimationFrame,
};
Modified: trunk/Source/WebCore/ChangeLog (220298 => 220299)
--- trunk/Source/WebCore/ChangeLog 2017-08-04 22:03:54 UTC (rev 220298)
+++ trunk/Source/WebCore/ChangeLog 2017-08-04 22:12:40 UTC (rev 220299)
@@ -1,3 +1,40 @@
+2017-08-04 Matt Baker <[email protected]>
+
+ Web Inspector: capture async stack trace when workers/main context posts a message
+ https://bugs.webkit.org/show_bug.cgi?id=167084
+ <rdar://problem/30033673>
+
+ Reviewed by Brian Burg.
+
+ Add instrumentation to DOMWindow to support showing asynchronous
+ stack traces when the debugger pauses in a MessageEvent handler.
+
+ Test: inspector/debugger/async-stack-trace.html
+
+ * inspector/InspectorInstrumentation.cpp:
+ (WebCore::InspectorInstrumentation::didPostMessageImpl):
+ (WebCore::InspectorInstrumentation::didFailPostMessageImpl):
+ (WebCore::InspectorInstrumentation::willDispatchPostMessageImpl):
+ (WebCore::InspectorInstrumentation::didDispatchPostMessageImpl):
+
+ * inspector/InspectorInstrumentation.h:
+ (WebCore::InspectorInstrumentation::didPostMessage):
+ (WebCore::InspectorInstrumentation::didFailPostMessage):
+ (WebCore::InspectorInstrumentation::willDispatchPostMessage):
+ (WebCore::InspectorInstrumentation::didDispatchPostMessage):
+
+ * inspector/PageDebuggerAgent.cpp:
+ (WebCore::PageDebuggerAgent::didClearAsyncStackTraceData):
+ (WebCore::PageDebuggerAgent::didPostMessage):
+ (WebCore::PageDebuggerAgent::didFailPostMessage):
+ (WebCore::PageDebuggerAgent::willDispatchPostMessage):
+ (WebCore::PageDebuggerAgent::didDispatchPostMessage):
+ * inspector/PageDebuggerAgent.h:
+
+ * page/DOMWindow.cpp:
+ (WebCore::DOMWindow::postMessage):
+ (WebCore::DOMWindow::postMessageTimerFired):
+
2017-08-04 Devin Rousso <[email protected]>
Web Inspector: add source view for WebGL shader programs
Modified: trunk/Source/WebCore/inspector/InspectorInstrumentation.cpp (220298 => 220299)
--- trunk/Source/WebCore/inspector/InspectorInstrumentation.cpp 2017-08-04 22:03:54 UTC (rev 220298)
+++ trunk/Source/WebCore/inspector/InspectorInstrumentation.cpp 2017-08-04 22:12:40 UTC (rev 220299)
@@ -363,6 +363,30 @@
pageDebuggerAgent->willRemoveEventListener(target, eventType, listener, capture);
}
+void InspectorInstrumentation::didPostMessageImpl(InstrumentingAgents& instrumentingAgents, const TimerBase& timer, JSC::ExecState& state)
+{
+ if (PageDebuggerAgent* pageDebuggerAgent = instrumentingAgents.pageDebuggerAgent())
+ pageDebuggerAgent->didPostMessage(timer, state);
+}
+
+void InspectorInstrumentation::didFailPostMessageImpl(InstrumentingAgents& instrumentingAgents, const TimerBase& timer)
+{
+ if (PageDebuggerAgent* pageDebuggerAgent = instrumentingAgents.pageDebuggerAgent())
+ pageDebuggerAgent->didFailPostMessage(timer);
+}
+
+void InspectorInstrumentation::willDispatchPostMessageImpl(InstrumentingAgents& instrumentingAgents, const TimerBase& timer)
+{
+ if (PageDebuggerAgent* pageDebuggerAgent = instrumentingAgents.pageDebuggerAgent())
+ pageDebuggerAgent->willDispatchPostMessage(timer);
+}
+
+void InspectorInstrumentation::didDispatchPostMessageImpl(InstrumentingAgents& instrumentingAgents, const TimerBase& timer)
+{
+ if (PageDebuggerAgent* pageDebuggerAgent = instrumentingAgents.pageDebuggerAgent())
+ pageDebuggerAgent->didDispatchPostMessage(timer);
+}
+
InspectorInstrumentationCookie InspectorInstrumentation::willCallFunctionImpl(InstrumentingAgents& instrumentingAgents, const String& scriptName, int scriptLine, ScriptExecutionContext* context)
{
int timelineAgentId = 0;
Modified: trunk/Source/WebCore/inspector/InspectorInstrumentation.h (220298 => 220299)
--- trunk/Source/WebCore/inspector/InspectorInstrumentation.h 2017-08-04 22:03:54 UTC (rev 220298)
+++ trunk/Source/WebCore/inspector/InspectorInstrumentation.h 2017-08-04 22:12:40 UTC (rev 220299)
@@ -85,6 +85,7 @@
class ScriptExecutionContext;
class SecurityOrigin;
class ShadowRoot;
+class TimerBase;
class URL;
#if ENABLE(WEBGL)
class WebGLProgram;
@@ -136,6 +137,11 @@
static void didInstallTimer(ScriptExecutionContext&, int timerId, Seconds timeout, bool singleShot);
static void didRemoveTimer(ScriptExecutionContext&, int timerId);
+ static void didPostMessage(Frame&, TimerBase&, JSC::ExecState&);
+ static void didFailPostMessage(Frame&, TimerBase&);
+ static void willDispatchPostMessage(Frame&, TimerBase&);
+ static void didDispatchPostMessage(Frame&, TimerBase&);
+
static InspectorInstrumentationCookie willCallFunction(ScriptExecutionContext*, const String& scriptName, int scriptLine);
static void didCallFunction(const InspectorInstrumentationCookie&, ScriptExecutionContext*);
static void didAddEventListener(EventTarget&, const AtomicString& eventType);
@@ -302,6 +308,11 @@
static void didInstallTimerImpl(InstrumentingAgents&, int timerId, Seconds timeout, bool singleShot, ScriptExecutionContext&);
static void didRemoveTimerImpl(InstrumentingAgents&, int timerId, ScriptExecutionContext&);
+ static void didPostMessageImpl(InstrumentingAgents&, const TimerBase&, JSC::ExecState&);
+ static void didFailPostMessageImpl(InstrumentingAgents&, const TimerBase&);
+ static void willDispatchPostMessageImpl(InstrumentingAgents&, const TimerBase&);
+ static void didDispatchPostMessageImpl(InstrumentingAgents&, const TimerBase&);
+
static InspectorInstrumentationCookie willCallFunctionImpl(InstrumentingAgents&, const String& scriptName, int scriptLine, ScriptExecutionContext*);
static void didCallFunctionImpl(const InspectorInstrumentationCookie&, ScriptExecutionContext*);
static void didAddEventListenerImpl(InstrumentingAgents&, EventTarget&, const AtomicString& eventType);
@@ -669,6 +680,34 @@
willRemoveEventListenerImpl(*instrumentingAgents, target, eventType, listener, capture);
}
+inline void InspectorInstrumentation::didPostMessage(Frame& frame, TimerBase& timer, JSC::ExecState& state)
+{
+ FAST_RETURN_IF_NO_FRONTENDS(void());
+ if (InstrumentingAgents* instrumentingAgents = instrumentingAgentsForFrame(frame))
+ didPostMessageImpl(*instrumentingAgents, timer, state);
+}
+
+inline void InspectorInstrumentation::didFailPostMessage(Frame& frame, TimerBase& timer)
+{
+ FAST_RETURN_IF_NO_FRONTENDS(void());
+ if (InstrumentingAgents* instrumentingAgents = instrumentingAgentsForFrame(frame))
+ didFailPostMessageImpl(*instrumentingAgents, timer);
+}
+
+inline void InspectorInstrumentation::willDispatchPostMessage(Frame& frame, TimerBase& timer)
+{
+ FAST_RETURN_IF_NO_FRONTENDS(void());
+ if (InstrumentingAgents* instrumentingAgents = instrumentingAgentsForFrame(frame))
+ willDispatchPostMessageImpl(*instrumentingAgents, timer);
+}
+
+inline void InspectorInstrumentation::didDispatchPostMessage(Frame& frame, TimerBase& timer)
+{
+ FAST_RETURN_IF_NO_FRONTENDS(void());
+ if (InstrumentingAgents* instrumentingAgents = instrumentingAgentsForFrame(frame))
+ didDispatchPostMessageImpl(*instrumentingAgents, timer);
+}
+
inline InspectorInstrumentationCookie InspectorInstrumentation::willCallFunction(ScriptExecutionContext* context, const String& scriptName, int scriptLine)
{
FAST_RETURN_IF_NO_FRONTENDS(InspectorInstrumentationCookie());
Modified: trunk/Source/WebCore/inspector/PageDebuggerAgent.cpp (220298 => 220299)
--- trunk/Source/WebCore/inspector/PageDebuggerAgent.cpp 2017-08-04 22:03:54 UTC (rev 220298)
+++ trunk/Source/WebCore/inspector/PageDebuggerAgent.cpp 2017-08-04 22:12:40 UTC (rev 220299)
@@ -45,6 +45,7 @@
#include "PageScriptDebugServer.h"
#include "ScriptExecutionContext.h"
#include "ScriptState.h"
+#include "Timer.h"
#include <inspector/InjectedScript.h>
#include <inspector/InjectedScriptManager.h>
#include <inspector/ScriptCallStack.h>
@@ -99,7 +100,9 @@
void PageDebuggerAgent::didClearAsyncStackTraceData()
{
m_registeredEventListeners.clear();
+ m_postMessageTimers.clear();
m_nextEventListenerIdentifier = 1;
+ m_nextPostMessageIdentifier = 1;
}
void PageDebuggerAgent::muteConsole()
@@ -227,4 +230,51 @@
didCancelAsyncCall(InspectorDebuggerAgent::AsyncCallType::RequestAnimationFrame, callbackId);
}
+void PageDebuggerAgent::didPostMessage(const TimerBase& timer, JSC::ExecState& state)
+{
+ if (!breakpointsActive())
+ return;
+
+ if (m_postMessageTimers.contains(&timer)) {
+ ASSERT_NOT_REACHED();
+ return;
+ }
+
+ int postMessageIdentifier = m_nextPostMessageIdentifier++;
+ m_postMessageTimers.set(&timer, postMessageIdentifier);
+
+ didScheduleAsyncCall(&state, InspectorDebuggerAgent::AsyncCallType::PostMessage, postMessageIdentifier, true);
+}
+
+void PageDebuggerAgent::didFailPostMessage(const TimerBase& timer)
+{
+ auto it = m_postMessageTimers.find(&timer);
+ if (it == m_postMessageTimers.end())
+ return;
+
+ didCancelAsyncCall(InspectorDebuggerAgent::AsyncCallType::PostMessage, it->value);
+
+ m_postMessageTimers.remove(it);
+}
+
+void PageDebuggerAgent::willDispatchPostMessage(const TimerBase& timer)
+{
+ auto it = m_postMessageTimers.find(&timer);
+ if (it == m_postMessageTimers.end())
+ return;
+
+ willDispatchAsyncCall(InspectorDebuggerAgent::AsyncCallType::PostMessage, it->value);
+}
+
+void PageDebuggerAgent::didDispatchPostMessage(const TimerBase& timer)
+{
+ auto it = m_postMessageTimers.find(&timer);
+ if (it == m_postMessageTimers.end())
+ return;
+
+ didDispatchAsyncCall();
+
+ m_postMessageTimers.remove(it);
+}
+
} // namespace WebCore
Modified: trunk/Source/WebCore/inspector/PageDebuggerAgent.h (220298 => 220299)
--- trunk/Source/WebCore/inspector/PageDebuggerAgent.h 2017-08-04 22:03:54 UTC (rev 220298)
+++ trunk/Source/WebCore/inspector/PageDebuggerAgent.h 2017-08-04 22:12:40 UTC (rev 220299)
@@ -42,6 +42,7 @@
class InspectorPageAgent;
class Page;
class RegisteredEventListener;
+class TimerBase;
class PageDebuggerAgent final : public WebDebuggerAgent {
WTF_MAKE_NONCOPYABLE(PageDebuggerAgent);
@@ -64,6 +65,11 @@
void willRemoveEventListener(EventTarget&, const AtomicString& eventType, EventListener&, bool capture);
void willHandleEvent(const RegisteredEventListener&);
+ void didPostMessage(const TimerBase&, JSC::ExecState&);
+ void didFailPostMessage(const TimerBase&);
+ void willDispatchPostMessage(const TimerBase&);
+ void didDispatchPostMessage(const TimerBase&);
+
protected:
void enable() override;
void disable(bool isBeingDestroyed) override;
@@ -87,7 +93,9 @@
InspectorOverlay* m_overlay { nullptr };
HashMap<const RegisteredEventListener*, int> m_registeredEventListeners;
+ HashMap<const TimerBase*, int> m_postMessageTimers;
int m_nextEventListenerIdentifier { 1 };
+ int m_nextPostMessageIdentifier { 1 };
};
} // namespace WebCore
Modified: trunk/Source/WebCore/page/DOMWindow.cpp (220298 => 220299)
--- trunk/Source/WebCore/page/DOMWindow.cpp 2017-08-04 22:03:54 UTC (rev 220298)
+++ trunk/Source/WebCore/page/DOMWindow.cpp 2017-08-04 22:12:40 UTC (rev 220299)
@@ -956,6 +956,8 @@
auto* timer = new PostMessageTimer(*this, message.releaseReturnValue(), sourceOrigin, incumbentWindow, channels.releaseReturnValue(), WTFMove(target), WTFMove(stackTrace));
timer->startOneShot(0_s);
+ InspectorInstrumentation::didPostMessage(*m_frame, *timer, state);
+
return { };
}
@@ -974,11 +976,17 @@
else
pageConsole->addMessage(MessageSource::Security, MessageLevel::Error, message);
}
+
+ InspectorInstrumentation::didFailPostMessage(*m_frame, timer);
return;
}
}
+ InspectorInstrumentation::willDispatchPostMessage(*m_frame, timer);
+
dispatchEvent(timer.event(*document()));
+
+ InspectorInstrumentation::didDispatchPostMessage(*m_frame, timer);
}
DOMSelection* DOMWindow::getSelection()