Commit d73ee834 authored by aandrey@chromium.org's avatar aandrey@chromium.org

DevTools: Instrument DOMWindowEventQueue for async stacks.

This adds async stacks support for the following DOM events:
- hashchange
- selectionchange
- pointerlockchange and others
- securitypolicyviolation
- storage

BUG=272416
R=yurys, pfeldman@chromium.org

Review URL: https://codereview.chromium.org/333333002

git-svn-id: svn://svn.chromium.org/blink/trunk@176352 bbb929c8-8fbe-4397-9dbb-9b2b20218538
parent 9459f56d
Tests asynchronous call stacks for various DOM events.
Set timer for test function.
Captured call stacks in no particular order:
Call stack:
0) onHashChange (async-callstack-events.html:51)
[hashchange]
0) doTestHashChange (async-callstack-events.html:45)
1) testFunction (async-callstack-events.html:11)
Call stack:
0) onSelectionChange (async-callstack-events.html:39)
[selectionchange]
0) setSelection (async-callstack-events.html:24)
1) doTestSelectionChange (async-callstack-events.html:31)
2) testFunction (async-callstack-events.html:11)
<html>
<head>
<script src="../../../http/tests/inspector/inspector-test.js"></script>
<script src="../../../http/tests/inspector/debugger-test.js"></script>
<script>
function testFunction()
{
for (var name in window) {
if (/^doTest[A-Z]/.test(name) && typeof window[name] === "function")
window[name]();
}
}
function setSelection(start, end)
{
var node = document.getElementById("content").firstChild;
var range = document.createRange();
range.setStart(node, start);
range.setEnd(node, end);
var selection = window.getSelection();
selection.removeAllRanges();
if (start !== end)
selection.addRange(range);
}
function doTestSelectionChange()
{
setSelection(0, 0);
document.addEventListener("selectionchange", onSelectionChange, false);
setSelection(0, 4);
setSelection(0, 8);
setSelection(0, 0);
}
function onSelectionChange()
{
document.removeEventListener("selectionchange", onSelectionChange, false);
debugger;
}
function doTestHashChange()
{
window.addEventListener("hashchange", onHashChange, false);
location.hash = location.hash + "x";
}
function onHashChange()
{
window.removeEventListener("hashchange", onHashChange, false);
debugger;
}
var test = function()
{
var totalDebuggerStatements = 2;
var maxAsyncCallStackDepth = 4;
InspectorTest.runAsyncCallStacksTest(totalDebuggerStatements, maxAsyncCallStackDepth);
}
</script>
</head>
<body onload="runTest()">
<p id="content">
Tests asynchronous call stacks for various DOM events.
</p>
</body>
</html>
...@@ -133,7 +133,7 @@ void ScriptedAnimationController::dispatchEvents() ...@@ -133,7 +133,7 @@ void ScriptedAnimationController::dispatchEvents()
else else
eventTarget->dispatchEvent(events[i]); eventTarget->dispatchEvent(events[i]);
InspectorInstrumentation::didDispatchEvent(eventTarget, events[i].get()); InspectorInstrumentation::didRemoveEvent(eventTarget, events[i].get());
} }
} }
......
...@@ -31,6 +31,7 @@ ...@@ -31,6 +31,7 @@
#include "core/events/Event.h" #include "core/events/Event.h"
#include "core/frame/DOMWindow.h" #include "core/frame/DOMWindow.h"
#include "core/frame/SuspendableTimer.h" #include "core/frame/SuspendableTimer.h"
#include "core/inspector/InspectorInstrumentation.h"
namespace WebCore { namespace WebCore {
...@@ -77,6 +78,8 @@ bool DOMWindowEventQueue::enqueueEvent(PassRefPtrWillBeRawPtr<Event> event) ...@@ -77,6 +78,8 @@ bool DOMWindowEventQueue::enqueueEvent(PassRefPtrWillBeRawPtr<Event> event)
return false; return false;
ASSERT(event->target()); ASSERT(event->target());
InspectorInstrumentation::didEnqueueEvent(event->target(), event.get());
bool wasAdded = m_queuedEvents.add(event).isNewEntry; bool wasAdded = m_queuedEvents.add(event).isNewEntry;
ASSERT_UNUSED(wasAdded, wasAdded); // It should not have already been in the list. ASSERT_UNUSED(wasAdded, wasAdded); // It should not have already been in the list.
...@@ -90,8 +93,10 @@ bool DOMWindowEventQueue::cancelEvent(Event* event) ...@@ -90,8 +93,10 @@ bool DOMWindowEventQueue::cancelEvent(Event* event)
{ {
WillBeHeapListHashSet<RefPtrWillBeMember<Event>, 16>::iterator it = m_queuedEvents.find(event); WillBeHeapListHashSet<RefPtrWillBeMember<Event>, 16>::iterator it = m_queuedEvents.find(event);
bool found = it != m_queuedEvents.end(); bool found = it != m_queuedEvents.end();
if (found) if (found) {
InspectorInstrumentation::didRemoveEvent(event->target(), event);
m_queuedEvents.remove(it); m_queuedEvents.remove(it);
}
if (m_queuedEvents.isEmpty()) if (m_queuedEvents.isEmpty())
m_pendingEventTimer->stop(); m_pendingEventTimer->stop();
return found; return found;
...@@ -101,6 +106,11 @@ void DOMWindowEventQueue::close() ...@@ -101,6 +106,11 @@ void DOMWindowEventQueue::close()
{ {
m_isClosed = true; m_isClosed = true;
m_pendingEventTimer->stop(); m_pendingEventTimer->stop();
if (InspectorInstrumentation::hasFrontends()) {
WillBeHeapListHashSet<RefPtrWillBeMember<Event>, 16>::iterator it = m_queuedEvents.begin();
for (; it != m_queuedEvents.end(); ++it)
InspectorInstrumentation::didRemoveEvent((*it)->target(), it->get());
}
m_queuedEvents.clear(); m_queuedEvents.clear();
} }
...@@ -123,6 +133,7 @@ void DOMWindowEventQueue::pendingEventTimerFired() ...@@ -123,6 +133,7 @@ void DOMWindowEventQueue::pendingEventTimerFired()
if (!event) if (!event)
break; break;
dispatchEvent(event.get()); dispatchEvent(event.get());
InspectorInstrumentation::didRemoveEvent(event->target(), event.get());
} }
} }
......
...@@ -208,7 +208,7 @@ void AsyncCallStackTracker::didEnqueueEvent(EventTarget* eventTarget, Event* eve ...@@ -208,7 +208,7 @@ void AsyncCallStackTracker::didEnqueueEvent(EventTarget* eventTarget, Event* eve
data->m_eventCallChains.set(event, createAsyncCallChain(event->type(), callFrames)); data->m_eventCallChains.set(event, createAsyncCallChain(event->type(), callFrames));
} }
void AsyncCallStackTracker::didDispatchEvent(EventTarget* eventTarget, Event* event) void AsyncCallStackTracker::didRemoveEvent(EventTarget* eventTarget, Event* event)
{ {
ASSERT(eventTarget->executionContext()); ASSERT(eventTarget->executionContext());
ASSERT(isEnabled()); ASSERT(isEnabled());
......
...@@ -89,7 +89,7 @@ public: ...@@ -89,7 +89,7 @@ public:
void willFireAnimationFrame(ExecutionContext*, int callbackId); void willFireAnimationFrame(ExecutionContext*, int callbackId);
void didEnqueueEvent(EventTarget*, Event*, const ScriptValue& callFrames); void didEnqueueEvent(EventTarget*, Event*, const ScriptValue& callFrames);
void didDispatchEvent(EventTarget*, Event*); void didRemoveEvent(EventTarget*, Event*);
void willHandleEvent(EventTarget*, Event*, EventListener*, bool useCapture); void willHandleEvent(EventTarget*, Event*, EventListener*, bool useCapture);
void willLoadXHR(XMLHttpRequest*, const ScriptValue& callFrames); void willLoadXHR(XMLHttpRequest*, const ScriptValue& callFrames);
......
...@@ -720,10 +720,10 @@ void InspectorDebuggerAgent::didEnqueueEvent(EventTarget* eventTarget, Event* ev ...@@ -720,10 +720,10 @@ void InspectorDebuggerAgent::didEnqueueEvent(EventTarget* eventTarget, Event* ev
m_asyncCallStackTracker.didEnqueueEvent(eventTarget, event, scriptDebugServer().currentCallFramesForAsyncStack()); m_asyncCallStackTracker.didEnqueueEvent(eventTarget, event, scriptDebugServer().currentCallFramesForAsyncStack());
} }
void InspectorDebuggerAgent::didDispatchEvent(EventTarget* eventTarget, Event* event) void InspectorDebuggerAgent::didRemoveEvent(EventTarget* eventTarget, Event* event)
{ {
if (m_asyncCallStackTracker.isEnabled()) if (m_asyncCallStackTracker.isEnabled())
m_asyncCallStackTracker.didDispatchEvent(eventTarget, event); m_asyncCallStackTracker.didRemoveEvent(eventTarget, event);
} }
void InspectorDebuggerAgent::willHandleEvent(EventTarget* eventTarget, Event* event, EventListener* listener, bool useCapture) void InspectorDebuggerAgent::willHandleEvent(EventTarget* eventTarget, Event* event, EventListener* listener, bool useCapture)
......
...@@ -150,7 +150,7 @@ public: ...@@ -150,7 +150,7 @@ public:
bool willFireAnimationFrame(Document*, int callbackId); bool willFireAnimationFrame(Document*, int callbackId);
void didFireAnimationFrame(); void didFireAnimationFrame();
void didEnqueueEvent(EventTarget*, Event*); void didEnqueueEvent(EventTarget*, Event*);
void didDispatchEvent(EventTarget*, Event*); void didRemoveEvent(EventTarget*, Event*);
void willHandleEvent(EventTarget*, Event*, EventListener*, bool useCapture); void willHandleEvent(EventTarget*, Event*, EventListener*, bool useCapture);
void didHandleEvent(); void didHandleEvent();
void willLoadXHR(XMLHttpRequest*, ThreadableLoaderClient*, const AtomicString& method, const KURL&, bool async, FormData* body, const HTTPHeaderMap& headers, bool includeCrendentials); void willLoadXHR(XMLHttpRequest*, ThreadableLoaderClient*, const AtomicString& method, const KURL&, bool async, FormData* body, const HTTPHeaderMap& headers, bool includeCrendentials);
......
...@@ -164,7 +164,7 @@ interface InspectorInstrumentation { ...@@ -164,7 +164,7 @@ interface InspectorInstrumentation {
void didEnqueueEvent([Keep] EventTarget*, Event*); void didEnqueueEvent([Keep] EventTarget*, Event*);
[Debugger, Inline=FastReturn] [Debugger, Inline=FastReturn]
void didDispatchEvent([Keep] EventTarget*, Event*); void didRemoveEvent([Keep] EventTarget*, Event*);
[Debugger, DOMDebugger, Inline=FastReturn] [Debugger, DOMDebugger, Inline=FastReturn]
InspectorInstrumentationCookie willHandleEvent([Keep] EventTarget*, Event*, EventListener* listener, bool useCapture); InspectorInstrumentationCookie willHandleEvent([Keep] EventTarget*, Event*, EventListener* listener, bool useCapture);
......
...@@ -30,6 +30,7 @@ ...@@ -30,6 +30,7 @@
#include "core/dom/ExecutionContext.h" #include "core/dom/ExecutionContext.h"
#include "core/dom/ExecutionContextTask.h" #include "core/dom/ExecutionContextTask.h"
#include "core/events/Event.h" #include "core/events/Event.h"
#include "core/inspector/InspectorInstrumentation.h"
namespace WebCore { namespace WebCore {
...@@ -104,6 +105,7 @@ private: ...@@ -104,6 +105,7 @@ private:
void WorkerEventQueue::removeEvent(Event* event) void WorkerEventQueue::removeEvent(Event* event)
{ {
InspectorInstrumentation::didRemoveEvent(event->target(), event);
m_eventTaskMap.remove(event); m_eventTaskMap.remove(event);
} }
...@@ -112,6 +114,7 @@ bool WorkerEventQueue::enqueueEvent(PassRefPtrWillBeRawPtr<Event> prpEvent) ...@@ -112,6 +114,7 @@ bool WorkerEventQueue::enqueueEvent(PassRefPtrWillBeRawPtr<Event> prpEvent)
if (m_isClosed) if (m_isClosed)
return false; return false;
RefPtrWillBeRawPtr<Event> event = prpEvent; RefPtrWillBeRawPtr<Event> event = prpEvent;
InspectorInstrumentation::didEnqueueEvent(event->target(), event.get());
OwnPtr<EventDispatcherTask> task = EventDispatcherTask::create(event, this); OwnPtr<EventDispatcherTask> task = EventDispatcherTask::create(event, this);
m_eventTaskMap.add(event.release(), task.get()); m_eventTaskMap.add(event.release(), task.get());
m_executionContext->postTask(task.release()); m_executionContext->postTask(task.release());
...@@ -132,7 +135,9 @@ void WorkerEventQueue::close() ...@@ -132,7 +135,9 @@ void WorkerEventQueue::close()
{ {
m_isClosed = true; m_isClosed = true;
for (EventTaskMap::iterator it = m_eventTaskMap.begin(); it != m_eventTaskMap.end(); ++it) { for (EventTaskMap::iterator it = m_eventTaskMap.begin(); it != m_eventTaskMap.end(); ++it) {
Event* event = it->key.get();
EventDispatcherTask* task = it->value; EventDispatcherTask* task = it->value;
InspectorInstrumentation::didRemoveEvent(event->target(), event);
task->cancel(); task->cancel();
} }
m_eventTaskMap.clear(); m_eventTaskMap.clear();
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment