Title: [138534] trunk
Revision
138534
Author
[email protected]
Date
2012-12-28 06:42:15 -0800 (Fri, 28 Dec 2012)

Log Message

Web Inspector: debugger should step into event handler on event dispatch
https://bugs.webkit.org/show_bug.cgi?id=105827

Reviewed by Pavel Feldman.

Source/WebCore:

Added m_pauseInNextEventListener to InspectorDOMDebuggerAgent. The flag is set
to true when "step into" is pressed and reset to false when either JS execution
pauses, the agent gets disabled or JS call stack becomes empty. If the flag is
true and the next JS stetement to be executed belongs to a JS event listener we
will stop in that listener, otherwise we have two options:
  1) Control flow directly(without comming through the native bindings) reaches some JS
     statement and will pause in the corresponding JS function, in which case the
     flag will be reset;
  2) JS call stack becomes empty and execution will continue in the native code. We
     use didProcessTask to detect such cases and reset the flag to false every time
     event queue finishes next task.

Test: inspector/debugger/debugger-step-into-event-listener.html

* inspector/InspectorController.cpp:
(WebCore::InspectorController::InspectorController):
(WebCore::InspectorController::reportMemoryUsage):
(WebCore::InspectorController::didProcessTask):
* inspector/InspectorController.h:
(WebCore):
(InspectorController):
* inspector/InspectorDOMDebuggerAgent.cpp:
(WebCore::InspectorDOMDebuggerAgent::InspectorDOMDebuggerAgent):
(WebCore::InspectorDOMDebuggerAgent::stepInto):
(WebCore):
(WebCore::InspectorDOMDebuggerAgent::didPause):
(WebCore::InspectorDOMDebuggerAgent::cancelStepIntoEventListener):
(WebCore::InspectorDOMDebuggerAgent::pauseOnNativeEventIfNeeded):
(WebCore::InspectorDOMDebuggerAgent::clear):
* inspector/InspectorDOMDebuggerAgent.h:
(InspectorDOMDebuggerAgent):
* inspector/InspectorDebuggerAgent.cpp:
(WebCore::InspectorDebuggerAgent::stepInto):
(WebCore::InspectorDebuggerAgent::didPause):
* inspector/InspectorDebuggerAgent.h:
(Listener):

LayoutTests:

* inspector/debugger/debugger-step-into-event-listener-expected.txt: Added.
* inspector/debugger/debugger-step-into-event-listener.html: Added.

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (138533 => 138534)


--- trunk/LayoutTests/ChangeLog	2012-12-28 14:26:00 UTC (rev 138533)
+++ trunk/LayoutTests/ChangeLog	2012-12-28 14:42:15 UTC (rev 138534)
@@ -1,3 +1,13 @@
+2012-12-28  Yury Semikhatsky  <[email protected]>
+
+        Web Inspector: debugger should step into event handler on event dispatch
+        https://bugs.webkit.org/show_bug.cgi?id=105827
+
+        Reviewed by Pavel Feldman.
+
+        * inspector/debugger/debugger-step-into-event-listener-expected.txt: Added.
+        * inspector/debugger/debugger-step-into-event-listener.html: Added.
+
 2012-12-28  Sudarsana Nagineni  <[email protected]>
 
         Unreviewed EFL gardening.

Added: trunk/LayoutTests/inspector/debugger/debugger-step-into-event-listener-expected.txt (0 => 138534)


--- trunk/LayoutTests/inspector/debugger/debugger-step-into-event-listener-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/inspector/debugger/debugger-step-into-event-listener-expected.txt	2012-12-28 14:42:15 UTC (rev 138534)
@@ -0,0 +1,14 @@
+Tests that stepping into dispatchEvent() method will lead to a pause in the first event listener.
+
+Recieved foo event(1)! Recieved foo event(2)!
+Debugger was enabled.
+Set timer for test function.
+Stepping into...
+Stepping into...
+SUCCESS: Did step into event listener(fooEventHandler1).
+Stepping into...
+Stepping into...
+Stepping into...
+SUCCESS: Did step into event listener(fooEventHandler2).
+Debugger was disabled.
+
Property changes on: trunk/LayoutTests/inspector/debugger/debugger-step-into-event-listener-expected.txt
___________________________________________________________________

Added: svn:eol-style

Added: trunk/LayoutTests/inspector/debugger/debugger-step-into-event-listener.html (0 => 138534)


--- trunk/LayoutTests/inspector/debugger/debugger-step-into-event-listener.html	                        (rev 0)
+++ trunk/LayoutTests/inspector/debugger/debugger-step-into-event-listener.html	2012-12-28 14:42:15 UTC (rev 138534)
@@ -0,0 +1,72 @@
+<html>
+<head>
+<script src=""
+<script src=""
+<script>
+
+function testFunction()
+{
+    var div = document.getElementById("myDiv");
+    function fooEventHandler1() {
+        div.textContent += "Recieved foo event(1)!\n";
+    }
+    div.addEventListener("foo", fooEventHandler1);
+
+    function fooEventHandler2() {
+        div.textContent += "Recieved foo event(2)!\n";
+    }
+    div.addEventListener("foo", fooEventHandler2);
+
+    var e = new CustomEvent('foo');
+    debugger;
+    div.dispatchEvent(e);
+}
+
+var test = function()
+{
+    InspectorTest.startDebuggerTest(step1, true);
+
+    function step1()
+    {
+        InspectorTest.runTestFunctionAndWaitUntilPaused(step2);
+    }
+
+
+    function checkTopFrameFunction(callFrames, expectedName)
+    {
+        var topFunctionName = callFrames[0].functionName;
+        if (expectedName === topFunctionName)
+            InspectorTest.addResult("SUCCESS: Did step into event listener(" + expectedName + ").");
+        else
+            InspectorTest.addResult("FAIL: Unexpected top function: expected " + expectedName + ", found " + topFunctionName);
+    }
+
+    var stepCount = 0;
+    function step2(callFrames)
+    {
+        if (stepCount === 2)
+            checkTopFrameFunction(callFrames, "fooEventHandler1");
+        else if (stepCount === 5)
+            checkTopFrameFunction(callFrames, "fooEventHandler2");
+
+        if (stepCount < 5) {
+            InspectorTest.addResult("Stepping into...");
+            document.getElementById("scripts-step-into").click();
+            InspectorTest.waitUntilResumed(InspectorTest.waitUntilPaused.bind(InspectorTest, step2));
+        } else
+            InspectorTest.completeDebuggerTest();
+        stepCount++;
+    }
+}
+
+</script>
+</head>
+
+<body _onload_="runTest()">
+<p>
+Tests that stepping into dispatchEvent() method will lead to a pause in the first event listener.
+</p>
+<div id="myDiv"></div>
+
+</body>
+</html>
Property changes on: trunk/LayoutTests/inspector/debugger/debugger-step-into-event-listener.html
___________________________________________________________________

Added: svn:eol-style

Modified: trunk/Source/WebCore/ChangeLog (138533 => 138534)


--- trunk/Source/WebCore/ChangeLog	2012-12-28 14:26:00 UTC (rev 138533)
+++ trunk/Source/WebCore/ChangeLog	2012-12-28 14:42:15 UTC (rev 138534)
@@ -1,3 +1,47 @@
+2012-12-28  Yury Semikhatsky  <[email protected]>
+
+        Web Inspector: debugger should step into event handler on event dispatch
+        https://bugs.webkit.org/show_bug.cgi?id=105827
+
+        Reviewed by Pavel Feldman.
+
+        Added m_pauseInNextEventListener to InspectorDOMDebuggerAgent. The flag is set
+        to true when "step into" is pressed and reset to false when either JS execution
+        pauses, the agent gets disabled or JS call stack becomes empty. If the flag is
+        true and the next JS stetement to be executed belongs to a JS event listener we
+        will stop in that listener, otherwise we have two options:
+          1) Control flow directly(without comming through the native bindings) reaches some JS
+             statement and will pause in the corresponding JS function, in which case the
+             flag will be reset;
+          2) JS call stack becomes empty and execution will continue in the native code. We
+             use didProcessTask to detect such cases and reset the flag to false every time
+             event queue finishes next task.
+
+        Test: inspector/debugger/debugger-step-into-event-listener.html
+
+        * inspector/InspectorController.cpp:
+        (WebCore::InspectorController::InspectorController):
+        (WebCore::InspectorController::reportMemoryUsage):
+        (WebCore::InspectorController::didProcessTask):
+        * inspector/InspectorController.h:
+        (WebCore):
+        (InspectorController):
+        * inspector/InspectorDOMDebuggerAgent.cpp:
+        (WebCore::InspectorDOMDebuggerAgent::InspectorDOMDebuggerAgent):
+        (WebCore::InspectorDOMDebuggerAgent::stepInto):
+        (WebCore):
+        (WebCore::InspectorDOMDebuggerAgent::didPause):
+        (WebCore::InspectorDOMDebuggerAgent::cancelStepIntoEventListener):
+        (WebCore::InspectorDOMDebuggerAgent::pauseOnNativeEventIfNeeded):
+        (WebCore::InspectorDOMDebuggerAgent::clear):
+        * inspector/InspectorDOMDebuggerAgent.h:
+        (InspectorDOMDebuggerAgent):
+        * inspector/InspectorDebuggerAgent.cpp:
+        (WebCore::InspectorDebuggerAgent::stepInto):
+        (WebCore::InspectorDebuggerAgent::didPause):
+        * inspector/InspectorDebuggerAgent.h:
+        (Listener):
+
 2012-12-28  Andrey Lushnikov  <[email protected]>
 
         Web Inspector: enable mutation observer in LayoutTests

Modified: trunk/Source/WebCore/bindings/js/ScriptDebugServer.cpp (138533 => 138534)


--- trunk/Source/WebCore/bindings/js/ScriptDebugServer.cpp	2012-12-28 14:26:00 UTC (rev 138533)
+++ trunk/Source/WebCore/bindings/js/ScriptDebugServer.cpp	2012-12-28 14:42:15 UTC (rev 138534)
@@ -55,6 +55,7 @@
     , m_pauseOnExceptionsState(DontPauseOnExceptions)
     , m_pauseOnNextStatement(false)
     , m_paused(false)
+    , m_runningNestedMessageLoop(false)
     , m_doneProcessingDebuggerEvents(true)
     , m_breakpointsActivated(true)
     , m_pauseOnCallFrame(0)
@@ -440,8 +441,10 @@
 
     TimerBase::fireTimersInNestedEventLoop();
 
+    m_runningNestedMessageLoop = true;
     m_doneProcessingDebuggerEvents = false;
     runEventLoopWhilePaused();
+    m_runningNestedMessageLoop = false;
 
     didContinue(dynamicGlobalObject);
     dispatchFunctionToListeners(&ScriptDebugServer::dispatchDidContinue, dynamicGlobalObject);

Modified: trunk/Source/WebCore/bindings/js/ScriptDebugServer.h (138533 => 138534)


--- trunk/Source/WebCore/bindings/js/ScriptDebugServer.h	2012-12-28 14:26:00 UTC (rev 138533)
+++ trunk/Source/WebCore/bindings/js/ScriptDebugServer.h	2012-12-28 14:42:15 UTC (rev 138534)
@@ -96,6 +96,7 @@
     }
 
     bool isPaused() { return m_paused; }
+    bool runningNestedMessageLoop() { return m_runningNestedMessageLoop; }
 
     void compileScript(ScriptState*, const String& _expression_, const String& sourceURL, String* scriptId, String* exceptionMessage);
     void clearCompiledScripts();
@@ -155,6 +156,7 @@
     PauseOnExceptionsState m_pauseOnExceptionsState;
     bool m_pauseOnNextStatement;
     bool m_paused;
+    bool m_runningNestedMessageLoop;
     bool m_doneProcessingDebuggerEvents;
     bool m_breakpointsActivated;
     _javascript_CallFrame* m_pauseOnCallFrame;

Modified: trunk/Source/WebCore/bindings/v8/ScriptDebugServer.cpp (138533 => 138534)


--- trunk/Source/WebCore/bindings/v8/ScriptDebugServer.cpp	2012-12-28 14:26:00 UTC (rev 138533)
+++ trunk/Source/WebCore/bindings/v8/ScriptDebugServer.cpp	2012-12-28 14:42:15 UTC (rev 138534)
@@ -153,6 +153,7 @@
 ScriptDebugServer::ScriptDebugServer()
     : m_pauseOnExceptionsState(DontPauseOnExceptions)
     , m_breakpointsActivated(true)
+    , m_runningNestedMessageLoop(false)
 {
 }
 
@@ -423,7 +424,9 @@
     ScriptState* currentCallFrameState = ScriptState::forContext(m_pausedContext);
     listener->didPause(currentCallFrameState, currentCallFrame(), ScriptValue(exception));
 
+    m_runningNestedMessageLoop = true;
     runMessageLoopOnPause(m_pausedContext);
+    m_runningNestedMessageLoop = false;
 }
 
 void ScriptDebugServer::v8DebugEventCallback(const v8::Debug::EventDetails& eventDetails)

Modified: trunk/Source/WebCore/bindings/v8/ScriptDebugServer.h (138533 => 138534)


--- trunk/Source/WebCore/bindings/v8/ScriptDebugServer.h	2012-12-28 14:26:00 UTC (rev 138533)
+++ trunk/Source/WebCore/bindings/v8/ScriptDebugServer.h	2012-12-28 14:42:15 UTC (rev 138534)
@@ -97,6 +97,7 @@
     void runPendingTasks();
 
     bool isPaused();
+    bool runningNestedMessageLoop() { return m_runningNestedMessageLoop; }
 
     v8::Local<v8::Value> functionScopes(v8::Handle<v8::Function>);
     v8::Local<v8::Value> getInternalProperties(v8::Handle<v8::Object>&);
@@ -140,6 +141,7 @@
 private:
     class ScriptPreprocessor;
     OwnPtr<ScriptPreprocessor> m_scriptPreprocessor;
+    bool m_runningNestedMessageLoop;
 };
 
 } // namespace WebCore

Modified: trunk/Source/WebCore/inspector/InspectorController.cpp (138533 => 138534)


--- trunk/Source/WebCore/inspector/InspectorController.cpp	2012-12-28 14:26:00 UTC (rev 138533)
+++ trunk/Source/WebCore/inspector/InspectorController.cpp	2012-12-28 14:42:15 UTC (rev 138534)
@@ -140,7 +140,9 @@
     m_debuggerAgent = debuggerAgentPtr.get();
     m_agents.append(debuggerAgentPtr.release());
 
-    m_agents.append(InspectorDOMDebuggerAgent::create(m_instrumentingAgents.get(), m_state.get(), m_domAgent, m_debuggerAgent, m_inspectorAgent));
+    OwnPtr<InspectorDOMDebuggerAgent> domDebuggerAgentPtr(InspectorDOMDebuggerAgent::create(m_instrumentingAgents.get(), m_state.get(), m_domAgent, m_debuggerAgent, m_inspectorAgent));
+    m_domDebuggerAgent = domDebuggerAgentPtr.get();
+    m_agents.append(domDebuggerAgentPtr.release());
 
     OwnPtr<InspectorProfilerAgent> profilerAgentPtr(InspectorProfilerAgent::create(m_instrumentingAgents.get(), consoleAgent, page, m_state.get(), m_injectedScriptManager.get()));
     m_profilerAgent = profilerAgentPtr.get();
@@ -398,6 +400,7 @@
     info.addMember(m_pageAgent);
 #if ENABLE(_javascript__DEBUGGER)
     info.addMember(m_debuggerAgent);
+    info.addMember(m_domDebuggerAgent);
     info.addMember(m_profilerAgent);
 #endif
 
@@ -424,6 +427,7 @@
         timelineAgent->didProcessTask();
 #if ENABLE(_javascript__DEBUGGER)
     m_profilerAgent->didProcessTask();
+    m_domDebuggerAgent->didProcessTask();
 #endif
 }
 

Modified: trunk/Source/WebCore/inspector/InspectorController.h (138533 => 138534)


--- trunk/Source/WebCore/inspector/InspectorController.h	2012-12-28 14:26:00 UTC (rev 138533)
+++ trunk/Source/WebCore/inspector/InspectorController.h	2012-12-28 14:42:15 UTC (rev 138534)
@@ -51,6 +51,7 @@
 class InspectorBaseAgentInterface;
 class InspectorClient;
 class InspectorDOMAgent;
+class InspectorDOMDebuggerAgent;
 class InspectorDebuggerAgent;
 class InspectorFrontend;
 class InspectorFrontendChannel;
@@ -139,6 +140,7 @@
     InspectorPageAgent* m_pageAgent;
 #if ENABLE(_javascript__DEBUGGER)
     InspectorDebuggerAgent* m_debuggerAgent;
+    InspectorDOMDebuggerAgent* m_domDebuggerAgent;
     InspectorProfilerAgent* m_profilerAgent;
 #endif
 

Modified: trunk/Source/WebCore/inspector/InspectorDOMDebuggerAgent.cpp (138533 => 138534)


--- trunk/Source/WebCore/inspector/InspectorDOMDebuggerAgent.cpp	2012-12-28 14:26:00 UTC (rev 138533)
+++ trunk/Source/WebCore/inspector/InspectorDOMDebuggerAgent.cpp	2012-12-28 14:42:15 UTC (rev 138534)
@@ -79,6 +79,7 @@
     : InspectorBaseAgent<InspectorDOMDebuggerAgent>("DOMDebugger", instrumentingAgents, inspectorState)
     , m_domAgent(domAgent)
     , m_debuggerAgent(debuggerAgent)
+    , m_pauseInNextEventListener(false)
 {
     m_debuggerAgent->setListener(this);
 }
@@ -100,6 +101,25 @@
     disable();
 }
 
+void InspectorDOMDebuggerAgent::stepInto()
+{
+    m_pauseInNextEventListener = true;
+}
+
+void InspectorDOMDebuggerAgent::didPause()
+{
+    m_pauseInNextEventListener = false;
+}
+
+void InspectorDOMDebuggerAgent::didProcessTask()
+{
+    if (!m_pauseInNextEventListener)
+        return;
+    if (m_debuggerAgent && m_debuggerAgent->runningNestedMessageLoop())
+        return;
+    m_pauseInNextEventListener = false;
+}
+
 void InspectorDOMDebuggerAgent::disable()
 {
     m_instrumentingAgents->setInspectorDOMDebuggerAgent(0);
@@ -358,9 +378,13 @@
 void InspectorDOMDebuggerAgent::pauseOnNativeEventIfNeeded(bool isDOMEvent, const String& eventName, bool synchronous)
 {
     String fullEventName = (isDOMEvent ? listenerEventCategoryType : instrumentationEventCategoryType) + eventName;
-    RefPtr<InspectorObject> eventListenerBreakpoints = m_state->getObject(DOMDebuggerAgentState::eventListenerBreakpoints);
-    if (eventListenerBreakpoints->find(fullEventName) == eventListenerBreakpoints->end())
-        return;
+    if (m_pauseInNextEventListener)
+        m_pauseInNextEventListener = false;
+    else {
+        RefPtr<InspectorObject> eventListenerBreakpoints = m_state->getObject(DOMDebuggerAgentState::eventListenerBreakpoints);
+        if (eventListenerBreakpoints->find(fullEventName) == eventListenerBreakpoints->end())
+            return;
+    }
 
     RefPtr<InspectorObject> eventData = InspectorObject::create();
     eventData->setString("eventName", fullEventName);
@@ -421,6 +445,7 @@
 void InspectorDOMDebuggerAgent::clear()
 {
     m_domBreakpoints.clear();
+    m_pauseInNextEventListener = false;
 }
 
 } // namespace WebCore

Modified: trunk/Source/WebCore/inspector/InspectorDOMDebuggerAgent.h (138533 => 138534)


--- trunk/Source/WebCore/inspector/InspectorDOMDebuggerAgent.h	2012-12-28 14:26:00 UTC (rev 138533)
+++ trunk/Source/WebCore/inspector/InspectorDOMDebuggerAgent.h	2012-12-28 14:42:15 UTC (rev 138534)
@@ -81,6 +81,8 @@
     void willSendXMLHttpRequest(const String& url);
     void pauseOnNativeEventIfNeeded(bool isDOMEvent, const String& eventName, bool synchronous);
 
+    void didProcessTask();
+
     virtual void clearFrontend();
     virtual void discardAgent();
 
@@ -90,6 +92,8 @@
     // InspectorDebuggerAgent::Listener implementation.
     virtual void debuggerWasEnabled();
     virtual void debuggerWasDisabled();
+    virtual void stepInto();
+    virtual void didPause();
     void disable();
 
     void descriptionForDOMEvent(Node* target, int breakpointType, bool insertion, InspectorObject* description);
@@ -104,6 +108,7 @@
     InspectorDOMAgent* m_domAgent;
     InspectorDebuggerAgent* m_debuggerAgent;
     HashMap<Node*, uint32_t> m_domBreakpoints;
+    bool m_pauseInNextEventListener;
 };
 
 } // namespace WebCore

Modified: trunk/Source/WebCore/inspector/InspectorDebuggerAgent.cpp (138533 => 138534)


--- trunk/Source/WebCore/inspector/InspectorDebuggerAgent.cpp	2012-12-28 14:26:00 UTC (rev 138533)
+++ trunk/Source/WebCore/inspector/InspectorDebuggerAgent.cpp	2012-12-28 14:42:15 UTC (rev 138534)
@@ -191,6 +191,11 @@
     return scriptDebugServer().isPaused();
 }
 
+bool InspectorDebuggerAgent::runningNestedMessageLoop()
+{
+    return scriptDebugServer().runningNestedMessageLoop();
+}
+
 void InspectorDebuggerAgent::addMessageToConsole(MessageSource source, MessageType type)
 {
     if (scriptDebugServer().pauseOnExceptionsState() != ScriptDebugServer::DontPauseOnExceptions && source == ConsoleAPIMessageSource && type == AssertMessageType)
@@ -458,6 +463,7 @@
     if (!assertPaused(errorString))
         return;
     scriptDebugServer().stepIntoStatement();
+    m_listener->stepInto();
 }
 
 void InspectorDebuggerAgent::stepOut(ErrorString* errorString)
@@ -683,6 +689,8 @@
         scriptDebugServer().removeBreakpoint(m_continueToLocationBreakpointId);
         m_continueToLocationBreakpointId = "";
     }
+    if (m_listener)
+        m_listener->didPause();
 }
 
 void InspectorDebuggerAgent::didContinue()

Modified: trunk/Source/WebCore/inspector/InspectorDebuggerAgent.h (138533 => 138534)


--- trunk/Source/WebCore/inspector/InspectorDebuggerAgent.h	2012-12-28 14:26:00 UTC (rev 138533)
+++ trunk/Source/WebCore/inspector/InspectorDebuggerAgent.h	2012-12-28 14:42:15 UTC (rev 138534)
@@ -79,6 +79,7 @@
     virtual void restore();
 
     bool isPaused();
+    bool runningNestedMessageLoop();
     void addMessageToConsole(MessageSource, MessageType);
 
     // Part of the protocol.
@@ -124,6 +125,8 @@
         virtual ~Listener() { }
         virtual void debuggerWasEnabled() = 0;
         virtual void debuggerWasDisabled() = 0;
+        virtual void stepInto() = 0;
+        virtual void didPause() = 0;
     };
     void setListener(Listener* listener) { m_listener = listener; }
 
_______________________________________________
webkit-changes mailing list
[email protected]
http://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to