JSMainThreadExecState::call() should clear exceptions before returning.
authormark.lam@apple.com <mark.lam@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 11 Apr 2014 20:24:56 +0000 (20:24 +0000)
committermark.lam@apple.com <mark.lam@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 11 Apr 2014 20:24:56 +0000 (20:24 +0000)
<https://webkit.org/b/131530>

Reviewed by Geoffrey Garen.

Source/JavaScriptCore:

Added a version of JSC::call() that return any uncaught exception instead
of leaving it pending in the VM.

As part of this change, I updated various parts of the code base to use the
new API as needed.

* bindings/ScriptFunctionCall.cpp:
(Deprecated::ScriptFunctionCall::call):
- ScriptFunctionCall::call() is only used by the inspector to inject scripts.
  The injected scripts that will include Inspector scripts that should catch
  and handle any exceptions that were thrown.  We should not be seeing any
  exceptions returned from this call.  However, we do have checks for
  exceptions in case there are bugs in the Inspector scripts which allowed
  the exception to leak through.  Hence, it is proper to clear the exception
  here, and only record the fact that an exception was seen (if present).

* bindings/ScriptFunctionCall.h:
* inspector/InspectorEnvironment.h:
* runtime/CallData.cpp:
(JSC::call):
* runtime/CallData.h:

Source/WebCore:

Test: fast/dom/regress-131530.html

Previously, JSMainThreadExecState::call() did not clear any pending
exceptions in the VM before returning.  On returning, the
JSMainThreadExecState destructor may re-enter the VM to notify
MutationObservers.  This may result in a crash because the VM expects
exceptions to be cleared at entry.

We now change JSMainThreadExecState::call() to return the exception
(if present) via an argument, and clear it from the VM before returning.

As part of this change, I updated various parts of the code base to use the
new API as needed.

* bindings/js/JSCallbackData.cpp:
(WebCore::JSCallbackData::invokeCallback):
* bindings/js/JSCustomXPathNSResolver.cpp:
(WebCore::JSCustomXPathNSResolver::lookupNamespaceURI):
* bindings/js/JSDOMGlobalObjectTask.cpp:
- Assert that there's no unhandled exception after the Microtask returns.
  See comment for WebCore::JSMainThreadExecState::runTask below for more
  details.

* bindings/js/JSErrorHandler.cpp:
(WebCore::JSErrorHandler::handleEvent):
* bindings/js/JSEventListener.cpp:
(WebCore::JSEventListener::handleEvent):
* bindings/js/JSHTMLDocumentCustom.cpp:
(WebCore::JSHTMLDocument::open):
- Document.open() cannot be the first function on the JS stack.  Hence,
  there is no need to use JSMainThreadExecState to call into the VM, as
  this is only needed to catch the event of returning from the first
  function for the purpose of notifying MutationObservers.  Change to
  call JSC::call() directly.

* bindings/js/JSMainThreadExecState.cpp:
(WebCore::functionCallHandlerFromAnyThread):
* bindings/js/JSMainThreadExecState.h:
(WebCore::JSMainThreadExecState::call):
(WebCore::JSMainThreadExecState::evaluate):
- Remove the explicitly acquisition of the JSLock here because we now
  acquire the JSLock as part of the JSMainThreadExecState instance.
(WebCore::JSMainThreadExecState::runTask):
- Added an assert to verify that the task does not return with an
  unhandled exception.  Currently, the only Microtask in use is for the
  Promise implementation, which will eat the exception before returning.
  This assertion is added here to verify that this contract does not
  inadvertantly change in the future.
(WebCore::JSMainThreadExecState::JSMainThreadExecState):
- Now acquires the JSLock as well since by definition, we're only
  instantiating the JSMainThreadExecState because we're about to enter
  the VM.

* bindings/js/JSMutationCallback.cpp:
(WebCore::JSMutationCallback::call):
* bindings/js/JSNodeFilterCondition.cpp:
(WebCore::JSNodeFilterCondition::acceptNode):
- acceptNode() is only used in the TreeWalker and NodeIterator APIs which
  cannot be the first function on the JS stack.  Hence, we should call
  JSC::call() directly instead of going through JSMainThreadExecState.

* bindings/js/ScheduledAction.cpp:
(WebCore::ScheduledAction::executeFunctionInContext):
* bindings/objc/WebScriptObject.mm:
(WebCore::addExceptionToConsole):
(-[WebScriptObject callWebScriptMethod:withArguments:]):

LayoutTests:

* fast/dom/regress-131530-expected.txt: Added.
* fast/dom/regress-131530.html: Added.

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

22 files changed:
LayoutTests/ChangeLog
LayoutTests/fast/dom/regress-131530-expected.txt [new file with mode: 0644]
LayoutTests/fast/dom/regress-131530.html [new file with mode: 0644]
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/bindings/ScriptFunctionCall.cpp
Source/JavaScriptCore/bindings/ScriptFunctionCall.h
Source/JavaScriptCore/inspector/InspectorEnvironment.h
Source/JavaScriptCore/runtime/CallData.cpp
Source/JavaScriptCore/runtime/CallData.h
Source/WebCore/ChangeLog
Source/WebCore/bindings/js/JSCallbackData.cpp
Source/WebCore/bindings/js/JSCustomXPathNSResolver.cpp
Source/WebCore/bindings/js/JSDOMGlobalObjectTask.cpp
Source/WebCore/bindings/js/JSErrorHandler.cpp
Source/WebCore/bindings/js/JSEventListener.cpp
Source/WebCore/bindings/js/JSHTMLDocumentCustom.cpp
Source/WebCore/bindings/js/JSMainThreadExecState.cpp
Source/WebCore/bindings/js/JSMainThreadExecState.h
Source/WebCore/bindings/js/JSMutationCallback.cpp
Source/WebCore/bindings/js/JSNodeFilterCondition.cpp
Source/WebCore/bindings/js/ScheduledAction.cpp
Source/WebCore/bindings/objc/WebScriptObject.mm

index d9568417fa27d2a3316e4b1ab953bca836f9af9d..8038eddc5859f3c4ccf41623eb18225aecf5b3d6 100644 (file)
@@ -1,3 +1,13 @@
+2014-04-11  Mark Lam  <mark.lam@apple.com>
+
+        JSMainThreadExecState::call() should clear exceptions before returning.
+        <https://webkit.org/b/131530>
+
+        Reviewed by Geoffrey Garen.
+
+        * fast/dom/regress-131530-expected.txt: Added.
+        * fast/dom/regress-131530.html: Added.
+
 2014-04-11  Carlos Alberto Lopez Perez  <clopez@igalia.com>
 
         [GTK] Unreviewed GTK gardening.
diff --git a/LayoutTests/fast/dom/regress-131530-expected.txt b/LayoutTests/fast/dom/regress-131530-expected.txt
new file mode 100644 (file)
index 0000000..81e8556
--- /dev/null
@@ -0,0 +1,5 @@
+CONSOLE MESSAGE: line 5: Exception to trigger unwinding in MutationObserver
+CONSOLE MESSAGE: Pending exception before MutationObservers are called.
+Regression test for https://webkit.org/b/131530. This test should not crash.
+
+Mutate that node
diff --git a/LayoutTests/fast/dom/regress-131530.html b/LayoutTests/fast/dom/regress-131530.html
new file mode 100644 (file)
index 0000000..6aecbb9
--- /dev/null
@@ -0,0 +1,29 @@
+<head>
+<script>
+var observer = new MutationObserver(function(mutations) {
+    function foo() {
+        throw "Exception to trigger unwinding in MutationObserver";
+    }
+    mutations.forEach(function(mutation) {
+        foo();
+    });
+});
+
+function test()
+{
+    if (window.testRunner)
+        testRunner.dumpAsText();
+
+    var node = document.getElementById('res');
+    var config = { attribute: true, childList: true, characterData: true };
+    observer.observe(node, config);
+
+    node.innerText += "Mutate that node";
+    throw "Pending exception before MutationObservers are called.";
+}
+</script>
+</head>
+<body onload="test();">
+<p>Regression test for https://webkit.org/b/131530. This test should not crash.<form>
+<div id="res"></div>
+</body>
index a8220348168abead7b5bd5e3a12e35f3d6459cf4..847dc184abfd97f8116fb2eb6526038b34f324ba 100644 (file)
@@ -1,3 +1,32 @@
+2014-04-11  Mark Lam  <mark.lam@apple.com>
+
+        JSMainThreadExecState::call() should clear exceptions before returning.
+        <https://webkit.org/b/131530>
+
+        Reviewed by Geoffrey Garen.
+
+        Added a version of JSC::call() that return any uncaught exception instead
+        of leaving it pending in the VM.
+
+        As part of this change, I updated various parts of the code base to use the
+        new API as needed.
+
+        * bindings/ScriptFunctionCall.cpp:
+        (Deprecated::ScriptFunctionCall::call):
+        - ScriptFunctionCall::call() is only used by the inspector to inject scripts.
+          The injected scripts that will include Inspector scripts that should catch
+          and handle any exceptions that were thrown.  We should not be seeing any
+          exceptions returned from this call.  However, we do have checks for
+          exceptions in case there are bugs in the Inspector scripts which allowed
+          the exception to leak through.  Hence, it is proper to clear the exception
+          here, and only record the fact that an exception was seen (if present).
+
+        * bindings/ScriptFunctionCall.h:
+        * inspector/InspectorEnvironment.h:
+        * runtime/CallData.cpp:
+        (JSC::call):
+        * runtime/CallData.h:
+
 2014-04-11  Oliver Hunt  <oliver@apple.com>
 
         Add BuiltinLog function to make debugging builtins easier
index 5b58814f563416835fbdf6243af3e7f2475b1765..2df7876410e78cf9fabf241786e60242fe4eee09 100644 (file)
@@ -133,12 +133,13 @@ Deprecated::ScriptValue ScriptFunctionCall::call(bool& hadException)
         return Deprecated::ScriptValue();
 
     JSValue result;
+    JSValue exception;
     if (m_callHandler)
-        result = m_callHandler(m_exec, function, callType, callData, thisObject, m_arguments);
+        result = m_callHandler(m_exec, function, callType, callData, thisObject, m_arguments, &exception);
     else
-        result = JSC::call(m_exec, function, callType, callData, thisObject, m_arguments);
+        result = JSC::call(m_exec, function, callType, callData, thisObject, m_arguments, &exception);
 
-    if (m_exec->hadException()) {
+    if (exception) {
         hadException = true;
         return Deprecated::ScriptValue();
     }
index 04b2afe0702424a3df4ec466976e387ebfe3e6ed..7c3e78c255cf3a1c32f645a141250050ac80071b 100644 (file)
@@ -71,7 +71,7 @@ private:
 
 class JS_EXPORT_PRIVATE ScriptFunctionCall : public ScriptCallArgumentHandler {
 public:
-    typedef JSC::JSValue (*ScriptFunctionCallHandler)(JSC::ExecState* exec, JSC::JSValue functionObject, JSC::CallType callType, const JSC::CallData& callData, JSC::JSValue thisValue, const JSC::ArgList& args);
+    typedef JSC::JSValue (*ScriptFunctionCallHandler)(JSC::ExecState* exec, JSC::JSValue functionObject, JSC::CallType callType, const JSC::CallData& callData, JSC::JSValue thisValue, const JSC::ArgList& args, JSC::JSValue* exception);
     ScriptFunctionCall(const ScriptObject& thisObject, const String& name, ScriptFunctionCallHandler handler = nullptr);
     ScriptValue call(bool& hadException);
     ScriptValue call();
index 26092d1b539f9471c99aa71fdfe0294b1f25ca81..588d7a125c1bfb08e738247faadd04bdee84d0a5 100644 (file)
@@ -34,7 +34,7 @@ class SourceCode;
 
 namespace Inspector {
 
-typedef JSC::JSValue (*InspectorFunctionCallHandler)(JSC::ExecState* exec, JSC::JSValue functionObject, JSC::CallType callType, const JSC::CallData& callData, JSC::JSValue thisValue, const JSC::ArgList& args);
+typedef JSC::JSValue (*InspectorFunctionCallHandler)(JSC::ExecState* exec, JSC::JSValue functionObject, JSC::CallType callType, const JSC::CallData& callData, JSC::JSValue thisValue, const JSC::ArgList& args, JSC::JSValue* exception);
 typedef JSC::JSValue (*InspectorEvaluateHandler)(JSC::ExecState*, const JSC::SourceCode&, JSC::JSValue thisValue, JSC::JSValue* exception);
 
 class InspectorEnvironment {
index c52b5672b704290d4856dfe605a08480623d897c..6d00109c3ddba5f13facd496f1027a0c2e37da8c 100644 (file)
@@ -39,4 +39,17 @@ JSValue call(ExecState* exec, JSValue functionObject, CallType callType, const C
     return exec->interpreter()->executeCall(exec, asObject(functionObject), callType, callData, thisValue, args);
 }
 
+JSValue call(ExecState* exec, JSValue functionObject, CallType callType, const CallData& callData, JSValue thisValue, const ArgList& args, JSValue* exception)
+{
+    JSValue result = call(exec, functionObject, callType, callData, thisValue, args);
+    if (exec->hadException()) {
+        if (exception)
+            *exception = exec->exception();
+        exec->clearException();
+        return jsUndefined();
+    }
+    RELEASE_ASSERT(result);
+    return result;
+}
+
 } // namespace JSC
index f9d41e81762de6bbecde86dbc0ce05efa100365d..b6edd3731083ce49b8a2af6a0bb47df6abfc25e6 100644 (file)
@@ -58,6 +58,7 @@ union CallData {
 };
 
 JS_EXPORT_PRIVATE JSValue call(ExecState*, JSValue functionObject, CallType, const CallData&, JSValue thisValue, const ArgList&);
+JS_EXPORT_PRIVATE JSValue call(ExecState*, JSValue functionObject, CallType, const CallData&, JSValue thisValue, const ArgList&, JSValue* exception);
 
 } // namespace JSC
 
index fdc9d4dca4b653424a2e1e7f5c08c4749a509eef..f40130a04e3bbeb7243250c946074d1e0b44734d 100644 (file)
@@ -1,3 +1,77 @@
+2014-04-11  Mark Lam  <mark.lam@apple.com>
+
+        JSMainThreadExecState::call() should clear exceptions before returning.
+        <https://webkit.org/b/131530>
+
+        Reviewed by Geoffrey Garen.
+
+        Test: fast/dom/regress-131530.html
+
+        Previously, JSMainThreadExecState::call() did not clear any pending
+        exceptions in the VM before returning.  On returning, the
+        JSMainThreadExecState destructor may re-enter the VM to notify
+        MutationObservers.  This may result in a crash because the VM expects
+        exceptions to be cleared at entry.
+
+        We now change JSMainThreadExecState::call() to return the exception
+        (if present) via an argument, and clear it from the VM before returning.
+
+        As part of this change, I updated various parts of the code base to use the
+        new API as needed.
+
+        * bindings/js/JSCallbackData.cpp:
+        (WebCore::JSCallbackData::invokeCallback):
+        * bindings/js/JSCustomXPathNSResolver.cpp:
+        (WebCore::JSCustomXPathNSResolver::lookupNamespaceURI):
+        * bindings/js/JSDOMGlobalObjectTask.cpp:
+        - Assert that there's no unhandled exception after the Microtask returns.
+          See comment for WebCore::JSMainThreadExecState::runTask below for more
+          details.
+
+        * bindings/js/JSErrorHandler.cpp:
+        (WebCore::JSErrorHandler::handleEvent):
+        * bindings/js/JSEventListener.cpp:
+        (WebCore::JSEventListener::handleEvent):
+        * bindings/js/JSHTMLDocumentCustom.cpp:
+        (WebCore::JSHTMLDocument::open):
+        - Document.open() cannot be the first function on the JS stack.  Hence,
+          there is no need to use JSMainThreadExecState to call into the VM, as
+          this is only needed to catch the event of returning from the first
+          function for the purpose of notifying MutationObservers.  Change to
+          call JSC::call() directly.
+
+        * bindings/js/JSMainThreadExecState.cpp:
+        (WebCore::functionCallHandlerFromAnyThread):
+        * bindings/js/JSMainThreadExecState.h:
+        (WebCore::JSMainThreadExecState::call):
+        (WebCore::JSMainThreadExecState::evaluate):
+        - Remove the explicitly acquisition of the JSLock here because we now
+          acquire the JSLock as part of the JSMainThreadExecState instance.
+        (WebCore::JSMainThreadExecState::runTask):
+        - Added an assert to verify that the task does not return with an
+          unhandled exception.  Currently, the only Microtask in use is for the
+          Promise implementation, which will eat the exception before returning.
+          This assertion is added here to verify that this contract does not
+          inadvertantly change in the future.
+        (WebCore::JSMainThreadExecState::JSMainThreadExecState):
+        - Now acquires the JSLock as well since by definition, we're only
+          instantiating the JSMainThreadExecState because we're about to enter
+          the VM.
+
+        * bindings/js/JSMutationCallback.cpp:
+        (WebCore::JSMutationCallback::call):
+        * bindings/js/JSNodeFilterCondition.cpp:
+        (WebCore::JSNodeFilterCondition::acceptNode):
+        - acceptNode() is only used in the TreeWalker and NodeIterator APIs which
+          cannot be the first function on the JS stack.  Hence, we should call
+          JSC::call() directly instead of going through JSMainThreadExecState.
+
+        * bindings/js/ScheduledAction.cpp:
+        (WebCore::ScheduledAction::executeFunctionInContext):
+        * bindings/objc/WebScriptObject.mm:
+        (WebCore::addExceptionToConsole):
+        (-[WebScriptObject callWebScriptMethod:withArguments:]):
+
 2014-04-11  Brian J. Burg  <burg@cs.washington.edu>
 
         Web Replay: CodeGeneratorJS should guard includes of replay-related headers
index 3be5e20766ef41551a1fa881da09e3a4737b153c..e1d725f8c6d111341215e10bdd7ab6727e74ead4 100644 (file)
@@ -73,14 +73,15 @@ JSValue JSCallbackData::invokeCallback(JSValue thisValue, MarkedArgumentBuffer&
 
     InspectorInstrumentationCookie cookie = JSMainThreadExecState::instrumentFunctionCall(context, callType, callData);
 
+    JSValue exception;
     JSValue result = context->isDocument()
-        ? JSMainThreadExecState::call(exec, function, callType, callData, thisValue, args)
-        : JSC::call(exec, function, callType, callData, thisValue, args);
+        ? JSMainThreadExecState::call(exec, function, callType, callData, thisValue, args, &exception)
+        : JSC::call(exec, function, callType, callData, thisValue, args, &exception);
 
     InspectorInstrumentation::didCallFunction(cookie, context);
 
-    if (exec->hadException()) {
-        reportCurrentException(exec);
+    if (exception) {
+        reportException(exec, exception);
         if (raisedException)
             *raisedException = true;
         return result;
index 0f52afab83b83baaeaa48b76436cc3e315f9ee39..fb2e641474d4003a52a95257901ca31314da38a8 100644 (file)
@@ -92,11 +92,12 @@ String JSCustomXPathNSResolver::lookupNamespaceURI(const String& prefix)
     MarkedArgumentBuffer args;
     args.append(jsStringWithCache(exec, prefix));
 
-    JSValue retval = JSMainThreadExecState::call(exec, function, callType, callData, m_customResolver.get(), args);
+    JSValue exception;
+    JSValue retval = JSMainThreadExecState::call(exec, function, callType, callData, m_customResolver.get(), args, &exception);
 
     String result;
-    if (exec->hadException())
-        reportCurrentException(exec);
+    if (exception)
+        reportException(exec, exception);
     else {
         if (!retval.isUndefinedOrNull())
             result = retval.toString(exec)->value(exec);
index 57291cc779fac24cbf8d97a1b7e50c7f1ca5e83b..9cca89beb459a1bb73c085b4e450f14f7f804e07 100644 (file)
@@ -64,6 +64,7 @@ public:
             JSMainThreadExecState::runTask(exec, *m_task.get());
         else
             m_task->run(exec);
+        ASSERT(!exec->hadException());
     }
 
 private:
index d92c1b8f3ae226a686e6a0c0b323f4f9785bbab0..ea51f79f2d48002ea61c99f5f9c172ee79e540b0 100644 (file)
@@ -98,14 +98,15 @@ void JSErrorHandler::handleEvent(ScriptExecutionContext* scriptExecutionContext,
         VM& vm = globalObject->vm();
         VMEntryScope entryScope(vm, vm.entryScope ? vm.entryScope->globalObject() : globalObject);
 
+        JSValue exception;
         JSValue returnValue = scriptExecutionContext->isDocument()
-            ? JSMainThreadExecState::call(exec, jsFunction, callType, callData, globalObject, args)
-            : JSC::call(exec, jsFunction, callType, callData, globalObject, args);
+            ? JSMainThreadExecState::call(exec, jsFunction, callType, callData, globalObject, args, &exception)
+            : JSC::call(exec, jsFunction, callType, callData, globalObject, args, &exception);
 
         globalObject->setCurrentEvent(savedEvent);
 
-        if (exec->hadException())
-            reportCurrentException(exec);
+        if (exception)
+            reportException(exec, exception);
         else {
             if (returnValue.isTrue())
                 event->preventDefault();
index 960b67e407c4a893f81db0c75d29feca9314c58a..6f35366c0022ed367f990bb9357c8337c14cc11d 100644 (file)
@@ -122,9 +122,10 @@ void JSEventListener::handleEvent(ScriptExecutionContext* scriptExecutionContext
         InspectorInstrumentationCookie cookie = JSMainThreadExecState::instrumentFunctionCall(scriptExecutionContext, callType, callData);
 
         JSValue thisValue = handleEventFunction == jsFunction ? toJS(exec, globalObject, event->currentTarget()) : jsFunction;
+        JSValue exception;
         JSValue retval = scriptExecutionContext->isDocument()
-            ? JSMainThreadExecState::call(exec, handleEventFunction, callType, callData, thisValue, args)
-            : JSC::call(exec, handleEventFunction, callType, callData, thisValue, args);
+            ? JSMainThreadExecState::call(exec, handleEventFunction, callType, callData, thisValue, args, &exception)
+            : JSC::call(exec, handleEventFunction, callType, callData, thisValue, args, &exception);
 
         InspectorInstrumentation::didCallFunction(cookie, scriptExecutionContext);
 
@@ -136,9 +137,9 @@ void JSEventListener::handleEvent(ScriptExecutionContext* scriptExecutionContext
                 toWorkerGlobalScope(scriptExecutionContext)->script()->forbidExecution();
         }
 
-        if (exec->hadException()) {
+        if (exception) {
             event->target()->uncaughtExceptionInEventHandler();
-            reportCurrentException(exec);
+            reportException(exec, exception);
         } else {
             if (!retval.isUndefinedOrNull() && event->isBeforeUnloadEvent())
                 toBeforeUnloadEvent(event)->setReturnValue(retval.toString(exec)->value(exec));
index 174e5f7f1d62741afa6b36ff7c3853845d97a3d1..b6ebc4cbb6ef97126a0c6d1344de6defcbb4fe55 100644 (file)
@@ -113,7 +113,7 @@ JSValue JSHTMLDocument::open(ExecState* exec)
                 CallType callType = ::getCallData(function, callData);
                 if (callType == CallTypeNone)
                     return throwTypeError(exec);
-                return JSMainThreadExecState::call(exec, function, callType, callData, wrapper, ArgList(exec));
+                return JSC::call(exec, function, callType, callData, wrapper, ArgList(exec));
             }
         }
         return jsUndefined();
index 779b96ab05bdcb8e7dc3443560805c6a5c327f79..06e92f2e3cdfccb4b84a7cc8fb7486beff27853f 100644 (file)
@@ -46,11 +46,11 @@ void JSMainThreadExecState::didLeaveScriptContext()
     MutationObserver::deliverAllMutations();
 }
 
-JSC::JSValue functionCallHandlerFromAnyThread(JSC::ExecState* exec, JSC::JSValue functionObject, JSC::CallType callType, const JSC::CallData& callData, JSC::JSValue thisValue, const JSC::ArgList& args)
+JSC::JSValue functionCallHandlerFromAnyThread(JSC::ExecState* exec, JSC::JSValue functionObject, JSC::CallType callType, const JSC::CallData& callData, JSC::JSValue thisValue, const JSC::ArgList& args, JSC::JSValue* exception)
 {
     if (isMainThread())
-        return JSMainThreadExecState::call(exec, functionObject, callType, callData, thisValue, args);
-    return JSC::call(exec, functionObject, callType, callData, thisValue, args);
+        return JSMainThreadExecState::call(exec, functionObject, callType, callData, thisValue, args, exception);
+    return JSC::call(exec, functionObject, callType, callData, thisValue, args, exception);
 }
 
 JSC::JSValue evaluateHandlerFromAnyThread(JSC::ExecState* exec, const JSC::SourceCode& source, JSC::JSValue thisValue, JSC::JSValue* exception)
index 29dd9713476f432145b6c7863c2a8250534c6a28..c157b0fd94888dbefa05008a56a5bad32efe16c7 100644 (file)
@@ -50,16 +50,15 @@ public:
         return s_mainThreadState;
     };
     
-    static JSC::JSValue call(JSC::ExecState* exec, JSC::JSValue functionObject, JSC::CallType callType, const JSC::CallData& callData, JSC::JSValue thisValue, const JSC::ArgList& args)
+    static JSC::JSValue call(JSC::ExecState* exec, JSC::JSValue functionObject, JSC::CallType callType, const JSC::CallData& callData, JSC::JSValue thisValue, const JSC::ArgList& args, JSC::JSValue* exception)
     {
         JSMainThreadExecState currentState(exec);
-        return JSC::call(exec, functionObject, callType, callData, thisValue, args);
+        return JSC::call(exec, functionObject, callType, callData, thisValue, args, exception);
     };
 
     static JSC::JSValue evaluate(JSC::ExecState* exec, const JSC::SourceCode& source, JSC::JSValue thisValue, JSC::JSValue* exception)
     {
         JSMainThreadExecState currentState(exec);
-        JSC::JSLockHolder lock(exec);
         return JSC::evaluate(exec, source, thisValue, exception);
     };
 
@@ -74,6 +73,7 @@ public:
 private:
     explicit JSMainThreadExecState(JSC::ExecState* exec)
         : m_previousState(s_mainThreadState)
+        , m_lock(exec)
     {
         ASSERT(isMainThread());
         s_mainThreadState = exec;
@@ -82,6 +82,7 @@ private:
     ~JSMainThreadExecState()
     {
         ASSERT(isMainThread());
+        ASSERT(!s_mainThreadState->hadException());
 
         bool didExitJavaScript = s_mainThreadState && !m_previousState;
 
@@ -93,6 +94,7 @@ private:
 
     static JSC::ExecState* s_mainThreadState;
     JSC::ExecState* m_previousState;
+    JSC::JSLockHolder m_lock;
 
     static void didLeaveScriptContext();
 };
@@ -119,7 +121,7 @@ private:
     JSC::ExecState* m_previousState;
 };
 
-JSC::JSValue functionCallHandlerFromAnyThread(JSC::ExecState*, JSC::JSValue functionObject, JSC::CallType callType, const JSC::CallData& callData, JSC::JSValue thisValue, const JSC::ArgList& args);
+JSC::JSValue functionCallHandlerFromAnyThread(JSC::ExecState*, JSC::JSValue functionObject, JSC::CallType, const JSC::CallData&, JSC::JSValue thisValue, const JSC::ArgList& args, JSC::JSValue* exception);
 JSC::JSValue evaluateHandlerFromAnyThread(JSC::ExecState*, const JSC::SourceCode&, JSC::JSValue thisValue, JSC::JSValue* exception);
 
 } // namespace WebCore
index c26f38ad71f03f35f267fa6a7052b624989fab31..7eb357a4a30ede20ff1debbcccc5af3d3d476182 100644 (file)
@@ -87,12 +87,13 @@ void JSMutationCallback::call(const Vector<RefPtr<MutationRecord>>& mutations, M
 
     InspectorInstrumentationCookie cookie = JSMainThreadExecState::instrumentFunctionCall(context, callType, callData);
 
-    JSMainThreadExecState::call(exec, callback, callType, callData, jsObserver, args);
+    JSValue exception;
+    JSMainThreadExecState::call(exec, callback, callType, callData, jsObserver, args, &exception);
 
     InspectorInstrumentation::didCallFunction(cookie, context);
 
-    if (exec->hadException())
-        reportCurrentException(exec);
+    if (exception)
+        reportException(exec, exception);
 }
 
 } // namespace WebCore
index d1b4721351eb1b2bf8ce0cd473fee144914c53ab..71726bbf1b1eb671e1a6b4ed482c61e2b58abca3 100644 (file)
@@ -67,7 +67,7 @@ short JSNodeFilterCondition::acceptNode(JSC::ExecState* exec, Node* filterNode)
     if (exec->hadException())
         return NodeFilter::FILTER_REJECT;
 
-    JSValue result = JSMainThreadExecState::call(exec, filter, callType, callData, m_filter.get(), args);
+    JSValue result = JSC::call(exec, filter, callType, callData, m_filter.get(), args);
     if (exec->hadException())
         return NodeFilter::FILTER_REJECT;
 
index eb0e31a8ba8eae4b2d03e290e830f4806f960275..f596371209bb7121361a516ad724ca523ab7757e 100644 (file)
@@ -99,15 +99,16 @@ void ScheduledAction::executeFunctionInContext(JSGlobalObject* globalObject, JSV
 
     InspectorInstrumentationCookie cookie = JSMainThreadExecState::instrumentFunctionCall(context, callType, callData);
 
+    JSValue exception;
     if (context->isDocument())
-        JSMainThreadExecState::call(exec, m_function.get(), callType, callData, thisValue, args);
+        JSMainThreadExecState::call(exec, m_function.get(), callType, callData, thisValue, args, &exception);
     else
-        JSC::call(exec, m_function.get(), callType, callData, thisValue, args);
+        JSC::call(exec, m_function.get(), callType, callData, thisValue, args, &exception);
 
     InspectorInstrumentation::didCallFunction(cookie, context);
 
-    if (exec->hadException())
-        reportCurrentException(exec);
+    if (exception)
+        reportException(exec, exception);
 }
 
 void ScheduledAction::execute(Document* document)
index 0427cb6a92fc768d14613814fa45efd37ed79e38..c5cf37e1848932c164ed0243d71f5055c2a3bf4c 100644 (file)
@@ -120,12 +120,19 @@ id createJSWrapper(JSC::JSObject* object, PassRefPtr<JSC::Bindings::RootObject>
     return [[[WebScriptObject alloc] _initWithJSObject:object originRootObject:origin rootObject:root] autorelease];
 }
 
-static void addExceptionToConsole(ExecState* exec)
+static void addExceptionToConsole(ExecState* exec, JSC::JSValue& exception)
 {
     JSDOMWindow* window = asJSDOMWindow(exec->vmEntryGlobalObject());
-    if (!window || !exec->hadException())
+    if (!window || !exception)
         return;
-    reportCurrentException(exec);
+    reportException(exec, exception);
+}
+
+static void addExceptionToConsole(ExecState* exec)
+{
+    JSC::JSValue exception = exec->exception();
+    exec->clearException();
+    addExceptionToConsole(exec, exception);
 }
 
 } // namespace WebCore
@@ -334,12 +341,12 @@ static void getListFromNSArray(ExecState *exec, NSArray *array, RootObject* root
     if (![self _isSafeScript])
         return nil;
 
-    JSC::JSValue result = JSMainThreadExecState::call(exec, function, callType, callData, [self _imp], argList);
+    JSC::JSValue exception;
+    JSC::JSValue result = JSMainThreadExecState::call(exec, function, callType, callData, [self _imp], argList, &exception);
 
-    if (exec->hadException()) {
-        addExceptionToConsole(exec);
+    if (exception) {
+        addExceptionToConsole(exec, exception);
         result = jsUndefined();
-        exec->clearException();
     }
 
     // Convert and return the result of the function call.