ScriptExecutionContext log exception should include a column number
authorjoepeck@webkit.org <joepeck@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 25 Apr 2013 19:31:50 +0000 (19:31 +0000)
committerjoepeck@webkit.org <joepeck@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 25 Apr 2013 19:31:50 +0000 (19:31 +0000)
https://bugs.webkit.org/show_bug.cgi?id=114315

Reviewed by Oliver Hunt.

Source/WebCore:

Test: inspector/console/console-exception-stack-traces.html

* bindings/js/ScriptCallStackFactory.h:
* bindings/js/ScriptCallStackFactory.cpp:
(WebCore::createScriptCallStackFromException):
Generate a ScriptCallStack from an exception. Use the vm.exceptionStack
if available, and fallback to the exception object where needed.

* bindings/js/JSDOMBinding.cpp:
(WebCore::reportException):
Always include a non-empty call stack with exceptions.
Where not provided, fallback to the exception object.

* dom/Document.h:
* dom/Document.cpp:
(WebCore::Document::logExceptionToConsole):
* dom/ScriptExecutionContext.h:
* dom/ScriptExecutionContext.cpp:
(WebCore::ScriptExecutionContext::PendingException::PendingException):
(ScriptExecutionContext::PendingException):
(WebCore::ScriptExecutionContext::reportException):
* workers/DefaultSharedWorkerRepository.cpp:
* workers/SharedWorkerContext.cpp:
(WebCore::SharedWorkerContext::logExceptionToConsole):
* workers/SharedWorkerContext.h:
* workers/WorkerContext.cpp:
(WebCore::WorkerContext::logExceptionToConsole):
* workers/WorkerContext.h:
* workers/WorkerMessagingProxy.cpp:
(WebCore::WorkerExceptionTask::performTask):
Plumb columnNumber through as needed.

LayoutTests:

* inspector/console/console-exception-stack-traces-expected.txt: Added.
* inspector/console/console-exception-stack-traces.html: Added.
Verifies that exceptions have stack traces and match a console.trace stack.

* http/tests/inspector-enabled/console-exception-while-no-inspector-expected.txt: Removed.
* http/tests/inspector-enabled/console-exception-while-no-inspector.html: Removed.
We now save exception backtraces even if the inspector is not open.

* fast/dom/javascript-url-exception-isolation-expected.txt
* fast/events/remove-target-with-shadow-in-drag-expected.txt
* fast/events/set-attribute-listener-window-onerror-crash-expected.txt
* inspector-protocol/media-query-listener-exception-expected.txt:
* inspector/console/console-uncaught-exception-expected.txt:
* inspector/console/console-uncaught-exception-in-eval-expected.txt:
Update results that now include backtraces or different data. Most better, some worse.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@149131 268f45cc-cd09-0410-ab3c-d52691b4dbfc

25 files changed:
LayoutTests/ChangeLog
LayoutTests/fast/dom/javascript-url-exception-isolation-expected.txt
LayoutTests/fast/events/remove-target-with-shadow-in-drag-expected.txt
LayoutTests/fast/events/set-attribute-listener-window-onerror-crash-expected.txt
LayoutTests/http/tests/inspector-enabled/console-exception-while-no-inspector-expected.txt [deleted file]
LayoutTests/http/tests/inspector-enabled/console-exception-while-no-inspector.html [deleted file]
LayoutTests/inspector-protocol/media-query-listener-exception-expected.txt
LayoutTests/inspector/console/console-exception-stack-traces-expected.txt [new file with mode: 0644]
LayoutTests/inspector/console/console-exception-stack-traces.html [new file with mode: 0644]
LayoutTests/inspector/console/console-uncaught-exception-expected.txt
LayoutTests/inspector/console/console-uncaught-exception-in-eval-expected.txt
Source/WebCore/ChangeLog
Source/WebCore/bindings/js/JSDOMBinding.cpp
Source/WebCore/bindings/js/ScriptCallStackFactory.cpp
Source/WebCore/bindings/js/ScriptCallStackFactory.h
Source/WebCore/dom/Document.cpp
Source/WebCore/dom/Document.h
Source/WebCore/dom/ScriptExecutionContext.cpp
Source/WebCore/dom/ScriptExecutionContext.h
Source/WebCore/workers/DefaultSharedWorkerRepository.cpp
Source/WebCore/workers/SharedWorkerContext.cpp
Source/WebCore/workers/SharedWorkerContext.h
Source/WebCore/workers/WorkerContext.cpp
Source/WebCore/workers/WorkerContext.h
Source/WebCore/workers/WorkerMessagingProxy.cpp

index 9490c9e15adbf574c76b89ef1e9c48e2aa85ae64..d8986ad02c524090547420a587344856de6cd65e 100644 (file)
@@ -1,3 +1,26 @@
+2013-04-25  Joseph Pecoraro  <pecoraro@apple.com>
+
+        ScriptExecutionContext log exception should include a column number
+        https://bugs.webkit.org/show_bug.cgi?id=114315
+
+        Reviewed by Oliver Hunt.
+
+        * inspector/console/console-exception-stack-traces-expected.txt: Added.
+        * inspector/console/console-exception-stack-traces.html: Added.
+        Verifies that exceptions have stack traces and match a console.trace stack.
+
+        * http/tests/inspector-enabled/console-exception-while-no-inspector-expected.txt: Removed.
+        * http/tests/inspector-enabled/console-exception-while-no-inspector.html: Removed.
+        We now save exception backtraces even if the inspector is not open.
+
+        * fast/dom/javascript-url-exception-isolation-expected.txt
+        * fast/events/remove-target-with-shadow-in-drag-expected.txt
+        * fast/events/set-attribute-listener-window-onerror-crash-expected.txt
+        * inspector-protocol/media-query-listener-exception-expected.txt:
+        * inspector/console/console-uncaught-exception-expected.txt:
+        * inspector/console/console-uncaught-exception-in-eval-expected.txt:
+        Update results that now include backtraces or different data. Most better, some worse.
+
 2013-04-25  Ryosuke Niwa  <rniwa@webkit.org>
 
         HTMLOptionsCollection's namedItem and name getter should return the first item
index b7485a1ef6b405b2bca9dfa88f68d2ec6da3ca11..cafca79747c51dc0c5d2971ad54e3ea8da2cdcd8 100644 (file)
@@ -1,5 +1,5 @@
 CONSOLE MESSAGE: line 1: 42
-CONSOLE MESSAGE: line 1: SyntaxError: Unexpected token '<'
+CONSOLE MESSAGE: line 18: SyntaxError: Unexpected token '<'
 Exceptions thrown in javascript URLs should not propagate to the main script.
 
 On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
index 45c119fe9b30cad2a50f1dff8c017119205afe7a..4669219fc7e766041756e4bbfde7c16d76351acf 100644 (file)
@@ -1,3 +1,3 @@
-CONSOLE MESSAGE: line 34: NotFoundError: DOM Exception 8: An attempt was made to reference a Node in a context where it does not exist.
-CONSOLE MESSAGE: line 34: NotFoundError: DOM Exception 8: An attempt was made to reference a Node in a context where it does not exist.
+CONSOLE MESSAGE: line 35: NotFoundError: DOM Exception 8: An attempt was made to reference a Node in a context where it does not exist.
+CONSOLE MESSAGE: line 35: NotFoundError: DOM Exception 8: An attempt was made to reference a Node in a context where it does not exist.
 PASS. DRT didn't crash.
index b5d9fffa8683ea383e1becbb5545407be16a1b0f..a23fe481c4a9a6c8bbe9f0c3933f0275152d6b9e 100644 (file)
@@ -1,2 +1,2 @@
-CONSOLE MESSAGE: line 16: SyntaxError: Unexpected token ';'
+CONSOLE MESSAGE: line 15: SyntaxError: Unexpected token ';'
 Test passes if it does not crash.
diff --git a/LayoutTests/http/tests/inspector-enabled/console-exception-while-no-inspector-expected.txt b/LayoutTests/http/tests/inspector-enabled/console-exception-while-no-inspector-expected.txt
deleted file mode 100644 (file)
index 1b6e71c..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-CONSOLE MESSAGE: line 6: 2013
-Tests that console will NOT contain stack trace for exception thrown when inspector front-end was closed. Bug 109427.
-
-SUCCESS: message doesn't have stack trace
-TEST COMPLETE.
-
diff --git a/LayoutTests/http/tests/inspector-enabled/console-exception-while-no-inspector.html b/LayoutTests/http/tests/inspector-enabled/console-exception-while-no-inspector.html
deleted file mode 100644 (file)
index 0504b43..0000000
+++ /dev/null
@@ -1,65 +0,0 @@
-<html>
-<head>
-<script src="../inspector/inspector-test.js"></script>
-<script>
-function throwException() {
-    throw 2013;
-}
-
-function baz()
-{
-    throwException();
-}
-
-function bar(callback)
-{
-    callback()
-}
-
-function foo()
-{
-    bar(baz.bind(this));
-}
-
-
-function handleLoaded()
-{
-    if (window.testRunner)
-        testRunner.waitUntilDone();
-    setTimeout(showInspectorAndRunTest, 0);
-    foo();
-}
-
-
-function showInspectorAndRunTest()
-{
-    if (window.testRunner)
-        testRunner.showWebInspector();
-    runTest();
-}
-
-function test()
-{
-    if (WebInspector.console.messages.length !== 1)
-        InspectorTest.addResult("FAIL: found too many console messages: " + WebInspector.console.messages.length);
-
-    var message = WebInspector.console.messages[0];
-    var stack = message.stackTrace;
-    if (stack)
-        InspectorTest.addResult("FAIL: found message with stack trace");
-    else
-        InspectorTest.addResult("SUCCESS: message doesn't have stack trace");
-
-    InspectorTest.addResult("TEST COMPLETE.");
-    InspectorTest.completeTest();
-}
-
-</script>
-
-</head>
-<body onload="handleLoaded()">
-<p>
-Tests that console will NOT contain stack trace for exception thrown when inspector front-end was closed. <a href="https://bugs.webkit.org/show_bug.cgi?id=109427">Bug 109427.</a>
-</p>
-</body>
-</html>
index 522bcef16e44bdb7d66c11706ae33ab4ac2e566d..3fc69948385f4c36b74b583e85e5b96e3d44a103 100644 (file)
@@ -1,5 +1,5 @@
-CONSOLE MESSAGE: line 13: 
-CONSOLE MESSAGE: line 13: 
+CONSOLE MESSAGE: line 13: ReferenceError: Can't find variable: objectThatDoesNotExist
+CONSOLE MESSAGE: line 13: ReferenceError: Can't find variable: objectThatDoesNotExist
 Test that uncaught exception in MediaQueryListListener will be reported to the console. On success you should see two exceptions in the listener logged to the console (first time when the media type is overridden and second - when they are restored). Bug 105162.
 
 
diff --git a/LayoutTests/inspector/console/console-exception-stack-traces-expected.txt b/LayoutTests/inspector/console/console-exception-stack-traces-expected.txt
new file mode 100644 (file)
index 0000000..9e1d197
--- /dev/null
@@ -0,0 +1,13 @@
+CONSOLE MESSAGE: line 16: URIError: URI error
+CONSOLE MESSAGE: line 21: TypeError: '1' is not a function (evaluating '1()')
+CONSOLE MESSAGE: line 26: RangeError: Array size is not a small enough positive integer.
+CONSOLE MESSAGE: line 31: SyntaxError: Expected token '}'
+CONSOLE MESSAGE: line 36: ReferenceError: Can't find variable: doesNotExist
+CONSOLE MESSAGE: line 46: Error: Custom Error
+CONSOLE MESSAGE: line 51: [object Object]
+CONSOLE MESSAGE: line 56: error string
+CONSOLE MESSAGE: line 1: DONE
+Tests that JavaScript exception's contain stack traces and that the functions match console.trace() stack traces.
+
+SUCCESS
+
diff --git a/LayoutTests/inspector/console/console-exception-stack-traces.html b/LayoutTests/inspector/console/console-exception-stack-traces.html
new file mode 100644 (file)
index 0000000..4e83591
--- /dev/null
@@ -0,0 +1,132 @@
+<html>
+<head>
+<script src="../../http/tests/inspector/inspector-test.js"></script>
+<script>
+function wrapper(f) { wrapper2(f); }
+function wrapper2(f) { wrapper3(f); }
+function wrapper3(f) { wrapper4(f); }
+function wrapper4(f) { finalWrapper(f); }
+function finalWrapper(f) { produceError(f); }
+function produceError(f) {
+    f();
+}
+
+function uriError() {
+    console.trace();
+    decodeURI("%");
+}
+
+function typeError() {
+    console.trace();
+    1();
+}
+
+function rangeError() {
+    console.trace();
+    Array(-1).length;
+}
+
+function syntaxError() {
+    console.trace();
+    eval("{");
+}
+
+function referenceError() {
+    console.trace();
+    doesNotExist;
+}
+
+function domException() {
+    console.trace();
+    document.body.appendChild("should not be a string");
+}
+
+function throwErrorObject() {
+    console.trace();
+    throw new Error("Custom Error");
+}
+
+function throwObject() {
+    console.trace();
+    throw {name: "CustomErrorObjectName", message: "CustomErrorObjectMessage"};
+}
+
+function throwString() {
+    console.trace();
+    throw "error string";
+}
+
+function test()
+{
+    InspectorTest.addSniffer(WebInspector.ConsoleDispatcher.prototype, "messageAdded", messageAdded, true);
+
+    var hadError = false;
+    var traceStackTrace = null;
+    var errorStackTrace = null;
+
+    function messageAdded(payload)
+    {
+        if (payload.text === "DONE") {
+            InspectorTest.addResult(hadError ? "FAILURE" : "SUCCESS");
+            InspectorTest.completeTest();
+            return;
+        }
+
+        if (!traceStackTrace) {
+            if (payload.source === "console-api" && payload.type === "trace" && payload.stackTrace)
+                traceStackTrace = payload.stackTrace;
+            else {
+                InspectorTest.addResult("Expected console.trace() message with a stackTrace, but got: " + JSON.stringify(payload));
+                traceStackTrace = errorStackTrace = null;
+                hadError = true;
+                return;
+            }
+        } else if (!errorStackTrace) {
+            if (payload.source === "javascript" && payload.level === "error" && payload.stackTrace)
+                errorStackTrace = payload.stackTrace;
+            else {
+                InspectorTest.addResult("Expected JavaScript Error message with stackTrace but got: " + JSON.stringify(payload));
+                traceStackTrace = errorStackTrace = null;
+                hadError = true;
+                return;
+            }
+        }
+
+        if (traceStackTrace && errorStackTrace) {
+            var hadStackTraceDifference = false;
+            if (traceStackTrace.length !== errorStackTrace.length)
+                hadStackTraceDifference = true;
+            else {
+                for (var i = 0; i < traceStackTrace.length; ++i) {
+                    if (traceStackTrace[i].functionName !== errorStackTrace[i].functionName)
+                        hadStackTraceDifference = true;
+                }
+            }
+
+            if (hadStackTraceDifference) {
+                InspectorTest.addResult("Unexpected stack trace for JavaScript Error: " + payload.text);
+                hadError = true;
+            }
+
+            traceStackTrace = errorStackTrace = null;
+        }
+    }
+
+    InspectorTest.evaluateInPageWithTimeout("wrapper(uriError)");
+    InspectorTest.evaluateInPageWithTimeout("wrapper(typeError)");
+    InspectorTest.evaluateInPageWithTimeout("wrapper(rangeError)");
+    InspectorTest.evaluateInPageWithTimeout("wrapper(syntaxError)");
+    InspectorTest.evaluateInPageWithTimeout("wrapper(referenceError)");
+    InspectorTest.evaluateInPageWithTimeout("wrapper(throwErrorObject)");
+    InspectorTest.evaluateInPageWithTimeout("wrapper(throwObject)");
+    InspectorTest.evaluateInPageWithTimeout("wrapper(throwString)");
+    InspectorTest.evaluateInPageWithTimeout("console.log('DONE')");
+}
+</script>
+</head>
+
+<body onload="runTest()">
+<p>Tests that JavaScript exception's contain stack traces and that the functions match console.trace() stack traces.</p>
+
+</body>
+</html>
index 46cf0bb9d4c443d2642eb7cbd589fdbea1d10362..3a2cfe6deda317351f0666d4ec6f8c95b785f950 100644 (file)
@@ -4,7 +4,7 @@ CONSOLE MESSAGE: line 6: Error: Exception in setTimeout callback.
 Tests that uncaught exceptions are logged into console.Bug 47250.
 
 
-Error: Exception in inline script. resources/uncaught-in-iframe.html:18
-Error: Exception in 'load' event listener. resources/uncaught-in-iframe.html:11
-Error: Exception in setTimeout callback. uncaught-in-iframe.html:6
+Error: Exception in inline script. resources/uncaught-in-iframe.html:18a resources/uncaught-in-iframe.html:18b resources/uncaught-in-iframe.html:23
+Error: Exception in 'load' event listener. resources/uncaught-in-iframe.html:11f resources/uncaught-in-iframe.html:11(anonymous function) resources/uncaught-in-iframe.html:13
+Error: Exception in setTimeout callback. uncaught-in-iframe.html:6bar uncaught-in-iframe.html:6(anonymous function) uncaught-in-iframe.html:8
 
index 2bced13d22f77f2b52f91fe73f03d868f22bf46a..738e63ebc4ec2f8bfd7c624c8386b0b9458ec41d 100644 (file)
@@ -3,5 +3,5 @@ CONSOLE MESSAGE: line 4: Error: Exception in eval.
 Tests that when uncaught exception in eval'ed script ending with //@ sourceURL=url is logged into console, its stack trace will have the url as the script source. Bug 47252.
 
 Page reloaded.
-Error: Exception in eval.
+Error: Exception in eval. undefined:4b undefined:4aevalSource
 
index 28a08fba13bbadc7c3e2489234484a35b43ce6f8..cb4ed378642cfce403bbbebe42f1da0f366ac88c 100644 (file)
@@ -1,3 +1,42 @@
+2013-04-25  Joseph Pecoraro  <pecoraro@apple.com>
+
+        ScriptExecutionContext log exception should include a column number
+        https://bugs.webkit.org/show_bug.cgi?id=114315
+
+        Reviewed by Oliver Hunt.
+
+        Test: inspector/console/console-exception-stack-traces.html
+
+        * bindings/js/ScriptCallStackFactory.h:
+        * bindings/js/ScriptCallStackFactory.cpp:
+        (WebCore::createScriptCallStackFromException):
+        Generate a ScriptCallStack from an exception. Use the vm.exceptionStack
+        if available, and fallback to the exception object where needed.
+
+        * bindings/js/JSDOMBinding.cpp:
+        (WebCore::reportException):
+        Always include a non-empty call stack with exceptions.
+        Where not provided, fallback to the exception object.
+
+        * dom/Document.h:
+        * dom/Document.cpp:
+        (WebCore::Document::logExceptionToConsole):
+        * dom/ScriptExecutionContext.h:
+        * dom/ScriptExecutionContext.cpp:
+        (WebCore::ScriptExecutionContext::PendingException::PendingException):
+        (ScriptExecutionContext::PendingException):
+        (WebCore::ScriptExecutionContext::reportException):
+        * workers/DefaultSharedWorkerRepository.cpp:
+        * workers/SharedWorkerContext.cpp:
+        (WebCore::SharedWorkerContext::logExceptionToConsole):
+        * workers/SharedWorkerContext.h:
+        * workers/WorkerContext.cpp:
+        (WebCore::WorkerContext::logExceptionToConsole):
+        * workers/WorkerContext.h:
+        * workers/WorkerMessagingProxy.cpp:
+        (WebCore::WorkerExceptionTask::performTask):
+        Plumb columnNumber through as needed.
+
 2013-04-25  Gregg Tavares  <gman@chromium.org>
 
         Fix build files so WebGLDebugXXX extensions can be used if enabled.
index a20cdb17be43262b21d49a846751314812722f58..67267d0a14b8f748ce6c069f84dfba88e51fd3db 100644 (file)
@@ -33,6 +33,7 @@
 #include "JSDOMWindowCustom.h"
 #include "JSExceptionBase.h"
 #include "ScriptCallStack.h"
+#include "ScriptCallStackFactory.h"
 #include <interpreter/Interpreter.h>
 #include <runtime/DateInstance.h>
 #include <runtime/Error.h>
@@ -146,33 +147,47 @@ void reportException(ExecState* exec, JSValue exception, CachedScript* cachedScr
         return;
 
     Interpreter::ErrorHandlingMode mode(exec);
-    String errorMessage = exception.toString(exec)->value(exec);
-    int lineNumber = 0;
-    String exceptionSourceURL;
 
-    RefCountedArray<StackFrame> stackTrace = exec->vm().exceptionStack;
+    RefPtr<ScriptCallStack> callStack(createScriptCallStackFromException(exec, exception, ScriptCallStack::maxCallStackSizeToCapture));
     exec->clearException();
     exec->clearSupplementaryExceptionInfo();
 
-    if (exception.isObject()) {
+    JSDOMGlobalObject* globalObject = jsCast<JSDOMGlobalObject*>(exec->lexicalGlobalObject());
+    if (JSDOMWindow* window = jsDynamicCast<JSDOMWindow*>(globalObject)) {
+        if (!window->impl()->isCurrentlyDisplayedInFrame())
+            return;
+    }
+
+    int lineNumber = 0;
+    int columnNumber = 0;
+    String exceptionSourceURL;
+    if (callStack->size()) {
+        const ScriptCallFrame& frame = callStack->at(0);
+        lineNumber = frame.lineNumber();
+        columnNumber = frame.columnNumber();
+        exceptionSourceURL = frame.sourceURL();
+    } else {
+        // There may not be an exceptionStack for a <script> SyntaxError. Fallback to getting at least the line and sourceURL from the exception.
         JSObject* exceptionObject = exception.toObject(exec);
-        lineNumber = exceptionObject->get(exec, Identifier(exec, "line")).toInt32(exec);
-        exceptionSourceURL = exceptionObject->get(exec, Identifier(exec, "sourceURL")).toString(exec)->value(exec);
-    } else if (stackTrace.size()) {
-        lineNumber = stackTrace[0].line();
-        exceptionSourceURL = stackTrace[0].friendlySourceURL();
+        JSValue lineValue = exceptionObject->getDirect(exec->vm(), Identifier(exec, "line"));
+        lineNumber = lineValue && lineValue.isNumber() ? int(lineValue.toNumber(exec)) : 0;
+        JSValue sourceURLValue = exceptionObject->getDirect(exec->vm(), Identifier(exec, "sourceURL"));
+        exceptionSourceURL = sourceURLValue && sourceURLValue.isString() ? sourceURLValue.toString(exec)->value(exec) : ASCIILiteral("undefined");
     }
 
+    String errorMessage;
     if (ExceptionBase* exceptionBase = toExceptionBase(exception))
         errorMessage = exceptionBase->message() + ": "  + exceptionBase->description();
-
-    JSDOMGlobalObject* globalObject = jsCast<JSDOMGlobalObject*>(exec->lexicalGlobalObject());
-    if (JSDOMWindow* window = jsDynamicCast<JSDOMWindow*>(globalObject)) {
-        if (!window->impl()->isCurrentlyDisplayedInFrame())
-            return;
+    else {
+        // FIXME: <http://webkit.org/b/115087> Web Inspector: WebCore::reportException should not evaluate JavaScript handling exceptions
+        // If this is a custon exception object, call toString on it to try and get a nice string representation for the exception.
+        errorMessage = exception.toString(exec)->value(exec);
+        exec->clearException();
+        exec->clearSupplementaryExceptionInfo();
     }
+
     ScriptExecutionContext* scriptExecutionContext = globalObject->scriptExecutionContext();
-    scriptExecutionContext->reportException(errorMessage, lineNumber, exceptionSourceURL, 0, cachedScript);
+    scriptExecutionContext->reportException(errorMessage, lineNumber, columnNumber, exceptionSourceURL, callStack->size() ? callStack : 0, cachedScript);
 }
 
 void reportCurrentException(ExecState* exec)
index 12b131d347ca68086b7ff1228071ab12ed3dbffe..c62e5db65fa597aa609f246f991be5f502d28d2b 100644 (file)
@@ -90,6 +90,35 @@ PassRefPtr<ScriptCallStack> createScriptCallStack(JSC::ExecState* exec, size_t m
     return ScriptCallStack::create(frames);
 }
 
+PassRefPtr<ScriptCallStack> createScriptCallStackFromException(JSC::ExecState* exec, JSC::JSValue& exception, size_t maxStackSize)
+{
+    Vector<ScriptCallFrame> frames;
+    RefCountedArray<StackFrame> stackTrace = exec->vm().exceptionStack;
+    for (size_t i = 0; i < stackTrace.size() && i < maxStackSize; i++) {
+        if (!stackTrace[i].callee && frames.size())
+            break;
+
+        String functionName = stackTrace[i].friendlyFunctionName(exec);
+        frames.append(ScriptCallFrame(functionName, stackTrace[i].sourceURL, stackTrace[i].line(), stackTrace[i].column()));
+    }
+
+    // FIXME: <http://webkit.org/b/115087> Web Inspector: WebCore::reportException should not evaluate JavaScript handling exceptions
+    // Fallback to getting at least the line and sourceURL from the exception if it has values and the exceptionStack doesn't.
+    if (frames.size() > 0) {
+        const ScriptCallFrame& firstCallFrame = frames.first();
+        JSObject* exceptionObject = exception.toObject(exec);
+        if (exception.isObject() && firstCallFrame.sourceURL().isEmpty()) {
+            JSValue lineValue = exceptionObject->getDirect(exec->vm(), Identifier(exec, "line"));
+            int lineNumber = lineValue && lineValue.isNumber() ? int(lineValue.toNumber(exec)) : 0;
+            JSValue sourceURLValue = exceptionObject->getDirect(exec->vm(), Identifier(exec, "sourceURL"));
+            String exceptionSourceURL = sourceURLValue && sourceURLValue.isString() ? sourceURLValue.toString(exec)->value(exec) : ASCIILiteral("undefined");
+            frames[0] = ScriptCallFrame(firstCallFrame.functionName(), exceptionSourceURL, lineNumber, 0);
+        }
+    }
+
+    return ScriptCallStack::create(frames);
+}
+
 PassRefPtr<ScriptCallStack> createScriptCallStackForConsole(JSC::ExecState* exec)
 {
     size_t maxStackSize = 1;
index 6e94b03e1ea28c98f56fb1b62f1b5ed8c1dd915b..298bbbd4030f901936a7791d942c350736a55960 100644 (file)
 #define ScriptCallStackFactory_h
 
 #include <wtf/Forward.h>
+#include <wtf/RefCountedArray.h>
 
 namespace JSC {
 class ExecState;
+class JSValue;
+struct StackFrame;
 }
 
 namespace WebCore {
@@ -44,6 +47,7 @@ class ScriptCallStack;
 
 PassRefPtr<ScriptCallStack> createScriptCallStack(size_t maxStackSize, bool emptyStackIsAllowed);
 PassRefPtr<ScriptCallStack> createScriptCallStack(JSC::ExecState*, size_t maxStackSize);
+PassRefPtr<ScriptCallStack> createScriptCallStackFromException(JSC::ExecState*, JSC::JSValue& exception, size_t maxStackSize);
 PassRefPtr<ScriptCallStack> createScriptCallStackForConsole(JSC::ExecState*);
 PassRefPtr<ScriptArguments> createScriptArguments(JSC::ExecState*, unsigned skipArgumentCount);
 
index 9e9f63ad26d7835c85246393b728fa8f86c3cb54..ffcbf835489710f54c3e42f67564a390df214c61 100644 (file)
@@ -2655,9 +2655,9 @@ EventTarget* Document::errorEventTarget()
     return domWindow();
 }
 
-void Document::logExceptionToConsole(const String& errorMessage, const String& sourceURL, int lineNumber, PassRefPtr<ScriptCallStack> callStack)
+void Document::logExceptionToConsole(const String& errorMessage, const String& sourceURL, int lineNumber, int columnNumber, PassRefPtr<ScriptCallStack> callStack)
 {
-    addMessage(JSMessageSource, ErrorMessageLevel, errorMessage, sourceURL, lineNumber, 0, callStack);
+    addMessage(JSMessageSource, ErrorMessageLevel, errorMessage, sourceURL, lineNumber, columnNumber, callStack);
 }
 
 void Document::setURL(const KURL& url)
index ea14741d62109394a7819c3791b126c231f6f02f..cf084144cca1c4e65a03dd4ba9db03bd5dbfbaf3 100644 (file)
@@ -1105,7 +1105,7 @@ public:
 #endif
 
     virtual EventTarget* errorEventTarget();
-    virtual void logExceptionToConsole(const String& errorMessage, const String& sourceURL, int lineNumber, PassRefPtr<ScriptCallStack>);
+    virtual void logExceptionToConsole(const String& errorMessage, const String& sourceURL, int lineNumber, int columnNumber, PassRefPtr<ScriptCallStack>);
 
     void initDNSPrefetch();
 
index ca5224d5aa6141fbe637e1656e990d922f090a10..f1273cfabdd3a141f5327267967945e0d6c68cb8 100644 (file)
@@ -64,15 +64,17 @@ public:
 class ScriptExecutionContext::PendingException {
     WTF_MAKE_NONCOPYABLE(PendingException);
 public:
-    PendingException(const String& errorMessage, int lineNumber, const String& sourceURL, PassRefPtr<ScriptCallStack> callStack)
+    PendingException(const String& errorMessage, int lineNumber, int columnNumber, const String& sourceURL, PassRefPtr<ScriptCallStack> callStack)
         : m_errorMessage(errorMessage)
         , m_lineNumber(lineNumber)
+        , m_columnNumber(columnNumber)
         , m_sourceURL(sourceURL)
         , m_callStack(callStack)
     {
     }
     String m_errorMessage;
     int m_lineNumber;
+    int m_columnNumber;
     String m_sourceURL;
     RefPtr<ScriptCallStack> m_callStack;
 };
@@ -279,25 +281,25 @@ bool ScriptExecutionContext::sanitizeScriptError(String& errorMessage, int& line
     return true;
 }
 
-void ScriptExecutionContext::reportException(const String& errorMessage, int lineNumber, const String& sourceURL, PassRefPtr<ScriptCallStack> callStack, CachedScript* cachedScript)
+void ScriptExecutionContext::reportException(const String& errorMessage, int lineNumber, int columnNumber, const String& sourceURL, PassRefPtr<ScriptCallStack> callStack, CachedScript* cachedScript)
 {
     if (m_inDispatchErrorEvent) {
         if (!m_pendingExceptions)
             m_pendingExceptions = adoptPtr(new Vector<OwnPtr<PendingException> >());
-        m_pendingExceptions->append(adoptPtr(new PendingException(errorMessage, lineNumber, sourceURL, callStack)));
+        m_pendingExceptions->append(adoptPtr(new PendingException(errorMessage, lineNumber, columnNumber, sourceURL, callStack)));
         return;
     }
 
     // First report the original exception and only then all the nested ones.
     if (!dispatchErrorEvent(errorMessage, lineNumber, sourceURL, cachedScript))
-        logExceptionToConsole(errorMessage, sourceURL, lineNumber, callStack);
+        logExceptionToConsole(errorMessage, sourceURL, lineNumber, columnNumber, callStack);
 
     if (!m_pendingExceptions)
         return;
 
     for (size_t i = 0; i < m_pendingExceptions->size(); i++) {
         PendingException* e = m_pendingExceptions->at(i).get();
-        logExceptionToConsole(e->m_errorMessage, e->m_sourceURL, e->m_lineNumber, e->m_callStack);
+        logExceptionToConsole(e->m_errorMessage, e->m_sourceURL, e->m_lineNumber, e->m_columnNumber, e->m_callStack);
     }
     m_pendingExceptions.clear();
 }
index 245228b17f762c74fdbb82089a523af8a7a56a72..97061244c587d301f3f9aff1d6b044edafa81e72 100644 (file)
@@ -77,7 +77,7 @@ public:
 
     bool sanitizeScriptError(String& errorMessage, int& lineNumber, String& sourceURL, CachedScript* = 0);
     // FIXME: <http://webkit.org/b/114315> ScriptExecutionContext log exception should include a column number
-    void reportException(const String& errorMessage, int lineNumber, const String& sourceURL, PassRefPtr<ScriptCallStack>, CachedScript* = 0);
+    void reportException(const String& errorMessage, int lineNumber, int columnNumber, const String& sourceURL, PassRefPtr<ScriptCallStack>, CachedScript* = 0);
 
     void addConsoleMessage(MessageSource, MessageLevel, const String& message, const String& sourceURL, unsigned lineNumber, unsigned columnNumber, ScriptState* = 0, unsigned long requestIdentifier = 0);
     virtual void addConsoleMessage(MessageSource, MessageLevel, const String& message, unsigned long requestIdentifier = 0) = 0;
@@ -185,8 +185,7 @@ private:
 
     virtual void addMessage(MessageSource, MessageLevel, const String& message, const String& sourceURL, unsigned lineNumber, unsigned columnNumber, PassRefPtr<ScriptCallStack>, ScriptState* = 0, unsigned long requestIdentifier = 0) = 0;
     virtual EventTarget* errorEventTarget() = 0;
-    // FIXME: <http://webkit.org/b/114315> ScriptExecutionContext log exception should include a column number
-    virtual void logExceptionToConsole(const String& errorMessage, const String& sourceURL, int lineNumber, PassRefPtr<ScriptCallStack>) = 0;
+    virtual void logExceptionToConsole(const String& errorMessage, const String& sourceURL, int lineNumber, int columnNumber, PassRefPtr<ScriptCallStack>) = 0;
     bool dispatchErrorEvent(const String& errorMessage, int lineNumber, const String& sourceURL, CachedScript*);
 
     void closeMessagePorts();
index 01d193ae1e2a643d042451a3161142630d28bca1..4786b0bacd81764ae942009cb5d5d3c4bcbd1959 100644 (file)
@@ -176,10 +176,9 @@ GroupSettings* SharedWorkerProxy::groupSettings() const
     return 0;
 }
 
-static void postExceptionTask(ScriptExecutionContext* context, const String& errorMessage, int lineNumber, int /*columnNumber*/, const String& sourceURL)
+static void postExceptionTask(ScriptExecutionContext* context, const String& errorMessage, int lineNumber, int columnNumber, const String& sourceURL)
 {
-    // FIXME: <http://webkit.org/b/114315> ScriptExecutionContext log exception should include a column number
-    context->reportException(errorMessage, lineNumber, sourceURL, 0);
+    context->reportException(errorMessage, lineNumber, columnNumber, sourceURL, 0);
 }
 
 void SharedWorkerProxy::postExceptionToWorkerObject(const String& errorMessage, int lineNumber, int columnNumber, const String& sourceURL)
index 82ac7e4cce8281a5feb54d32f853191cfa226016..6ed0029ff9b52871ce78b44f031bd2cca0ddf3c2 100644 (file)
@@ -78,11 +78,10 @@ SharedWorkerThread* SharedWorkerContext::thread()
     return static_cast<SharedWorkerThread*>(Base::thread());
 }
 
-void SharedWorkerContext::logExceptionToConsole(const String& errorMessage, const String& sourceURL, int lineNumber, PassRefPtr<ScriptCallStack> callStack)
+void SharedWorkerContext::logExceptionToConsole(const String& errorMessage, const String& sourceURL, int lineNumber, int columnNumber, PassRefPtr<ScriptCallStack> callStack)
 {
-    // FIXME: <http://webkit.org/b/114315> ScriptExecutionContext log exception should include a column number
-    WorkerContext::logExceptionToConsole(errorMessage, sourceURL, lineNumber, callStack);
-    addMessageToWorkerConsole(JSMessageSource, ErrorMessageLevel, errorMessage, sourceURL, lineNumber, 0, callStack);
+    WorkerContext::logExceptionToConsole(errorMessage, sourceURL, lineNumber, columnNumber, callStack);
+    addMessageToWorkerConsole(JSMessageSource, ErrorMessageLevel, errorMessage, sourceURL, lineNumber, columnNumber, callStack);
 }
 
 } // namespace WebCore
index c7442d2a23766ce36fa9f62620fc0edcbaad0a63..e8b18fbaf0b5b3c0a32493a9a2b8e0ea4f0b2e64 100644 (file)
@@ -60,7 +60,7 @@ namespace WebCore {
 
     private:
         SharedWorkerContext(const String& name, const KURL&, const String& userAgent, PassOwnPtr<GroupSettings>, SharedWorkerThread*);
-        virtual void logExceptionToConsole(const String& errorMessage, const String& sourceURL, int lineNumber, PassRefPtr<ScriptCallStack>) OVERRIDE;
+        virtual void logExceptionToConsole(const String& errorMessage, const String& sourceURL, int lineNumber, int columnNumber, PassRefPtr<ScriptCallStack>) OVERRIDE;
 
         String m_name;
     };
index f0f26f802887cddbe2fed075b6da1fa9454ba84c..2cbdfa2bec6d95c8b66229fb29828d2393cee2d0 100644 (file)
@@ -273,10 +273,9 @@ EventTarget* WorkerContext::errorEventTarget()
     return this;
 }
 
-void WorkerContext::logExceptionToConsole(const String& errorMessage, const String& sourceURL, int lineNumber, PassRefPtr<ScriptCallStack>)
+void WorkerContext::logExceptionToConsole(const String& errorMessage, const String& sourceURL, int lineNumber, int columnNumber, PassRefPtr<ScriptCallStack>)
 {
-    // FIXME: <http://webkit.org/b/114315> ScriptExecutionContext log exception should include a column number
-    thread()->workerReportingProxy().postExceptionToWorkerObject(errorMessage, lineNumber, 0, sourceURL);
+    thread()->workerReportingProxy().postExceptionToWorkerObject(errorMessage, lineNumber, columnNumber, sourceURL);
 }
 
 void WorkerContext::addConsoleMessage(MessageSource source, MessageLevel level, const String& message, unsigned long requestIdentifier)
index 3e93215e1a4439846d109a36dad51f05a6736718..b7b10809f91478c36e52fa586c6a65a98097902b 100644 (file)
@@ -144,7 +144,7 @@ namespace WebCore {
         WorkerContext(const KURL&, const String& userAgent, PassOwnPtr<GroupSettings>, WorkerThread*, PassRefPtr<SecurityOrigin> topOrigin);
         void applyContentSecurityPolicyFromString(const String& contentSecurityPolicy, ContentSecurityPolicy::HeaderType);
 
-        virtual void logExceptionToConsole(const String& errorMessage, const String& sourceURL, int lineNumber, PassRefPtr<ScriptCallStack>) OVERRIDE;
+        virtual void logExceptionToConsole(const String& errorMessage, const String& sourceURL, int lineNumber, int columnNumber, PassRefPtr<ScriptCallStack>) OVERRIDE;
         void addMessageToWorkerConsole(MessageSource, MessageLevel, const String& message, const String& sourceURL, unsigned lineNumber, unsigned columnNumber, PassRefPtr<ScriptCallStack>, ScriptState* = 0, unsigned long requestIdentifier = 0);
 
     private:
index b075570e5d5b9a19045bb162992d6d68eda0ae58..926c7cb9f7270b61407a3da95375b6f7b550c097 100644 (file)
@@ -138,10 +138,8 @@ private:
         // This is intentionally different than the behavior in MessageWorkerTask, because terminated workers no longer deliver messages (section 4.6 of the WebWorker spec), but they do report exceptions.
 
         bool errorHandled = !workerObject->dispatchEvent(ErrorEvent::create(m_errorMessage, m_sourceURL, m_lineNumber));
-        if (!errorHandled) {
-            // FIXME: <http://webkit.org/b/114315> ScriptExecutionContext log exception should include a column number
-            context->reportException(m_errorMessage, m_lineNumber, m_sourceURL, 0);
-        }
+        if (!errorHandled)
+            context->reportException(m_errorMessage, m_lineNumber, m_columnNumber, m_sourceURL, 0);
     }
 
     String m_errorMessage;