Changeset 167142 in webkit


Ignore:
Timestamp:
Apr 11, 2014 1:24:56 PM (10 years ago)
Author:
mark.lam@apple.com
Message:

JSMainThreadExecState::call() should clear exceptions before returning.
<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.
Location:
trunk
Files:
2 added
20 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r167139 r167142  
     12014-04-11  Mark Lam  <mark.lam@apple.com>
     2
     3        JSMainThreadExecState::call() should clear exceptions before returning.
     4        <https://webkit.org/b/131530>
     5
     6        Reviewed by Geoffrey Garen.
     7
     8        * fast/dom/regress-131530-expected.txt: Added.
     9        * fast/dom/regress-131530.html: Added.
     10
    1112014-04-11  Carlos Alberto Lopez Perez  <clopez@igalia.com>
    212
  • trunk/Source/JavaScriptCore/ChangeLog

    r167137 r167142  
     12014-04-11  Mark Lam  <mark.lam@apple.com>
     2
     3        JSMainThreadExecState::call() should clear exceptions before returning.
     4        <https://webkit.org/b/131530>
     5
     6        Reviewed by Geoffrey Garen.
     7
     8        Added a version of JSC::call() that return any uncaught exception instead
     9        of leaving it pending in the VM.
     10
     11        As part of this change, I updated various parts of the code base to use the
     12        new API as needed.
     13
     14        * bindings/ScriptFunctionCall.cpp:
     15        (Deprecated::ScriptFunctionCall::call):
     16        - ScriptFunctionCall::call() is only used by the inspector to inject scripts.
     17          The injected scripts that will include Inspector scripts that should catch
     18          and handle any exceptions that were thrown.  We should not be seeing any
     19          exceptions returned from this call.  However, we do have checks for
     20          exceptions in case there are bugs in the Inspector scripts which allowed
     21          the exception to leak through.  Hence, it is proper to clear the exception
     22          here, and only record the fact that an exception was seen (if present).
     23
     24        * bindings/ScriptFunctionCall.h:
     25        * inspector/InspectorEnvironment.h:
     26        * runtime/CallData.cpp:
     27        (JSC::call):
     28        * runtime/CallData.h:
     29
    1302014-04-11  Oliver Hunt  <oliver@apple.com>
    231
  • trunk/Source/JavaScriptCore/bindings/ScriptFunctionCall.cpp

    r163844 r167142  
    134134
    135135    JSValue result;
     136    JSValue exception;
    136137    if (m_callHandler)
    137         result = m_callHandler(m_exec, function, callType, callData, thisObject, m_arguments);
     138        result = m_callHandler(m_exec, function, callType, callData, thisObject, m_arguments, &exception);
    138139    else
    139         result = JSC::call(m_exec, function, callType, callData, thisObject, m_arguments);
     140        result = JSC::call(m_exec, function, callType, callData, thisObject, m_arguments, &exception);
    140141
    141     if (m_exec->hadException()) {
     142    if (exception) {
    142143        hadException = true;
    143144        return Deprecated::ScriptValue();
  • trunk/Source/JavaScriptCore/bindings/ScriptFunctionCall.h

    r160457 r167142  
    7272class JS_EXPORT_PRIVATE ScriptFunctionCall : public ScriptCallArgumentHandler {
    7373public:
    74     typedef JSC::JSValue (*ScriptFunctionCallHandler)(JSC::ExecState* exec, JSC::JSValue functionObject, JSC::CallType callType, const JSC::CallData& callData, JSC::JSValue thisValue, const JSC::ArgList& args);
     74    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);
    7575    ScriptFunctionCall(const ScriptObject& thisObject, const String& name, ScriptFunctionCallHandler handler = nullptr);
    7676    ScriptValue call(bool& hadException);
  • trunk/Source/JavaScriptCore/inspector/InspectorEnvironment.h

    r163139 r167142  
    3535namespace Inspector {
    3636
    37 typedef JSC::JSValue (*InspectorFunctionCallHandler)(JSC::ExecState* exec, JSC::JSValue functionObject, JSC::CallType callType, const JSC::CallData& callData, JSC::JSValue thisValue, const JSC::ArgList& args);
     37typedef 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);
    3838typedef JSC::JSValue (*InspectorEvaluateHandler)(JSC::ExecState*, const JSC::SourceCode&, JSC::JSValue thisValue, JSC::JSValue* exception);
    3939
  • trunk/Source/JavaScriptCore/runtime/CallData.cpp

    r163844 r167142  
    4040}
    4141
     42JSValue call(ExecState* exec, JSValue functionObject, CallType callType, const CallData& callData, JSValue thisValue, const ArgList& args, JSValue* exception)
     43{
     44    JSValue result = call(exec, functionObject, callType, callData, thisValue, args);
     45    if (exec->hadException()) {
     46        if (exception)
     47            *exception = exec->exception();
     48        exec->clearException();
     49        return jsUndefined();
     50    }
     51    RELEASE_ASSERT(result);
     52    return result;
     53}
     54
    4255} // namespace JSC
  • trunk/Source/JavaScriptCore/runtime/CallData.h

    r165676 r167142  
    5959
    6060JS_EXPORT_PRIVATE JSValue call(ExecState*, JSValue functionObject, CallType, const CallData&, JSValue thisValue, const ArgList&);
     61JS_EXPORT_PRIVATE JSValue call(ExecState*, JSValue functionObject, CallType, const CallData&, JSValue thisValue, const ArgList&, JSValue* exception);
    6162
    6263} // namespace JSC
  • trunk/Source/WebCore/ChangeLog

    r167140 r167142  
     12014-04-11  Mark Lam  <mark.lam@apple.com>
     2
     3        JSMainThreadExecState::call() should clear exceptions before returning.
     4        <https://webkit.org/b/131530>
     5
     6        Reviewed by Geoffrey Garen.
     7
     8        Test: fast/dom/regress-131530.html
     9
     10        Previously, JSMainThreadExecState::call() did not clear any pending
     11        exceptions in the VM before returning.  On returning, the
     12        JSMainThreadExecState destructor may re-enter the VM to notify
     13        MutationObservers.  This may result in a crash because the VM expects
     14        exceptions to be cleared at entry.
     15
     16        We now change JSMainThreadExecState::call() to return the exception
     17        (if present) via an argument, and clear it from the VM before returning.
     18
     19        As part of this change, I updated various parts of the code base to use the
     20        new API as needed.
     21
     22        * bindings/js/JSCallbackData.cpp:
     23        (WebCore::JSCallbackData::invokeCallback):
     24        * bindings/js/JSCustomXPathNSResolver.cpp:
     25        (WebCore::JSCustomXPathNSResolver::lookupNamespaceURI):
     26        * bindings/js/JSDOMGlobalObjectTask.cpp:
     27        - Assert that there's no unhandled exception after the Microtask returns.
     28          See comment for WebCore::JSMainThreadExecState::runTask below for more
     29          details.
     30
     31        * bindings/js/JSErrorHandler.cpp:
     32        (WebCore::JSErrorHandler::handleEvent):
     33        * bindings/js/JSEventListener.cpp:
     34        (WebCore::JSEventListener::handleEvent):
     35        * bindings/js/JSHTMLDocumentCustom.cpp:
     36        (WebCore::JSHTMLDocument::open):
     37        - Document.open() cannot be the first function on the JS stack.  Hence,
     38          there is no need to use JSMainThreadExecState to call into the VM, as
     39          this is only needed to catch the event of returning from the first
     40          function for the purpose of notifying MutationObservers.  Change to
     41          call JSC::call() directly.
     42
     43        * bindings/js/JSMainThreadExecState.cpp:
     44        (WebCore::functionCallHandlerFromAnyThread):
     45        * bindings/js/JSMainThreadExecState.h:
     46        (WebCore::JSMainThreadExecState::call):
     47        (WebCore::JSMainThreadExecState::evaluate):
     48        - Remove the explicitly acquisition of the JSLock here because we now
     49          acquire the JSLock as part of the JSMainThreadExecState instance.
     50        (WebCore::JSMainThreadExecState::runTask):
     51        - Added an assert to verify that the task does not return with an
     52          unhandled exception.  Currently, the only Microtask in use is for the
     53          Promise implementation, which will eat the exception before returning.
     54          This assertion is added here to verify that this contract does not
     55          inadvertantly change in the future.
     56        (WebCore::JSMainThreadExecState::JSMainThreadExecState):
     57        - Now acquires the JSLock as well since by definition, we're only
     58          instantiating the JSMainThreadExecState because we're about to enter
     59          the VM.
     60
     61        * bindings/js/JSMutationCallback.cpp:
     62        (WebCore::JSMutationCallback::call):
     63        * bindings/js/JSNodeFilterCondition.cpp:
     64        (WebCore::JSNodeFilterCondition::acceptNode):
     65        - acceptNode() is only used in the TreeWalker and NodeIterator APIs which
     66          cannot be the first function on the JS stack.  Hence, we should call
     67          JSC::call() directly instead of going through JSMainThreadExecState.
     68
     69        * bindings/js/ScheduledAction.cpp:
     70        (WebCore::ScheduledAction::executeFunctionInContext):
     71        * bindings/objc/WebScriptObject.mm:
     72        (WebCore::addExceptionToConsole):
     73        (-[WebScriptObject callWebScriptMethod:withArguments:]):
     74
    1752014-04-11  Brian J. Burg  <burg@cs.washington.edu>
    276
  • trunk/Source/WebCore/bindings/js/JSCallbackData.cpp

    r165676 r167142  
    7474    InspectorInstrumentationCookie cookie = JSMainThreadExecState::instrumentFunctionCall(context, callType, callData);
    7575
     76    JSValue exception;
    7677    JSValue result = context->isDocument()
    77         ? JSMainThreadExecState::call(exec, function, callType, callData, thisValue, args)
    78         : JSC::call(exec, function, callType, callData, thisValue, args);
     78        ? JSMainThreadExecState::call(exec, function, callType, callData, thisValue, args, &exception)
     79        : JSC::call(exec, function, callType, callData, thisValue, args, &exception);
    7980
    8081    InspectorInstrumentation::didCallFunction(cookie, context);
    8182
    82     if (exec->hadException()) {
    83         reportCurrentException(exec);
     83    if (exception) {
     84        reportException(exec, exception);
    8485        if (raisedException)
    8586            *raisedException = true;
  • trunk/Source/WebCore/bindings/js/JSCustomXPathNSResolver.cpp

    r165676 r167142  
    9393    args.append(jsStringWithCache(exec, prefix));
    9494
    95     JSValue retval = JSMainThreadExecState::call(exec, function, callType, callData, m_customResolver.get(), args);
     95    JSValue exception;
     96    JSValue retval = JSMainThreadExecState::call(exec, function, callType, callData, m_customResolver.get(), args, &exception);
    9697
    9798    String result;
    98     if (exec->hadException())
    99         reportCurrentException(exec);
     99    if (exception)
     100        reportException(exec, exception);
    100101    else {
    101102        if (!retval.isUndefinedOrNull())
  • trunk/Source/WebCore/bindings/js/JSDOMGlobalObjectTask.cpp

    r166943 r167142  
    6565        else
    6666            m_task->run(exec);
     67        ASSERT(!exec->hadException());
    6768    }
    6869
  • trunk/Source/WebCore/bindings/js/JSErrorHandler.cpp

    r164184 r167142  
    9999        VMEntryScope entryScope(vm, vm.entryScope ? vm.entryScope->globalObject() : globalObject);
    100100
     101        JSValue exception;
    101102        JSValue returnValue = scriptExecutionContext->isDocument()
    102             ? JSMainThreadExecState::call(exec, jsFunction, callType, callData, globalObject, args)
    103             : JSC::call(exec, jsFunction, callType, callData, globalObject, args);
     103            ? JSMainThreadExecState::call(exec, jsFunction, callType, callData, globalObject, args, &exception)
     104            : JSC::call(exec, jsFunction, callType, callData, globalObject, args, &exception);
    104105
    105106        globalObject->setCurrentEvent(savedEvent);
    106107
    107         if (exec->hadException())
    108             reportCurrentException(exec);
     108        if (exception)
     109            reportException(exec, exception);
    109110        else {
    110111            if (returnValue.isTrue())
  • trunk/Source/WebCore/bindings/js/JSEventListener.cpp

    r164735 r167142  
    123123
    124124        JSValue thisValue = handleEventFunction == jsFunction ? toJS(exec, globalObject, event->currentTarget()) : jsFunction;
     125        JSValue exception;
    125126        JSValue retval = scriptExecutionContext->isDocument()
    126             ? JSMainThreadExecState::call(exec, handleEventFunction, callType, callData, thisValue, args)
    127             : JSC::call(exec, handleEventFunction, callType, callData, thisValue, args);
     127            ? JSMainThreadExecState::call(exec, handleEventFunction, callType, callData, thisValue, args, &exception)
     128            : JSC::call(exec, handleEventFunction, callType, callData, thisValue, args, &exception);
    128129
    129130        InspectorInstrumentation::didCallFunction(cookie, scriptExecutionContext);
     
    137138        }
    138139
    139         if (exec->hadException()) {
     140        if (exception) {
    140141            event->target()->uncaughtExceptionInEventHandler();
    141             reportCurrentException(exec);
     142            reportException(exec, exception);
    142143        } else {
    143144            if (!retval.isUndefinedOrNull() && event->isBeforeUnloadEvent())
  • trunk/Source/WebCore/bindings/js/JSHTMLDocumentCustom.cpp

    r165676 r167142  
    114114                if (callType == CallTypeNone)
    115115                    return throwTypeError(exec);
    116                 return JSMainThreadExecState::call(exec, function, callType, callData, wrapper, ArgList(exec));
     116                return JSC::call(exec, function, callType, callData, wrapper, ArgList(exec));
    117117            }
    118118        }
  • trunk/Source/WebCore/bindings/js/JSMainThreadExecState.cpp

    r161563 r167142  
    4747}
    4848
    49 JSC::JSValue functionCallHandlerFromAnyThread(JSC::ExecState* exec, JSC::JSValue functionObject, JSC::CallType callType, const JSC::CallData& callData, JSC::JSValue thisValue, const JSC::ArgList& args)
     49JSC::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)
    5050{
    5151    if (isMainThread())
    52         return JSMainThreadExecState::call(exec, functionObject, callType, callData, thisValue, args);
    53     return JSC::call(exec, functionObject, callType, callData, thisValue, args);
     52        return JSMainThreadExecState::call(exec, functionObject, callType, callData, thisValue, args, exception);
     53    return JSC::call(exec, functionObject, callType, callData, thisValue, args, exception);
    5454}
    5555
  • trunk/Source/WebCore/bindings/js/JSMainThreadExecState.h

    r166943 r167142  
    5151    };
    5252   
    53     static JSC::JSValue call(JSC::ExecState* exec, JSC::JSValue functionObject, JSC::CallType callType, const JSC::CallData& callData, JSC::JSValue thisValue, const JSC::ArgList& args)
     53    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)
    5454    {
    5555        JSMainThreadExecState currentState(exec);
    56         return JSC::call(exec, functionObject, callType, callData, thisValue, args);
     56        return JSC::call(exec, functionObject, callType, callData, thisValue, args, exception);
    5757    };
    5858
     
    6060    {
    6161        JSMainThreadExecState currentState(exec);
    62         JSC::JSLockHolder lock(exec);
    6362        return JSC::evaluate(exec, source, thisValue, exception);
    6463    };
     
    7574    explicit JSMainThreadExecState(JSC::ExecState* exec)
    7675        : m_previousState(s_mainThreadState)
     76        , m_lock(exec)
    7777    {
    7878        ASSERT(isMainThread());
     
    8383    {
    8484        ASSERT(isMainThread());
     85        ASSERT(!s_mainThreadState->hadException());
    8586
    8687        bool didExitJavaScript = s_mainThreadState && !m_previousState;
     
    9495    static JSC::ExecState* s_mainThreadState;
    9596    JSC::ExecState* m_previousState;
     97    JSC::JSLockHolder m_lock;
    9698
    9799    static void didLeaveScriptContext();
     
    120122};
    121123
    122 JSC::JSValue functionCallHandlerFromAnyThread(JSC::ExecState*, JSC::JSValue functionObject, JSC::CallType callType, const JSC::CallData& callData, JSC::JSValue thisValue, const JSC::ArgList& args);
     124JSC::JSValue functionCallHandlerFromAnyThread(JSC::ExecState*, JSC::JSValue functionObject, JSC::CallType, const JSC::CallData&, JSC::JSValue thisValue, const JSC::ArgList& args, JSC::JSValue* exception);
    123125JSC::JSValue evaluateHandlerFromAnyThread(JSC::ExecState*, const JSC::SourceCode&, JSC::JSValue thisValue, JSC::JSValue* exception);
    124126
  • trunk/Source/WebCore/bindings/js/JSMutationCallback.cpp

    r163139 r167142  
    8888    InspectorInstrumentationCookie cookie = JSMainThreadExecState::instrumentFunctionCall(context, callType, callData);
    8989
    90     JSMainThreadExecState::call(exec, callback, callType, callData, jsObserver, args);
     90    JSValue exception;
     91    JSMainThreadExecState::call(exec, callback, callType, callData, jsObserver, args, &exception);
    9192
    9293    InspectorInstrumentation::didCallFunction(cookie, context);
    9394
    94     if (exec->hadException())
    95         reportCurrentException(exec);
     95    if (exception)
     96        reportException(exec, exception);
    9697}
    9798
  • trunk/Source/WebCore/bindings/js/JSNodeFilterCondition.cpp

    r163225 r167142  
    6868        return NodeFilter::FILTER_REJECT;
    6969
    70     JSValue result = JSMainThreadExecState::call(exec, filter, callType, callData, m_filter.get(), args);
     70    JSValue result = JSC::call(exec, filter, callType, callData, m_filter.get(), args);
    7171    if (exec->hadException())
    7272        return NodeFilter::FILTER_REJECT;
  • trunk/Source/WebCore/bindings/js/ScheduledAction.cpp

    r164182 r167142  
    100100    InspectorInstrumentationCookie cookie = JSMainThreadExecState::instrumentFunctionCall(context, callType, callData);
    101101
     102    JSValue exception;
    102103    if (context->isDocument())
    103         JSMainThreadExecState::call(exec, m_function.get(), callType, callData, thisValue, args);
     104        JSMainThreadExecState::call(exec, m_function.get(), callType, callData, thisValue, args, &exception);
    104105    else
    105         JSC::call(exec, m_function.get(), callType, callData, thisValue, args);
     106        JSC::call(exec, m_function.get(), callType, callData, thisValue, args, &exception);
    106107
    107108    InspectorInstrumentation::didCallFunction(cookie, context);
    108109
    109     if (exec->hadException())
    110         reportCurrentException(exec);
     110    if (exception)
     111        reportException(exec, exception);
    111112}
    112113
  • trunk/Source/WebCore/bindings/objc/WebScriptObject.mm

    r165848 r167142  
    121121}
    122122
     123static void addExceptionToConsole(ExecState* exec, JSC::JSValue& exception)
     124{
     125    JSDOMWindow* window = asJSDOMWindow(exec->vmEntryGlobalObject());
     126    if (!window || !exception)
     127        return;
     128    reportException(exec, exception);
     129}
     130
    123131static void addExceptionToConsole(ExecState* exec)
    124132{
    125     JSDOMWindow* window = asJSDOMWindow(exec->vmEntryGlobalObject());
    126     if (!window || !exec->hadException())
    127         return;
    128     reportCurrentException(exec);
     133    JSC::JSValue exception = exec->exception();
     134    exec->clearException();
     135    addExceptionToConsole(exec, exception);
    129136}
    130137
     
    335342        return nil;
    336343
    337     JSC::JSValue result = JSMainThreadExecState::call(exec, function, callType, callData, [self _imp], argList);
    338 
    339     if (exec->hadException()) {
    340         addExceptionToConsole(exec);
     344    JSC::JSValue exception;
     345    JSC::JSValue result = JSMainThreadExecState::call(exec, function, callType, callData, [self _imp], argList, &exception);
     346
     347    if (exception) {
     348        addExceptionToConsole(exec, exception);
    341349        result = jsUndefined();
    342         exec->clearException();
    343350    }
    344351
Note: See TracChangeset for help on using the changeset viewer.