Title: [176357] trunk
Revision
176357
Author
[email protected]
Date
2014-11-19 15:49:36 -0800 (Wed, 19 Nov 2014)

Log Message

Web Inspector: Provide $exception in the console for the thrown exception value
https://bugs.webkit.org/show_bug.cgi?id=138726

Reviewed by Timothy Hatcher.

Source/_javascript_Core:

* debugger/DebuggerScope.cpp:
(JSC::DebuggerScope::caughtValue):
* debugger/DebuggerScope.h:
Access the caught value if this scope is a catch scope.

* runtime/JSNameScope.h:
(JSC::JSNameScope::isFunctionNameScope):
(JSC::JSNameScope::isCatchScope):
(JSC::JSNameScope::value):
Provide an accessor for the single value in the JSNameScope (with / catch block).

* inspector/InjectedScriptSource.js:
Save the exception value and expose it via $exception. Since the command line api
is recreated on each evaluation, $exception is essentially readonly.

* inspector/ScriptDebugServer.h:
* inspector/ScriptDebugServer.cpp:
(Inspector::ScriptDebugServer::dispatchDidPause):
(Inspector::ScriptDebugServer::exceptionOrCaughtValue):
When pausing, get the exception or caught value. The exception will be provided
if we are breaking on an explicit exception. When inside of a catch block, we
can get the caught value by walking up the scope chain.

* inspector/agents/InspectorDebuggerAgent.h:
* inspector/agents/InspectorDebuggerAgent.cpp:
(Inspector::InspectorDebuggerAgent::InspectorDebuggerAgent):
(Inspector::InspectorDebuggerAgent::resume):
(Inspector::InspectorDebuggerAgent::stepOver):
(Inspector::InspectorDebuggerAgent::stepInto):
(Inspector::InspectorDebuggerAgent::stepOut):
Clearing state can be done in didContinue.

(Inspector::InspectorDebuggerAgent::didPause):
Set the exception value explicitly in the injected script when we have it.

(Inspector::InspectorDebuggerAgent::didContinue):
Clear state saved when we had paused, including clearly an exception value if needed.

(Inspector::InspectorDebuggerAgent::clearDebuggerBreakpointState):
(Inspector::InspectorDebuggerAgent::clearExceptionValue):
Call into the injected script only when needed.

* inspector/InjectedScript.cpp:
(Inspector::InjectedScript::setExceptionValue):
(Inspector::InjectedScript::clearExceptionValue):
* inspector/InjectedScript.h:
* inspector/InjectedScriptManager.cpp:
(Inspector::InjectedScriptManager::clearExceptionValue):
* inspector/InjectedScriptManager.h:
Clear on all injected scripts.

Source/WebCore:

Tests: inspector/debugger/command-line-api-exception-nested-catch.html
       inspector/debugger/command-line-api-exception.html

* inspector/CommandLineAPIModuleSource.js:
Expose $exception in the more complete command line API.

Source/WebInspectorUI:

* UserInterface/Base/Test.js:
(WebInspector.loaded):
In order to use RuntimeManager to execute in the global context or on the
active debugger call frame, we need to expose the quickConsole controller.

* UserInterface/Controllers/_javascript_RuntimeCompletionProvider.js:
Expose $exception to completion when we paused because of an exception.

LayoutTests:

Provide some tests to ensure $exception is the value we expect at different times,
such as on the exception line, when there is no exception, or when stepping through
catch blocks (it should always be the most recent caught exception).

* inspector/debugger/command-line-api-exception-expected.txt: Added.
* inspector/debugger/command-line-api-exception-nested-catch-expected.txt: Added.
* inspector/debugger/command-line-api-exception-nested-catch.html: Added.
* inspector/debugger/command-line-api-exception.html: Added.
* inspector/debugger/resources/exceptions.js: Added.
(triggerUncaughtTypeException):
(triggerUncaughtReferenceException):
(triggerUncaughtSyntaxException):
(triggerUncaughtDOMException):
(throwString):
(throwNumber):
(throwNull):
(throwObject):
(throwNode):
(catcher):
(nestedCatchBlocks):

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (176356 => 176357)


--- trunk/LayoutTests/ChangeLog	2014-11-19 23:48:53 UTC (rev 176356)
+++ trunk/LayoutTests/ChangeLog	2014-11-19 23:49:36 UTC (rev 176357)
@@ -1,3 +1,31 @@
+2014-11-19  Joseph Pecoraro  <[email protected]>
+
+        Web Inspector: Provide $exception in the console for the thrown exception value
+        https://bugs.webkit.org/show_bug.cgi?id=138726
+
+        Reviewed by Timothy Hatcher.
+
+        Provide some tests to ensure $exception is the value we expect at different times,
+        such as on the exception line, when there is no exception, or when stepping through
+        catch blocks (it should always be the most recent caught exception).
+
+        * inspector/debugger/command-line-api-exception-expected.txt: Added.
+        * inspector/debugger/command-line-api-exception-nested-catch-expected.txt: Added.
+        * inspector/debugger/command-line-api-exception-nested-catch.html: Added.
+        * inspector/debugger/command-line-api-exception.html: Added.
+        * inspector/debugger/resources/exceptions.js: Added.
+        (triggerUncaughtTypeException):
+        (triggerUncaughtReferenceException):
+        (triggerUncaughtSyntaxException):
+        (triggerUncaughtDOMException):
+        (throwString):
+        (throwNumber):
+        (throwNull):
+        (throwObject):
+        (throwNode):
+        (catcher):
+        (nestedCatchBlocks):
+
 2014-11-19  David Hyatt  <[email protected]>
 
         Images/replaced elements that are as tall as a page should be on their own page

Added: trunk/LayoutTests/inspector/debugger/command-line-api-exception-expected.txt (0 => 176357)


--- trunk/LayoutTests/inspector/debugger/command-line-api-exception-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/inspector/debugger/command-line-api-exception-expected.txt	2014-11-19 23:49:36 UTC (rev 176357)
@@ -0,0 +1,32 @@
+CONSOLE MESSAGE: line 4: TypeError: undefined is not an object (evaluating '[].x.x')
+CONSOLE MESSAGE: line 10: ReferenceError: Can't find variable: variableThatDoesNotExist
+CONSOLE MESSAGE: line 16: SyntaxError: Unexpected token ')'
+CONSOLE MESSAGE: line 22: IndexSizeError: DOM Exception 1: Index or size was negative, or greater than the allowed value.
+CONSOLE MESSAGE: line 27: thrown string
+CONSOLE MESSAGE: line 32: 123.456
+CONSOLE MESSAGE: line 37: null
+CONSOLE MESSAGE: line 42: [object Object]
+CONSOLE MESSAGE: line 47: [object HTMLBodyElement]
+CONSOLE MESSAGE: line 55: CATCHER: TypeError: undefined is not an object (evaluating '[].x.x')
+CONSOLE MESSAGE: line 55: CATCHER: thrown string
+CONSOLE MESSAGE: line 55: CATCHER: [object Object]
+Checks that $exception is available and accurate in evaluations when paused on an exception.
+
+BEFORE: $exception => undefined
+PAUSE #1: $exception => TypeError: undefined is not an object (evaluating '[].x.x')
+PAUSE #2: $exception => ReferenceError: Can't find variable: variableThatDoesNotExist
+PAUSE #3: $exception => SyntaxError: Unexpected token ')'
+PAUSE #4: $exception => DOMException
+PAUSE #5: $exception => thrown string
+PAUSE #6: $exception => 123.456
+PAUSE #7: $exception => null
+PAUSE #8: $exception => Object
+PAUSE #9: $exception => body
+PAUSE #10: $exception => TypeError: undefined is not an object (evaluating '[].x.x')
+STEPPED OUT TO CATCH BLOCK: $exception === e ? true
+PAUSE #11: $exception => thrown string
+STEPPED OUT TO CATCH BLOCK: $exception === e ? true
+PAUSE #12: $exception => Object
+STEPPED OUT TO CATCH BLOCK: $exception === e ? true
+AFTER: $exception => undefined
+

Added: trunk/LayoutTests/inspector/debugger/command-line-api-exception-nested-catch-expected.txt (0 => 176357)


--- trunk/LayoutTests/inspector/debugger/command-line-api-exception-nested-catch-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/inspector/debugger/command-line-api-exception-nested-catch-expected.txt	2014-11-19 23:49:36 UTC (rev 176357)
@@ -0,0 +1,13 @@
+CONSOLE MESSAGE: line 67: inner exception
+CONSOLE MESSAGE: line 69: outer exception
+Checks that $exception is the value of the current exception, even in nested catch blocks.
+
+BEFORE : $exception => undefined
+OUTER 1: $exception => outer exception
+INNER 1: $exception => inner exception
+INNER 2: $exception => inner exception
+  CATCH: $exception === e2 ? true
+OUTER 2: $exception => outer exception
+  CATCH: $exception === e1 ? true
+AFTER  : $exception => undefined
+

Added: trunk/LayoutTests/inspector/debugger/command-line-api-exception-nested-catch.html (0 => 176357)


--- trunk/LayoutTests/inspector/debugger/command-line-api-exception-nested-catch.html	                        (rev 0)
+++ trunk/LayoutTests/inspector/debugger/command-line-api-exception-nested-catch.html	2014-11-19 23:49:36 UTC (rev 176357)
@@ -0,0 +1,84 @@
+<!doctype html>
+<html>
+<head>
+<script type="text/_javascript_" src=""
+<script type="text/_javascript_" src=""
+<script>
+function triggerException()
+{
+    // We expect uncaught exceptions, so avoid logs for them.
+    window._onerror_ = function(){};
+    setTimeout(nestedCatchBlocks, 0);
+}
+
+function test()
+{
+    WebInspector.debuggerManager.allExceptionsBreakpoint.disabled = false;
+
+    function dumpCommandLineAPIValue(prefix) {
+        WebInspector.runtimeManager.evaluateInInspectedWindow("$exception", "test", true, true, false, function(result, wasThrown) {
+            InspectorTest.log(prefix + ": $exception => " + result.description);
+        });
+    }
+
+    function checkIfExceptionValueMatchesVariable(varName) {
+        WebInspector.runtimeManager.evaluateInInspectedWindow("$exception === " + varName, "test", true, true, false, function(result, wasThrown) {
+            InspectorTest.log("  CATCH: $exception === " + varName + " ? " + result.description);
+        });
+    }
+
+    var done = false;
+    var phase = 0;
+
+    WebInspector.debuggerManager.addEventListener(WebInspector.DebuggerManager.Event.CallFramesDidChange, function(event) {
+        if (done)
+            return;
+
+        phase++;
+
+        // Skip past the first pause to the second pause.
+        if (phase === 1) {
+            dumpCommandLineAPIValue("OUTER 1");
+            WebInspector.debuggerManager.resume();
+            return;
+        }
+
+        // Paused on the exception in the inner try, step over to get into the inner catch.
+        if (phase === 2) {
+            dumpCommandLineAPIValue("INNER 1");
+            WebInspector.debuggerManager.stepOver();
+            return;
+        }
+
+        // Paused in the inner catch, verify $exception is "inner exception".
+        if (phase === 3) {
+            dumpCommandLineAPIValue("INNER 2");
+            checkIfExceptionValueMatchesVariable("e2");
+            WebInspector.debuggerManager.stepOver();
+            return;
+        }
+        
+        // Stepped into the outer catch, verify $exception is "outer exception".
+        if (phase === 4) {
+            dumpCommandLineAPIValue("OUTER 2");
+            checkIfExceptionValueMatchesVariable("e1");
+            WebInspector.debuggerManager.resume();
+            return;
+        }
+    });
+
+    WebInspector.debuggerManager.addEventListener(WebInspector.DebuggerManager.Event.Resumed, function(event) {
+        done = true;
+        dumpCommandLineAPIValue("AFTER  ");
+        InspectorTest.completeTest();
+    });
+
+    dumpCommandLineAPIValue("BEFORE ");
+    InspectorTest.evaluateInPage("triggerException()");
+}
+</script>
+</head>
+<body _onload_="runTest()">
+    <p>Checks that <code>$exception</code> is the value of the current exception, even in nested catch blocks.</p>
+</body>
+</html>

Added: trunk/LayoutTests/inspector/debugger/command-line-api-exception.html (0 => 176357)


--- trunk/LayoutTests/inspector/debugger/command-line-api-exception.html	                        (rev 0)
+++ trunk/LayoutTests/inspector/debugger/command-line-api-exception.html	2014-11-19 23:49:36 UTC (rev 176357)
@@ -0,0 +1,98 @@
+<!doctype html>
+<html>
+<head>
+<script type="text/_javascript_" src=""
+<script type="text/_javascript_" src=""
+<script>
+var exceptionIndex = 0;
+var exceptionCausers = [
+    triggerUncaughtTypeException,
+    triggerUncaughtReferenceException,
+    triggerUncaughtSyntaxException,
+    triggerUncaughtDOMException,
+    throwString,
+    throwNumber,
+    throwNull,
+    throwObject,
+    throwNode,
+    function() { catcher(triggerUncaughtTypeException); },
+    function() { catcher(throwString); },
+    function() { catcher(throwObject); },
+];
+
+
+function triggerNextException()
+{
+    // We expect uncaught exceptions, so avoid logs for them.
+    window._onerror_ = function(){};
+
+    setTimeout(function() {
+        exceptionCausers[exceptionIndex++]();
+    }, 0);
+}
+
+function test()
+{
+    WebInspector.debuggerManager.allExceptionsBreakpoint.disabled = false;
+
+    function triggerNextException() {
+        InspectorTest.evaluateInPage("triggerNextException()");
+    }
+
+    function dumpCommandLineAPIValue(prefix) {
+        WebInspector.runtimeManager.evaluateInInspectedWindow("$exception", "test", true, true, false, function(result, wasThrown) {
+            InspectorTest.log(prefix + ": $exception => " + result.description);
+        });
+    }
+
+    function checkIfExceptionValueMatchesCatchVariable() {
+        WebInspector.runtimeManager.evaluateInInspectedWindow("$exception === e", "test", true, true, false, function(result, wasThrown) {
+            InspectorTest.log("STEPPED OUT TO CATCH BLOCK: $exception === e ? " + result.description);
+        });
+    }
+
+    var pauses = 0;
+    var stepping = false;
+    var done = false;
+    const pointWhereExpectionsAreBeingCaught = 9;
+    const expectedPauses = 12;
+
+    WebInspector.debuggerManager.addEventListener(WebInspector.DebuggerManager.Event.CallFramesDidChange, function(event) {
+        if (done)
+            return;
+
+        if (!stepping) {
+            dumpCommandLineAPIValue("PAUSE #" + (++pauses));
+            if (pauses > pointWhereExpectionsAreBeingCaught) {
+                WebInspector.debuggerManager.stepOut();
+                stepping = true;
+                return;
+            }
+        } else {
+            checkIfExceptionValueMatchesCatchVariable();
+            stepping = false;
+        }
+
+        WebInspector.debuggerManager.resume();
+
+        if (pauses !== expectedPauses) {
+            triggerNextException();
+            return;
+        }
+    });
+
+    WebInspector.debuggerManager.addEventListener(WebInspector.DebuggerManager.Event.Resumed, function(event) {
+        done = true;
+        dumpCommandLineAPIValue("AFTER");
+        InspectorTest.completeTest();
+    });
+
+    dumpCommandLineAPIValue("BEFORE");
+    triggerNextException();
+}
+</script>
+</head>
+<body _onload_="runTest()">
+    <p>Checks that <code>$exception</code> is available and accurate in evaluations when paused on an exception.</p>
+</body>
+</html>

Added: trunk/LayoutTests/inspector/debugger/resources/exceptions.js (0 => 176357)


--- trunk/LayoutTests/inspector/debugger/resources/exceptions.js	                        (rev 0)
+++ trunk/LayoutTests/inspector/debugger/resources/exceptions.js	2014-11-19 23:49:36 UTC (rev 176357)
@@ -0,0 +1,71 @@
+function triggerUncaughtTypeException()
+{
+    // Exception: TypeError: undefined is not an object (evaluating '[].x.x')
+    [].x.x;
+}
+
+function triggerUncaughtReferenceException()
+{
+    // Exception: ReferenceError: Can't find variable: variableThatDoesNotExist
+    variableThatDoesNotExist += 1;
+}
+
+function triggerUncaughtSyntaxException()
+{
+    // Exception: SyntaxError: Unexpected token ')'
+    eval("if()");
+}
+
+function triggerUncaughtDOMException()
+{
+    // Error: IndexSizeError: DOM Exception 1
+    document.createTextNode("").splitText(100);
+}
+
+function throwString()
+{
+    throw "thrown string";
+}
+
+function throwNumber()
+{
+    throw 123.456;
+}
+
+function throwNull()
+{
+    throw null;
+}
+
+function throwObject()
+{
+    throw {x:1,y:2};
+}
+
+function throwNode()
+{
+    throw document.body;
+}
+
+function catcher(func)
+{
+    try {
+        func();
+    } catch (e) {
+        console.log("CATCHER: " + e);
+    }
+}
+
+function nestedCatchBlocks()
+{
+    try {
+        throw "outer exception";
+    } catch (e1) {
+        try {
+            throw "inner exception";
+        } catch (e2) {
+            console.log(e2);
+        }
+        console.log(e1);
+    }
+}

Modified: trunk/Source/_javascript_Core/ChangeLog (176356 => 176357)


--- trunk/Source/_javascript_Core/ChangeLog	2014-11-19 23:48:53 UTC (rev 176356)
+++ trunk/Source/_javascript_Core/ChangeLog	2014-11-19 23:49:36 UTC (rev 176357)
@@ -1,5 +1,63 @@
 2014-11-19  Joseph Pecoraro  <[email protected]>
 
+        Web Inspector: Provide $exception in the console for the thrown exception value
+        https://bugs.webkit.org/show_bug.cgi?id=138726
+
+        Reviewed by Timothy Hatcher.
+
+        * debugger/DebuggerScope.cpp:
+        (JSC::DebuggerScope::caughtValue):
+        * debugger/DebuggerScope.h:
+        Access the caught value if this scope is a catch scope.
+
+        * runtime/JSNameScope.h:
+        (JSC::JSNameScope::isFunctionNameScope):
+        (JSC::JSNameScope::isCatchScope):
+        (JSC::JSNameScope::value):
+        Provide an accessor for the single value in the JSNameScope (with / catch block).
+
+        * inspector/InjectedScriptSource.js:
+        Save the exception value and expose it via $exception. Since the command line api
+        is recreated on each evaluation, $exception is essentially readonly.
+
+        * inspector/ScriptDebugServer.h:
+        * inspector/ScriptDebugServer.cpp:
+        (Inspector::ScriptDebugServer::dispatchDidPause):
+        (Inspector::ScriptDebugServer::exceptionOrCaughtValue):
+        When pausing, get the exception or caught value. The exception will be provided
+        if we are breaking on an explicit exception. When inside of a catch block, we
+        can get the caught value by walking up the scope chain.
+
+        * inspector/agents/InspectorDebuggerAgent.h:
+        * inspector/agents/InspectorDebuggerAgent.cpp:
+        (Inspector::InspectorDebuggerAgent::InspectorDebuggerAgent):
+        (Inspector::InspectorDebuggerAgent::resume):
+        (Inspector::InspectorDebuggerAgent::stepOver):
+        (Inspector::InspectorDebuggerAgent::stepInto):
+        (Inspector::InspectorDebuggerAgent::stepOut):
+        Clearing state can be done in didContinue.
+
+        (Inspector::InspectorDebuggerAgent::didPause):
+        Set the exception value explicitly in the injected script when we have it.
+
+        (Inspector::InspectorDebuggerAgent::didContinue):
+        Clear state saved when we had paused, including clearly an exception value if needed.
+
+        (Inspector::InspectorDebuggerAgent::clearDebuggerBreakpointState):
+        (Inspector::InspectorDebuggerAgent::clearExceptionValue):
+        Call into the injected script only when needed.
+
+        * inspector/InjectedScript.cpp:
+        (Inspector::InjectedScript::setExceptionValue):
+        (Inspector::InjectedScript::clearExceptionValue):
+        * inspector/InjectedScript.h:
+        * inspector/InjectedScriptManager.cpp:
+        (Inspector::InjectedScriptManager::clearExceptionValue):
+        * inspector/InjectedScriptManager.h:
+        Clear on all injected scripts.
+
+2014-11-19  Joseph Pecoraro  <[email protected]>
+
         Unreviewed build fixes after r176329.
 
           - export all of the codegen python files as they are included by the main generator

Modified: trunk/Source/_javascript_Core/debugger/DebuggerScope.cpp (176356 => 176357)


--- trunk/Source/_javascript_Core/debugger/DebuggerScope.cpp	2014-11-19 23:48:53 UTC (rev 176356)
+++ trunk/Source/_javascript_Core/debugger/DebuggerScope.cpp	2014-11-19 23:49:36 UTC (rev 176357)
@@ -183,4 +183,10 @@
     return m_scope->isActivationObject();
 }
 
+JSValue DebuggerScope::caughtValue() const
+{
+    ASSERT(isCatchScope());
+    return reinterpret_cast<JSNameScope*>(m_scope.get())->value();
+}
+
 } // namespace JSC

Modified: trunk/Source/_javascript_Core/debugger/DebuggerScope.h (176356 => 176357)


--- trunk/Source/_javascript_Core/debugger/DebuggerScope.h	2014-11-19 23:48:53 UTC (rev 176356)
+++ trunk/Source/_javascript_Core/debugger/DebuggerScope.h	2014-11-19 23:49:36 UTC (rev 176357)
@@ -90,6 +90,8 @@
     bool isGlobalScope() const;
     bool isFunctionOrEvalScope() const;
 
+    JSValue caughtValue() const;
+
 private:
     JS_EXPORT_PRIVATE DebuggerScope(VM&, JSScope*);
     JS_EXPORT_PRIVATE void finishCreation(VM&);

Modified: trunk/Source/_javascript_Core/inspector/InjectedScript.cpp (176356 => 176357)


--- trunk/Source/_javascript_Core/inspector/InjectedScript.cpp	2014-11-19 23:48:53 UTC (rev 176356)
+++ trunk/Source/_javascript_Core/inspector/InjectedScript.cpp	2014-11-19 23:49:36 UTC (rev 176357)
@@ -202,6 +202,23 @@
     return BindingTraits<Inspector::Protocol::Runtime::RemoteObject>::runtimeCast(resultObject);
 }
 
+void InjectedScript::setExceptionValue(const Deprecated::ScriptValue& value)
+{
+    ASSERT(!hasNoValue());
+    Deprecated::ScriptFunctionCall function(injectedScriptObject(), ASCIILiteral("setExceptionValue"), inspectorEnvironment()->functionCallHandler());
+    function.appendArgument(value);
+    RefPtr<InspectorValue> result;
+    makeCall(function, &result);
+}
+
+void InjectedScript::clearExceptionValue()
+{
+    ASSERT(!hasNoValue());
+    Deprecated::ScriptFunctionCall function(injectedScriptObject(), ASCIILiteral("clearExceptionValue"), inspectorEnvironment()->functionCallHandler());
+    RefPtr<InspectorValue> result;
+    makeCall(function, &result);
+}
+
 Deprecated::ScriptValue InjectedScript::findObjectById(const String& objectId) const
 {
     ASSERT(!hasNoValue());

Modified: trunk/Source/_javascript_Core/inspector/InjectedScript.h (176356 => 176357)


--- trunk/Source/_javascript_Core/inspector/InjectedScript.h	2014-11-19 23:48:53 UTC (rev 176356)
+++ trunk/Source/_javascript_Core/inspector/InjectedScript.h	2014-11-19 23:49:36 UTC (rev 176357)
@@ -66,6 +66,9 @@
     PassRefPtr<Protocol::Runtime::RemoteObject> wrapObject(const Deprecated::ScriptValue&, const String& groupName, bool generatePreview = false) const;
     PassRefPtr<Protocol::Runtime::RemoteObject> wrapTable(const Deprecated::ScriptValue& table, const Deprecated::ScriptValue& columns) const;
 
+    void setExceptionValue(const Deprecated::ScriptValue&);
+    void clearExceptionValue();
+
     Deprecated::ScriptValue findObjectById(const String& objectId) const;
     void inspectObject(Deprecated::ScriptValue);
     void releaseObject(const String& objectId);

Modified: trunk/Source/_javascript_Core/inspector/InjectedScriptManager.cpp (176356 => 176357)


--- trunk/Source/_javascript_Core/inspector/InjectedScriptManager.cpp	2014-11-19 23:48:53 UTC (rev 176356)
+++ trunk/Source/_javascript_Core/inspector/InjectedScriptManager.cpp	2014-11-19 23:49:36 UTC (rev 176357)
@@ -118,10 +118,16 @@
 
 void InjectedScriptManager::releaseObjectGroup(const String& objectGroup)
 {
-    for (auto it = m_idToInjectedScript.begin(); it != m_idToInjectedScript.end(); ++it)
-        it->value.releaseObjectGroup(objectGroup);
+    for (auto& injectedScript : m_idToInjectedScript.values())
+        injectedScript.releaseObjectGroup(objectGroup);
 }
 
+void InjectedScriptManager::clearExceptionValue()
+{
+    for (auto& injectedScript : m_idToInjectedScript.values())
+        injectedScript.clearExceptionValue();
+}
+
 String InjectedScriptManager::injectedScriptSource()
 {
     return StringImpl::createWithoutCopying(InjectedScriptSource_js, sizeof(InjectedScriptSource_js));

Modified: trunk/Source/_javascript_Core/inspector/InjectedScriptManager.h (176356 => 176357)


--- trunk/Source/_javascript_Core/inspector/InjectedScriptManager.h	2014-11-19 23:48:53 UTC (rev 176356)
+++ trunk/Source/_javascript_Core/inspector/InjectedScriptManager.h	2014-11-19 23:49:36 UTC (rev 176357)
@@ -66,6 +66,7 @@
     InjectedScript injectedScriptForObjectId(const String& objectId);
     void discardInjectedScripts();
     void releaseObjectGroup(const String& objectGroup);
+    void clearExceptionValue();
 
 protected:
     virtual void didCreateInjectedScript(InjectedScript);

Modified: trunk/Source/_javascript_Core/inspector/InjectedScriptSource.js (176356 => 176357)


--- trunk/Source/_javascript_Core/inspector/InjectedScriptSource.js	2014-11-19 23:48:53 UTC (rev 176356)
+++ trunk/Source/_javascript_Core/inspector/InjectedScriptSource.js	2014-11-19 23:49:36 UTC (rev 176357)
@@ -86,6 +86,16 @@
         return this._fallbackWrapper(object);
     },
 
+    setExceptionValue: function(value)
+    {
+        this._exceptionValue = value;
+    },
+
+    clearExceptionValue: function()
+    {
+        delete this._exceptionValue;
+    },
+
     /**
      * @param {*} object
      * @return {!RuntimeAgent.RemoteObject}
@@ -1041,6 +1051,7 @@
 function BasicCommandLineAPI()
 {
     this.$_ = injectedScript._lastResult;
+    this.$exception = injectedScript._exceptionValue;
 }
 
 return injectedScript;

Modified: trunk/Source/_javascript_Core/inspector/ScriptDebugServer.cpp (176356 => 176357)


--- trunk/Source/_javascript_Core/inspector/ScriptDebugServer.cpp	2014-11-19 23:48:53 UTC (rev 176356)
+++ trunk/Source/_javascript_Core/inspector/ScriptDebugServer.cpp	2014-11-19 23:49:36 UTC (rev 176357)
@@ -138,8 +138,8 @@
     JSC::ExecState* state = globalObject->globalExec();
     RefPtr<_javascript_CallFrame> _javascript_CallFrame = _javascript_CallFrame::create(debuggerCallFrame);
     JSValue jsCallFrame = toJS(state, globalObject, _javascript_CallFrame.get());
-    Deprecated::ScriptValue exception = reasonForPause() == PausedForException ? Deprecated::ScriptValue(state->vm(), currentException()) : Deprecated::ScriptValue();
-    listener->didPause(state, Deprecated::ScriptValue(state->vm(), jsCallFrame), exception);
+
+    listener->didPause(state, Deprecated::ScriptValue(state->vm(), jsCallFrame), exceptionOrCaughtValue(state));
 }
 
 void ScriptDebugServer::dispatchBreakpointActionLog(ExecState* exec, const String& message)
@@ -327,6 +327,22 @@
     return emptyActionVector;
 }
 
+Deprecated::ScriptValue ScriptDebugServer::exceptionOrCaughtValue(JSC::ExecState* state)
+{
+    if (reasonForPause() == PausedForException)
+        return Deprecated::ScriptValue(state->vm(), currentException());
+
+    RefPtr<DebuggerCallFrame> debuggerCallFrame = currentDebuggerCallFrame();
+    while (debuggerCallFrame) {
+        DebuggerScope* scope = debuggerCallFrame->scope();
+        if (scope->isCatchScope())
+            return Deprecated::ScriptValue(state->vm(), scope->caughtValue());
+        debuggerCallFrame = debuggerCallFrame->callerFrame();
+    }
+
+    return Deprecated::ScriptValue();
+}
+
 } // namespace Inspector
 
 #endif // ENABLE(INSPECTOR)

Modified: trunk/Source/_javascript_Core/inspector/ScriptDebugServer.h (176356 => 176357)


--- trunk/Source/_javascript_Core/inspector/ScriptDebugServer.h	2014-11-19 23:48:53 UTC (rev 176356)
+++ trunk/Source/_javascript_Core/inspector/ScriptDebugServer.h	2014-11-19 23:49:36 UTC (rev 176357)
@@ -105,6 +105,8 @@
     virtual void handlePause(JSC::Debugger::ReasonForPause, JSC::JSGlobalObject*) override final;
     virtual void notifyDoneProcessingDebuggerEvents() override final;
 
+    Deprecated::ScriptValue exceptionOrCaughtValue(JSC::ExecState*);
+
     unsigned m_hitCount;
     bool m_callingListeners;
     BreakpointIDToActionsMap m_breakpointIDToActions;

Modified: trunk/Source/_javascript_Core/inspector/agents/InspectorDebuggerAgent.cpp (176356 => 176357)


--- trunk/Source/_javascript_Core/inspector/agents/InspectorDebuggerAgent.cpp	2014-11-19 23:48:53 UTC (rev 176356)
+++ trunk/Source/_javascript_Core/inspector/agents/InspectorDebuggerAgent.cpp	2014-11-19 23:49:36 UTC (rev 176357)
@@ -65,6 +65,7 @@
     , m_continueToLocationBreakpointID(JSC::noBreakpointID)
     , m_enabled(false)
     , m_javaScriptPauseScheduled(false)
+    , m_hasExceptionValue(false)
     , m_nextProbeSampleId(1)
 {
     // FIXME: make breakReason optional so that there was no need to init it with "other".
@@ -468,7 +469,6 @@
     if (!assertPaused(errorString))
         return;
 
-    m_injectedScriptManager->releaseObjectGroup(InspectorDebuggerAgent::backtraceObjectGroup);
     scriptDebugServer().continueProgram();
 }
 
@@ -477,7 +477,6 @@
     if (!assertPaused(errorString))
         return;
 
-    m_injectedScriptManager->releaseObjectGroup(InspectorDebuggerAgent::backtraceObjectGroup);
     scriptDebugServer().stepOverStatement();
 }
 
@@ -486,7 +485,6 @@
     if (!assertPaused(errorString))
         return;
 
-    m_injectedScriptManager->releaseObjectGroup(InspectorDebuggerAgent::backtraceObjectGroup);
     scriptDebugServer().stepIntoStatement();
 
     if (m_listener)
@@ -498,7 +496,6 @@
     if (!assertPaused(errorString))
         return;
 
-    m_injectedScriptManager->releaseObjectGroup(InspectorDebuggerAgent::backtraceObjectGroup);
     scriptDebugServer().stepOutOfFunction();
 }
 
@@ -643,6 +640,8 @@
             m_breakReason = InspectorDebuggerFrontendDispatcher::Reason::Exception;
             m_breakAuxData = injectedScript.wrapObject(exception, InspectorDebuggerAgent::backtraceObjectGroup)->openAccessors();
             // m_breakAuxData might be null after this.
+            injectedScript.setExceptionValue(exception);
+            m_hasExceptionValue = true;
         }
     }
 
@@ -687,8 +686,10 @@
 {
     m_pausedScriptState = nullptr;
     m_currentCallStack = Deprecated::ScriptValue();
+    m_injectedScriptManager->releaseObjectGroup(InspectorDebuggerAgent::backtraceObjectGroup);
     m_injectedScriptManager->inspectorEnvironment().executionStopwatch()->start();
     clearBreakDetails();
+    clearExceptionValue();
 
     m_frontendDispatcher->resumed();
 }
@@ -724,6 +725,7 @@
     m_continueToLocationBreakpointID = JSC::noBreakpointID;
     clearBreakDetails();
     m_javaScriptPauseScheduled = false;
+    m_hasExceptionValue = false;
 
     scriptDebugServer().continueProgram();
 }
@@ -754,6 +756,14 @@
     m_breakAuxData = nullptr;
 }
 
+void InspectorDebuggerAgent::clearExceptionValue()
+{
+    if (m_hasExceptionValue) {
+        m_injectedScriptManager->clearExceptionValue();
+        m_hasExceptionValue = false;
+    }
+}
+
 } // namespace Inspector
 
 #endif // ENABLE(INSPECTOR)

Modified: trunk/Source/_javascript_Core/inspector/agents/InspectorDebuggerAgent.h (176356 => 176357)


--- trunk/Source/_javascript_Core/inspector/agents/InspectorDebuggerAgent.h	2014-11-19 23:48:53 UTC (rev 176356)
+++ trunk/Source/_javascript_Core/inspector/agents/InspectorDebuggerAgent.h	2014-11-19 23:49:36 UTC (rev 176357)
@@ -146,6 +146,7 @@
     void clearDebuggerBreakpointState();
     void clearInspectorBreakpointState();
     void clearBreakDetails();
+    void clearExceptionValue();
 
     bool breakpointActionsFromProtocol(ErrorString&, RefPtr<InspectorArray>& actions, BreakpointActions* result);
 
@@ -167,6 +168,7 @@
     RefPtr<InspectorObject> m_breakAuxData;
     bool m_enabled;
     bool m_javaScriptPauseScheduled;
+    bool m_hasExceptionValue;
     RefPtr<WTF::Stopwatch> m_stopwatch;
     int m_nextProbeSampleId;
 };

Modified: trunk/Source/_javascript_Core/runtime/JSNameScope.h (176356 => 176357)


--- trunk/Source/_javascript_Core/runtime/JSNameScope.h	2014-11-19 23:48:53 UTC (rev 176356)
+++ trunk/Source/_javascript_Core/runtime/JSNameScope.h	2014-11-19 23:49:36 UTC (rev 176357)
@@ -65,9 +65,11 @@
 
     DECLARE_INFO;
 
-    bool isFunctionNameScope() { return m_type == FunctionNameScope; }
-    bool isCatchScope() { return m_type == CatchScope; }
+    bool isFunctionNameScope() const { return m_type == FunctionNameScope; }
+    bool isCatchScope() const { return m_type == CatchScope; }
 
+    JSValue value() const { return m_registerStore.get(); }
+
 protected:
     void finishCreation(VM& vm, const Identifier& identifier, JSValue value, unsigned attributes)
     {

Modified: trunk/Source/WebCore/ChangeLog (176356 => 176357)


--- trunk/Source/WebCore/ChangeLog	2014-11-19 23:48:53 UTC (rev 176356)
+++ trunk/Source/WebCore/ChangeLog	2014-11-19 23:49:36 UTC (rev 176357)
@@ -1,3 +1,16 @@
+2014-11-19  Joseph Pecoraro  <[email protected]>
+
+        Web Inspector: Provide $exception in the console for the thrown exception value
+        https://bugs.webkit.org/show_bug.cgi?id=138726
+
+        Reviewed by Timothy Hatcher.
+
+        Tests: inspector/debugger/command-line-api-exception-nested-catch.html
+               inspector/debugger/command-line-api-exception.html
+
+        * inspector/CommandLineAPIModuleSource.js:
+        Expose $exception in the more complete command line API.
+
 2014-11-19  David Hyatt  <[email protected]>
 
         Images/replaced elements that are as tall as a page should be on their own page

Modified: trunk/Source/WebCore/inspector/CommandLineAPIModuleSource.js (176356 => 176357)


--- trunk/Source/WebCore/inspector/CommandLineAPIModuleSource.js	2014-11-19 23:48:53 UTC (rev 176356)
+++ trunk/Source/WebCore/inspector/CommandLineAPIModuleSource.js	2014-11-19 23:49:36 UTC (rev 176357)
@@ -124,6 +124,7 @@
     }
 
     this.$_ = injectedScript._lastResult;
+    this.$exception = injectedScript._exceptionValue;
 }
 
 /**

Modified: trunk/Source/WebInspectorUI/ChangeLog (176356 => 176357)


--- trunk/Source/WebInspectorUI/ChangeLog	2014-11-19 23:48:53 UTC (rev 176356)
+++ trunk/Source/WebInspectorUI/ChangeLog	2014-11-19 23:49:36 UTC (rev 176357)
@@ -1,5 +1,20 @@
 2014-11-19  Joseph Pecoraro  <[email protected]>
 
+        Web Inspector: Provide $exception in the console for the thrown exception value
+        https://bugs.webkit.org/show_bug.cgi?id=138726
+
+        Reviewed by Timothy Hatcher.
+
+        * UserInterface/Base/Test.js:
+        (WebInspector.loaded):
+        In order to use RuntimeManager to execute in the global context or on the
+        active debugger call frame, we need to expose the quickConsole controller.
+
+        * UserInterface/Controllers/_javascript_RuntimeCompletionProvider.js:
+        Expose $exception to completion when we paused because of an exception.
+
+2014-11-19  Joseph Pecoraro  <[email protected]>
+
         Web Inspector: Debugger should not mutate variable when hovering mouse over ++n _expression_
         https://bugs.webkit.org/show_bug.cgi?id=138839
 

Modified: trunk/Source/WebInspectorUI/UserInterface/Base/Test.js (176356 => 176357)


--- trunk/Source/WebInspectorUI/UserInterface/Base/Test.js	2014-11-19 23:48:53 UTC (rev 176356)
+++ trunk/Source/WebInspectorUI/UserInterface/Base/Test.js	2014-11-19 23:49:36 UTC (rev 176357)
@@ -56,6 +56,9 @@
     this.probeManager = new WebInspector.ProbeManager;
     this.replayManager = new WebInspector.ReplayManager;
 
+    // Global controllers.
+    this.quickConsole = {executionContextIdentifier: undefined};
+
     document.addEventListener("DOMContentLoaded", this.contentLoaded.bind(this));
 
     // Enable agents.

Modified: trunk/Source/WebInspectorUI/UserInterface/Controllers/_javascript_RuntimeCompletionProvider.js (176356 => 176357)


--- trunk/Source/WebInspectorUI/UserInterface/Controllers/_javascript_RuntimeCompletionProvider.js	2014-11-19 23:48:53 UTC (rev 176356)
+++ trunk/Source/WebInspectorUI/UserInterface/Controllers/_javascript_RuntimeCompletionProvider.js	2014-11-19 23:49:36 UTC (rev 176357)
@@ -174,7 +174,9 @@
             RuntimeAgent.releaseObjectGroup("completion");
 
             if (!base) {
-                const commandLineAPI = ["$", "$$", "$x", "dir", "dirxml", "keys", "values", "profile", "profileEnd", "monitorEvents", "unmonitorEvents", "inspect", "copy", "clear", "getEventListeners", "$0", "$1", "$2", "$3", "$4", "$_"];
+                var commandLineAPI = ["$", "$$", "$x", "dir", "dirxml", "keys", "values", "profile", "profileEnd", "monitorEvents", "unmonitorEvents", "inspect", "copy", "clear", "getEventListeners", "$0", "$1", "$2", "$3", "$4", "$_"];
+                if (WebInspector.debuggerManager.paused && WebInspector.debuggerManager.pauseReason === WebInspector.DebuggerManager.PauseReason.Exception)
+                    commandLineAPI.push("$exception");
                 for (var i = 0; i < commandLineAPI.length; ++i)
                     propertyNames[commandLineAPI[i]] = true;
             }
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to