finally blocks should not set the exception stack trace when re-throwing the exception.
authormark.lam@apple.com <mark.lam@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 5 Jun 2015 18:52:12 +0000 (18:52 +0000)
committermark.lam@apple.com <mark.lam@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 5 Jun 2015 18:52:12 +0000 (18:52 +0000)
https://bugs.webkit.org/show_bug.cgi?id=145525

Reviewed by Geoffrey Garen.

Source/JavaScriptCore:

How exceptions presently work:
=============================
1. op_throw can throw any JSValue.
2. the VM tries to capture the stack at the throw point and propagate that as needed.
3. finally blocks are implemented using op_catch to catch the thrown value, and throws it again using op_throw.

What's wrong with how it presently works:
========================================
1. finally's makes for bad exception throw line numbers in the Inspector console.

   The op_throw in finally will throw the value anew i.e. it captures a stack from the re-throw point.
   As a result, the Inspector sees the finally block as the throw point.  The original stack is lost.

2. finally's breaks the Inspector's "Breaks on Uncaught Exception"

   This is because finally blocks are indistinguishable from catch blocks.  As a result, a try-finally,
   which should break in the Inspector on the throw, does not because the Inspector thought the
   exception was "caught".

3. finally's yields confusing break points when the Inspector "Breaks on All Exceptions"

   a. In a try-finally scenario, the Inspector breaks 2 times: 1 at the throw, 1 at the finally.
   b. In a for-of loop (which has synthesized finallys), the Inspector will do another break.
      Similarly for other cases of JS code which synthesize finallys.
   c. At VM re-entry boundaries (e.g. js throws & returns to native code, which returns to js),
      the Inspector will do another break if there's an uncaught exception.

How this patch fixes the issues:
===============================
1. We introduce an Exception object that wraps the thrown value and the exception stack.

   When throwing an exception, the VM will check if the thrown value is an Exception
   object or not.  If it is not an Exception object, then we must be throwing a new
   exception.  The VM will create an Exception object to wrap the thrown value and
   capture the current stack for it.

   If the thrown value is already an Exception object, then the requested throw operation
   must be a re-throw.  The VM will not capture a new stack for it.

2. op_catch will now populate 2 locals: 1 for the Exception, 1 for the thrown JSValue.

   The VM is aware of the Exception object and uses it for rethrows in finally blocks.
   JS source code is never aware of the Exception object.

   JS code is aware of the thrown value.  If it throws the caught thrown value, that
   constitutes a new throw, and a new Exception object will be created for it.

3. The VM no longer tracks the thrown JSValue and the exception stack.  It will only
   track a m_exception field which is an Exception*.

4. The BytecodeGenerator has already been updated in a prior patch to distinguish
   between Catch, Finally, and SynthesizedFinally blocks.  The interpreter runtime will
   now report to the debugger whether we have a Catch handler, not just any handlers.

   The debugger will use this detail to determine whether to break or not.  "Break on
   uncaught exceptions" will only break if no Catch handler was found.

   This solves the issue of the debugger breaking at finally blocks, and for-of statements.

5. The Exception object will also have a flag to indicate whether the debugger has been
   notified of the Exception being thrown.  Once the Interpreter notifies the debugger
   of the Exception object, it will mark this flag and not repeat the notify the debugger
   again of the same Exception.

   This solves the issue of the debugger breaking at VM re-entry points due to uncaught
   exceptions.

6. The life-cycle of the captured exception stack trace will now follow the life-cycle
   of the Exception object.

Other changes:
7. Change all clients of the VM::exception() to expect an Exception* instead of JSValue.

8. Fixed a few bugs where thrown exceptions are not cleared before exiting the VM.

9. Also renamed some variables and classes to better describe what they are.

* API/JSBase.cpp:
(JSEvaluateScript):
(JSCheckScriptSyntax):

* API/JSObjectRef.cpp:
(handleExceptionIfNeeded):
- The functions below all do the same exception check.  Added this helper
  to simplify the code.
(JSClassCreate):
(JSObjectMakeFunction):
(JSObjectMakeArray):
(JSObjectMakeDate):
(JSObjectMakeError):
(JSObjectMakeRegExp):
(JSObjectGetProperty):
(JSObjectSetProperty):
(JSObjectGetPropertyAtIndex):
(JSObjectSetPropertyAtIndex):
(JSObjectDeleteProperty):
(JSObjectCallAsFunction):
(JSObjectCallAsConstructor):

* API/JSScriptRef.cpp:
* API/JSValue.mm:
(JSContainerConvertor::take):
(reportExceptionToInspector):

* API/JSValueRef.cpp:
(handleExceptionIfNeeded):
- The functions below all do the same exception check.  Added this helper
  to simplify the code.
(evernoteHackNeeded):
(JSValueIsEqual):
(JSValueIsInstanceOfConstructor):
(JSValueCreateJSONString):
(JSValueToNumber):
(JSValueToStringCopy):
(JSValueToObject):

* CMakeLists.txt:
* JavaScriptCore.vcxproj/JavaScriptCore.vcxproj:
* JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters:
* JavaScriptCore.xcodeproj/project.pbxproj:
- Added new files Exception.h and Exception.cpp.

* bindings/ScriptFunctionCall.cpp:
(Deprecated::ScriptFunctionCall::call):
* bindings/ScriptFunctionCall.h:

* bytecode/BytecodeList.json:
- op_catch now had 2 operands: the exception register, and the thrown value register.

* bytecode/BytecodeUseDef.h:
(JSC::computeDefsForBytecodeOffset):
* bytecode/CodeBlock.cpp:
(JSC::CodeBlock::dumpBytecode):
(JSC::CodeBlock::handlerForBytecodeOffset):
* bytecode/CodeBlock.h:
- handlerForBytecodeOffset() now can look for just Catch handlers only.

* bytecode/HandlerInfo.h:
- Cleaned up some white space I accidentally added in a previous patch.

* bytecompiler/BytecodeGenerator.cpp:
(JSC::BytecodeGenerator::pushTry):
(JSC::BytecodeGenerator::popTryAndEmitCatch):
(JSC::BytecodeGenerator::emitThrowReferenceError):
(JSC::BytecodeGenerator::emitEnumeration):
* bytecompiler/BytecodeGenerator.h:
(JSC::BytecodeGenerator::emitThrow):
* bytecompiler/NodesCodegen.cpp:
(JSC::TryNode::emitBytecode):
- Adding support for op_catch's 2 operands.

* debugger/Debugger.cpp:
(JSC::Debugger::hasBreakpoint):
(JSC::Debugger::pauseIfNeeded):
(JSC::Debugger::exception):
* debugger/Debugger.h:
* debugger/DebuggerCallFrame.cpp:
(JSC::DebuggerCallFrame::thisValue):
(JSC::DebuggerCallFrame::evaluate):
* debugger/DebuggerCallFrame.h:
(JSC::DebuggerCallFrame::isValid):
* inspector/InjectedScriptManager.cpp:
(Inspector::InjectedScriptManager::createInjectedScript):
* inspector/InspectorEnvironment.h:
* inspector/JSGlobalObjectInspectorController.cpp:
(Inspector::JSGlobalObjectInspectorController::appendAPIBacktrace):
(Inspector::JSGlobalObjectInspectorController::reportAPIException):
* inspector/JSGlobalObjectInspectorController.h:
* inspector/JSGlobalObjectScriptDebugServer.h:
* inspector/JSJavaScriptCallFrame.cpp:
(Inspector::JSJavaScriptCallFrame::evaluate):
* inspector/JavaScriptCallFrame.h:
(Inspector::JavaScriptCallFrame::vmEntryGlobalObject):
(Inspector::JavaScriptCallFrame::thisValue):
(Inspector::JavaScriptCallFrame::evaluate):
* inspector/ScriptCallStackFactory.cpp:
(Inspector::extractSourceInformationFromException):
(Inspector::createScriptCallStackFromException):
* inspector/ScriptCallStackFactory.h:
* inspector/ScriptDebugServer.cpp:
(Inspector::ScriptDebugServer::evaluateBreakpointAction):
(Inspector::ScriptDebugServer::handleBreakpointHit):
(Inspector::ScriptDebugServer::handleExceptionInBreakpointCondition):
* inspector/ScriptDebugServer.h:
* interpreter/CallFrame.h:
(JSC::ExecState::clearException):
(JSC::ExecState::exception):
(JSC::ExecState::hadException):
(JSC::ExecState::atomicStringTable):
(JSC::ExecState::propertyNames):
(JSC::ExecState::clearSupplementaryExceptionInfo): Deleted.

* interpreter/Interpreter.cpp:
(JSC::unwindCallFrame):
(JSC::Interpreter::stackTraceAsString):
(JSC::GetCatchHandlerFunctor::GetCatchHandlerFunctor):
(JSC::GetCatchHandlerFunctor::operator()):
(JSC::Interpreter::unwind):
- Added a check for didNotifyInspectorOfThrow() here to prevent duplicate reports
  of the same Exception to the debugger.

(JSC::GetExceptionHandlerFunctor::GetExceptionHandlerFunctor): Deleted.
(JSC::GetExceptionHandlerFunctor::operator()): Deleted.
- Renamed GetExceptionHandlerFunctor to GetCatchHandlerFunctor since the debugger
  is only interested in knowing whether we have Catch handlers.

* interpreter/Interpreter.h:
(JSC::SuspendExceptionScope::SuspendExceptionScope):
(JSC::SuspendExceptionScope::~SuspendExceptionScope):
(JSC::Interpreter::sampler):
(JSC::ClearExceptionScope::ClearExceptionScope): Deleted.
(JSC::ClearExceptionScope::~ClearExceptionScope): Deleted.
- Renamed ClearExceptionScope to SuspendExceptionScope because "clear" implies that
  we're purging the exception.  Instead, we're merely suspending any handling of
  that exception for a period defined by the scope.

* jit/AssemblyHelpers.cpp:
(JSC::AssemblyHelpers::emitExceptionCheck):

* jit/JITExceptions.cpp:
(JSC::genericUnwind):
- Removed the exception argument.  It is always the value in VM::exception() anyway.
  genericUnwind() can just get it from the VM, and save everyone some work.

* jit/JITExceptions.h:
* jit/JITOpcodes.cpp:
(JSC::JIT::emit_op_catch):
* jit/JITOpcodes32_64.cpp:
(JSC::JIT::privateCompileCTINativeCall):
(JSC::JIT::emit_op_catch):
- Add support for the new op_catch operands.

* jit/JITOperations.cpp:
* jit/ThunkGenerators.cpp:
(JSC::nativeForGenerator):
* jsc.cpp:
(functionRun):
(functionLoad):
(runWithScripts):
(runInteractive):
* llint/LLIntOffsetsExtractor.cpp:
* llint/LLIntSlowPaths.cpp:
(JSC::LLInt::LLINT_SLOW_PATH_DECL):

* llint/LowLevelInterpreter32_64.asm:
* llint/LowLevelInterpreter64.asm:
- Add support for the new op_catch operands.  Also update the code to handle
  VM::m_exception being an Exception pointer, not a JSValue.

* parser/NodeConstructors.h:
(JSC::TryNode::TryNode):
* parser/Nodes.h:
* runtime/CallData.cpp:
(JSC::call):
* runtime/CallData.h:

* runtime/Completion.cpp:
(JSC::evaluate):
* runtime/Completion.h:
(JSC::evaluate):
- Change evaluate() to take a reference to the returned exception value instead
  of a pointer.  In all but 2 or 3 cases, we want the returned exception anyway.
  Might as well simplify the code by requiring the reference.

* runtime/Error.h:
(JSC::throwVMError):
(JSC::throwVMTypeError):

* runtime/Exception.cpp: Added.
(JSC::Exception::create):
(JSC::Exception::destroy):
(JSC::Exception::createStructure):
(JSC::Exception::visitChildren):
(JSC::Exception::Exception):
(JSC::Exception::~Exception):
* runtime/Exception.h: Added.
(JSC::Exception::valueOffset):
(JSC::Exception::cast):
(JSC::Exception::value):
(JSC::Exception::stack):
(JSC::Exception::didNotifyInspectorOfThrow):
(JSC::Exception::setDidNotifyInspectorOfThrow):

* runtime/ExceptionHelpers.cpp:
(JSC::createTerminatedExecutionException):
(JSC::isTerminatedExecutionException):
(JSC::createStackOverflowError):
* runtime/ExceptionHelpers.h:
* runtime/GetterSetter.cpp:
(JSC::callGetter):
* runtime/IteratorOperations.cpp:
(JSC::iteratorClose):
* runtime/JSObject.cpp:
* runtime/JSPromiseConstructor.cpp:
(JSC::constructPromise):
* runtime/JSPromiseDeferred.cpp:
(JSC::updateDeferredFromPotentialThenable):
(JSC::abruptRejection):
* runtime/JSPromiseReaction.cpp:
(JSC::ExecutePromiseReactionMicrotask::run):

* runtime/VM.cpp:
(JSC::VM::VM):
(JSC::VM::releaseExecutableMemory):
(JSC::VM::throwException):
(JSC::VM::setStackPointerAtVMEntry):
(JSC::VM::getExceptionInfo): Deleted.
(JSC::VM::setExceptionInfo): Deleted.
(JSC::VM::clearException): Deleted.
(JSC::clearExceptionStack): Deleted.
* runtime/VM.h:
(JSC::VM::targetMachinePCForThrowOffset):
(JSC::VM::clearException):
(JSC::VM::setException):
(JSC::VM::exception):
(JSC::VM::addressOfException):
(JSC::VM::exceptionStack): Deleted.
* runtime/VMEntryScope.cpp:
(JSC::VMEntryScope::VMEntryScope):
(JSC::VMEntryScope::setEntryScopeDidPopListener):

Source/WebCore:

Update to use the new JSC::Exception object.

Test: inspector/debugger/break-on-exceptions.html

* ForwardingHeaders/runtime/Exception.h: Added.
* bindings/js/JSCallbackData.cpp:
(WebCore::JSCallbackData::invokeCallback):
* bindings/js/JSCustomXPathNSResolver.cpp:
(WebCore::JSCustomXPathNSResolver::lookupNamespaceURI):
* bindings/js/JSDOMBinding.cpp:
(WebCore::jsArray):
(WebCore::reportException):
(WebCore::reportCurrentException):
* bindings/js/JSDOMBinding.h:
* bindings/js/JSErrorHandler.cpp:
(WebCore::JSErrorHandler::handleEvent):
* bindings/js/JSEventListener.cpp:
(WebCore::JSEventListener::handleEvent):
* bindings/js/JSMainThreadExecState.cpp:
(WebCore::JSMainThreadExecState::didLeaveScriptContext):
(WebCore::functionCallHandlerFromAnyThread):
(WebCore::evaluateHandlerFromAnyThread):
* bindings/js/JSMainThreadExecState.h:
(WebCore::JSMainThreadExecState::currentState):
(WebCore::JSMainThreadExecState::call):
(WebCore::JSMainThreadExecState::evaluate):
(WebCore::JSMainThreadExecState::runTask):

* bindings/js/JSMediaDevicesCustom.cpp:
(WebCore::JSMediaDevices::getUserMedia):
- Fixed a bug where the exception was not cleared before entering the VM to
  call JS code.

* bindings/js/JSMutationCallback.cpp:
(WebCore::JSMutationCallback::call):
* bindings/js/ReadableJSStream.cpp:
(WebCore::getPropertyFromObject):
(WebCore::callFunction):
(WebCore::ReadableJSStream::Source::start):
* bindings/js/ScheduledAction.cpp:
(WebCore::ScheduledAction::executeFunctionInContext):
* bindings/js/ScriptController.cpp:
(WebCore::ScriptController::evaluateInWorld):
* bindings/js/SerializedScriptValue.cpp:
(WebCore::SerializedScriptValue::create):
(WebCore::SerializedScriptValue::deserialize):
* bindings/js/WorkerScriptController.cpp:
(WebCore::WorkerScriptController::evaluate):
(WebCore::WorkerScriptController::setException):
(WebCore::WorkerScriptController::scheduleExecutionTermination):
* bindings/js/WorkerScriptController.h:
(WebCore::WorkerScriptController::workerGlobalScopeWrapper):
* bindings/js/WorkerScriptDebugServer.cpp:
(WebCore::WorkerScriptDebugServer::runEventLoopWhilePaused):
(WebCore::WorkerScriptDebugServer::reportException):
* bindings/js/WorkerScriptDebugServer.h:
* bindings/objc/WebScriptObject.mm:
(WebCore::createJSWrapper):
(WebCore::addExceptionToConsole):
(-[WebScriptObject callWebScriptMethod:withArguments:]):
(-[WebScriptObject evaluateWebScript:]):
- Changed to call a version of JSMainThreadExecState::evaluate() that provides
  a stub returnedException because evaluateWebScript: doesn't need the exception.

* inspector/PageScriptDebugServer.cpp:
(WebCore::PageScriptDebugServer::isContentScript):
(WebCore::PageScriptDebugServer::reportException):
* inspector/PageScriptDebugServer.h:
* workers/WorkerGlobalScope.cpp:
(WebCore::WorkerGlobalScope::importScripts):

Source/WebKit/mac:

* WebView/WebView.mm:
(+[WebView _reportException:inContext:]):
(WebKitInitializeApplicationCachePathIfNecessary):
- Changed to use the new Exception object.

Source/WebKit/win:

* WebView.cpp:
(WebView::reportException):
- Changed to use the new Exception object.

Source/WebKit2:

* WebProcess/InjectedBundle/InjectedBundle.cpp:
(WebKit::InjectedBundle::reportException):
- Changed to use the new Exception object.

LayoutTests:

* TestExpectations:
- Skip the new tests until webkit.org/b/145090 is fixed.

* fast/dom/regress-131530-expected.txt:
- Rebased results because we now have a proper line number.

* http/tests/inspector/inspector-test.js:
(InspectorTestProxy.clearResults):
(InspectorTestProxy.reportUncaughtException):
- Add the feature to sanitize the url reported by reportUncaughtException() since
  we can have tests that do expect uncaught exceptions, and we need the test
  results to be invariant.  Sanitization of the url, in this case means, stripping
  off the preceding path.

* inspector/debugger/break-on-exception-expected.txt: Added.
* inspector/debugger/break-on-exception.html: Added.
* inspector/debugger/break-on-exception-catch-expected.txt: Added.
* inspector/debugger/break-on-exception-catch.html: Added.
* inspector/debugger/break-on-exception-finally-expected.txt: Added.
* inspector/debugger/break-on-exception-finally.html: Added.
* inspector/debugger/break-on-exception-native-expected.txt: Added.
* inspector/debugger/break-on-exception-native.html: Added.

* inspector/debugger/break-on-exception-throw-in-promise-expected.txt: Added.
* inspector/debugger/break-on-exception-throw-in-promise.html: Added.
* inspector/debugger/break-on-exception-throw-in-promise-with-catch-expected.txt: Added.
* inspector/debugger/break-on-exception-throw-in-promise-with-catch.html: Added.
* inspector/debugger/break-on-exception-throw-in-promise-then-expected.txt: Added.
* inspector/debugger/break-on-exception-throw-in-promise-then.html: Added.
* inspector/debugger/break-on-exception-throw-in-promise-then-with-catch-expected.txt: Added.
* inspector/debugger/break-on-exception-throw-in-promise-then-with-catch.html: Added.
* inspector/debugger/break-on-exception-throw-in-promise-rethrow-in-catch-expected.txt: Added.
* inspector/debugger/break-on-exception-throw-in-promise-rethrow-in-catch.html: Added.

* inspector/debugger/break-on-exception-window-onerror-expected.txt: Added.
* inspector/debugger/break-on-exception-window-onerror.html: Added.

* inspector/debugger/break-on-uncaught-exception-expected.txt: Added.
* inspector/debugger/break-on-uncaught-exception.html: Added.
* inspector/debugger/break-on-uncaught-exception-catch-expected.txt: Added.
* inspector/debugger/break-on-uncaught-exception-catch.html: Added.
* inspector/debugger/break-on-uncaught-exception-finally-expected.txt: Added.
* inspector/debugger/break-on-uncaught-exception-finally.html: Added.
* inspector/debugger/break-on-uncaught-exception-native-expected.txt: Added.
* inspector/debugger/break-on-uncaught-exception-native.html: Added.

* inspector/debugger/break-on-uncaught-exception-throw-in-promise-expected.txt: Added.
* inspector/debugger/break-on-uncaught-exception-throw-in-promise.html: Added.
* inspector/debugger/break-on-uncaught-exception-throw-in-promise-with-catch-expected.txt: Added.
* inspector/debugger/break-on-uncaught-exception-throw-in-promise-with-catch.html: Added.
* inspector/debugger/break-on-uncaught-exception-throw-in-promise-then-expected.txt: Added.
* inspector/debugger/break-on-uncaught-exception-throw-in-promise-then.html: Added.
* inspector/debugger/break-on-uncaught-exception-throw-in-promise-then-with-catch-expected.txt: Added.
* inspector/debugger/break-on-uncaught-exception-throw-in-promise-then-with-catch.html: Added.
* inspector/debugger/break-on-uncaught-exception-throw-in-promise-rethrow-in-catch-expected.txt: Added.
* inspector/debugger/break-on-uncaught-exception-throw-in-promise-rethrow-in-catch.html: Added.

* inspector/debugger/break-on-uncaught-exception-window-onerror-expected.txt: Added.
* inspector/debugger/break-on-uncaught-exception-window-onerror.html: Added.

* inspector/debugger/resources/break-on-exception-tests.js: Added.
(doThrow):
(testCatch):
(testFinally):
(testThrowingThruNativeCode):
(testThrowingInPromise):
(testThrowingInPromiseWithCatch):
(testThrowingInPromiseThen):
(testThrowingInPromiseThenWithCatch):
(testThrowingInPromiseWithRethrowInCatch):

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

145 files changed:
LayoutTests/ChangeLog
LayoutTests/TestExpectations
LayoutTests/fast/dom/regress-131530-expected.txt
LayoutTests/http/tests/inspector/inspector-test.js
LayoutTests/inspector/debugger/break-on-exception-catch-expected.txt [new file with mode: 0644]
LayoutTests/inspector/debugger/break-on-exception-catch.html [new file with mode: 0644]
LayoutTests/inspector/debugger/break-on-exception-expected.txt [new file with mode: 0644]
LayoutTests/inspector/debugger/break-on-exception-finally-expected.txt [new file with mode: 0644]
LayoutTests/inspector/debugger/break-on-exception-finally.html [new file with mode: 0644]
LayoutTests/inspector/debugger/break-on-exception-native-expected.txt [new file with mode: 0644]
LayoutTests/inspector/debugger/break-on-exception-native.html [new file with mode: 0644]
LayoutTests/inspector/debugger/break-on-exception-throw-in-promise-expected.txt [new file with mode: 0644]
LayoutTests/inspector/debugger/break-on-exception-throw-in-promise-rethrow-in-catch-expected.txt [new file with mode: 0644]
LayoutTests/inspector/debugger/break-on-exception-throw-in-promise-rethrow-in-catch.html [new file with mode: 0644]
LayoutTests/inspector/debugger/break-on-exception-throw-in-promise-then-expected.txt [new file with mode: 0644]
LayoutTests/inspector/debugger/break-on-exception-throw-in-promise-then-with-catch-expected.txt [new file with mode: 0644]
LayoutTests/inspector/debugger/break-on-exception-throw-in-promise-then-with-catch.html [new file with mode: 0644]
LayoutTests/inspector/debugger/break-on-exception-throw-in-promise-then.html [new file with mode: 0644]
LayoutTests/inspector/debugger/break-on-exception-throw-in-promise-with-catch-expected.txt [new file with mode: 0644]
LayoutTests/inspector/debugger/break-on-exception-throw-in-promise-with-catch.html [new file with mode: 0644]
LayoutTests/inspector/debugger/break-on-exception-throw-in-promise.html [new file with mode: 0644]
LayoutTests/inspector/debugger/break-on-exception-window-onerror-expected.txt [new file with mode: 0644]
LayoutTests/inspector/debugger/break-on-exception-window-onerror.html [new file with mode: 0644]
LayoutTests/inspector/debugger/break-on-exception.html [new file with mode: 0644]
LayoutTests/inspector/debugger/break-on-uncaught-exception-catch-expected.txt [new file with mode: 0644]
LayoutTests/inspector/debugger/break-on-uncaught-exception-catch.html [new file with mode: 0644]
LayoutTests/inspector/debugger/break-on-uncaught-exception-expected.txt [new file with mode: 0644]
LayoutTests/inspector/debugger/break-on-uncaught-exception-finally-expected.txt [new file with mode: 0644]
LayoutTests/inspector/debugger/break-on-uncaught-exception-finally.html [new file with mode: 0644]
LayoutTests/inspector/debugger/break-on-uncaught-exception-native-expected.txt [new file with mode: 0644]
LayoutTests/inspector/debugger/break-on-uncaught-exception-native.html [new file with mode: 0644]
LayoutTests/inspector/debugger/break-on-uncaught-exception-throw-in-promise-expected.txt [new file with mode: 0644]
LayoutTests/inspector/debugger/break-on-uncaught-exception-throw-in-promise-rethrow-in-catch-expected.txt [new file with mode: 0644]
LayoutTests/inspector/debugger/break-on-uncaught-exception-throw-in-promise-rethrow-in-catch.html [new file with mode: 0644]
LayoutTests/inspector/debugger/break-on-uncaught-exception-throw-in-promise-then-expected.txt [new file with mode: 0644]
LayoutTests/inspector/debugger/break-on-uncaught-exception-throw-in-promise-then-with-catch-expected.txt [new file with mode: 0644]
LayoutTests/inspector/debugger/break-on-uncaught-exception-throw-in-promise-then-with-catch.html [new file with mode: 0644]
LayoutTests/inspector/debugger/break-on-uncaught-exception-throw-in-promise-then.html [new file with mode: 0644]
LayoutTests/inspector/debugger/break-on-uncaught-exception-throw-in-promise-with-catch-expected.txt [new file with mode: 0644]
LayoutTests/inspector/debugger/break-on-uncaught-exception-throw-in-promise-with-catch.html [new file with mode: 0644]
LayoutTests/inspector/debugger/break-on-uncaught-exception-throw-in-promise.html [new file with mode: 0644]
LayoutTests/inspector/debugger/break-on-uncaught-exception-window-onerror-expected.txt [new file with mode: 0644]
LayoutTests/inspector/debugger/break-on-uncaught-exception-window-onerror.html [new file with mode: 0644]
LayoutTests/inspector/debugger/break-on-uncaught-exception.html [new file with mode: 0644]
LayoutTests/inspector/debugger/resources/break-on-exception-tests.js [new file with mode: 0644]
Source/JavaScriptCore/API/JSBase.cpp
Source/JavaScriptCore/API/JSObjectRef.cpp
Source/JavaScriptCore/API/JSScriptRef.cpp
Source/JavaScriptCore/API/JSValue.mm
Source/JavaScriptCore/API/JSValueRef.cpp
Source/JavaScriptCore/CMakeLists.txt
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/JavaScriptCore.vcxproj/JavaScriptCore.vcxproj
Source/JavaScriptCore/JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters
Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj
Source/JavaScriptCore/bindings/ScriptFunctionCall.cpp
Source/JavaScriptCore/bindings/ScriptFunctionCall.h
Source/JavaScriptCore/bytecode/BytecodeList.json
Source/JavaScriptCore/bytecode/BytecodeUseDef.h
Source/JavaScriptCore/bytecode/CodeBlock.cpp
Source/JavaScriptCore/bytecode/CodeBlock.h
Source/JavaScriptCore/bytecode/HandlerInfo.h
Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp
Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h
Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp
Source/JavaScriptCore/debugger/Debugger.cpp
Source/JavaScriptCore/debugger/Debugger.h
Source/JavaScriptCore/debugger/DebuggerCallFrame.cpp
Source/JavaScriptCore/debugger/DebuggerCallFrame.h
Source/JavaScriptCore/inspector/InjectedScriptManager.cpp
Source/JavaScriptCore/inspector/InspectorEnvironment.h
Source/JavaScriptCore/inspector/JSGlobalObjectInspectorController.cpp
Source/JavaScriptCore/inspector/JSGlobalObjectInspectorController.h
Source/JavaScriptCore/inspector/JSGlobalObjectScriptDebugServer.h
Source/JavaScriptCore/inspector/JSJavaScriptCallFrame.cpp
Source/JavaScriptCore/inspector/JavaScriptCallFrame.h
Source/JavaScriptCore/inspector/ScriptCallStackFactory.cpp
Source/JavaScriptCore/inspector/ScriptCallStackFactory.h
Source/JavaScriptCore/inspector/ScriptDebugServer.cpp
Source/JavaScriptCore/inspector/ScriptDebugServer.h
Source/JavaScriptCore/interpreter/CallFrame.h
Source/JavaScriptCore/interpreter/Interpreter.cpp
Source/JavaScriptCore/interpreter/Interpreter.h
Source/JavaScriptCore/jit/AssemblyHelpers.cpp
Source/JavaScriptCore/jit/JITExceptions.cpp
Source/JavaScriptCore/jit/JITExceptions.h
Source/JavaScriptCore/jit/JITOpcodes.cpp
Source/JavaScriptCore/jit/JITOpcodes32_64.cpp
Source/JavaScriptCore/jit/JITOperations.cpp
Source/JavaScriptCore/jit/ThunkGenerators.cpp
Source/JavaScriptCore/jsc.cpp
Source/JavaScriptCore/llint/LLIntOffsetsExtractor.cpp
Source/JavaScriptCore/llint/LLIntSlowPaths.cpp
Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm
Source/JavaScriptCore/llint/LowLevelInterpreter64.asm
Source/JavaScriptCore/parser/NodeConstructors.h
Source/JavaScriptCore/parser/Nodes.h
Source/JavaScriptCore/runtime/CallData.cpp
Source/JavaScriptCore/runtime/CallData.h
Source/JavaScriptCore/runtime/Completion.cpp
Source/JavaScriptCore/runtime/Completion.h
Source/JavaScriptCore/runtime/Error.h
Source/JavaScriptCore/runtime/Exception.cpp [new file with mode: 0644]
Source/JavaScriptCore/runtime/Exception.h [new file with mode: 0644]
Source/JavaScriptCore/runtime/ExceptionHelpers.cpp
Source/JavaScriptCore/runtime/ExceptionHelpers.h
Source/JavaScriptCore/runtime/GetterSetter.cpp
Source/JavaScriptCore/runtime/IteratorOperations.cpp
Source/JavaScriptCore/runtime/JSObject.cpp
Source/JavaScriptCore/runtime/JSPromiseConstructor.cpp
Source/JavaScriptCore/runtime/JSPromiseDeferred.cpp
Source/JavaScriptCore/runtime/JSPromiseReaction.cpp
Source/JavaScriptCore/runtime/VM.cpp
Source/JavaScriptCore/runtime/VM.h
Source/JavaScriptCore/runtime/VMEntryScope.cpp
Source/WebCore/ChangeLog
Source/WebCore/ForwardingHeaders/runtime/Exception.h [new file with mode: 0644]
Source/WebCore/bindings/js/JSCallbackData.cpp
Source/WebCore/bindings/js/JSCustomXPathNSResolver.cpp
Source/WebCore/bindings/js/JSDOMBinding.cpp
Source/WebCore/bindings/js/JSDOMBinding.h
Source/WebCore/bindings/js/JSErrorHandler.cpp
Source/WebCore/bindings/js/JSEventListener.cpp
Source/WebCore/bindings/js/JSMainThreadExecState.cpp
Source/WebCore/bindings/js/JSMainThreadExecState.h
Source/WebCore/bindings/js/JSMediaDevicesCustom.cpp
Source/WebCore/bindings/js/JSMutationCallback.cpp
Source/WebCore/bindings/js/ReadableJSStream.cpp
Source/WebCore/bindings/js/ScheduledAction.cpp
Source/WebCore/bindings/js/ScriptController.cpp
Source/WebCore/bindings/js/SerializedScriptValue.cpp
Source/WebCore/bindings/js/WorkerScriptController.cpp
Source/WebCore/bindings/js/WorkerScriptController.h
Source/WebCore/bindings/js/WorkerScriptDebugServer.cpp
Source/WebCore/bindings/js/WorkerScriptDebugServer.h
Source/WebCore/bindings/objc/WebScriptObject.mm
Source/WebCore/inspector/PageScriptDebugServer.cpp
Source/WebCore/inspector/PageScriptDebugServer.h
Source/WebCore/workers/WorkerGlobalScope.cpp
Source/WebKit/mac/ChangeLog
Source/WebKit/mac/WebView/WebView.mm
Source/WebKit/win/ChangeLog
Source/WebKit/win/WebView.cpp
Source/WebKit2/ChangeLog
Source/WebKit2/WebProcess/InjectedBundle/InjectedBundle.cpp

index b8c2cae..f900a2d 100644 (file)
@@ -1,3 +1,81 @@
+2015-06-05  Mark Lam  <mark.lam@apple.com>
+
+        finally blocks should not set the exception stack trace when re-throwing the exception.
+        https://bugs.webkit.org/show_bug.cgi?id=145525
+
+        Reviewed by Geoffrey Garen.
+
+        * TestExpectations:
+        - Skip the new tests until webkit.org/b/145090 is fixed.
+
+        * fast/dom/regress-131530-expected.txt:
+        - Rebased results because we now have a proper line number.
+
+        * http/tests/inspector/inspector-test.js:
+        (InspectorTestProxy.clearResults):
+        (InspectorTestProxy.reportUncaughtException):
+        - Add the feature to sanitize the url reported by reportUncaughtException() since
+          we can have tests that do expect uncaught exceptions, and we need the test
+          results to be invariant.  Sanitization of the url, in this case means, stripping
+          off the preceding path.
+
+        * inspector/debugger/break-on-exception-expected.txt: Added.
+        * inspector/debugger/break-on-exception.html: Added.
+        * inspector/debugger/break-on-exception-catch-expected.txt: Added.
+        * inspector/debugger/break-on-exception-catch.html: Added.
+        * inspector/debugger/break-on-exception-finally-expected.txt: Added.
+        * inspector/debugger/break-on-exception-finally.html: Added.
+        * inspector/debugger/break-on-exception-native-expected.txt: Added.
+        * inspector/debugger/break-on-exception-native.html: Added.
+
+        * inspector/debugger/break-on-exception-throw-in-promise-expected.txt: Added.
+        * inspector/debugger/break-on-exception-throw-in-promise.html: Added.
+        * inspector/debugger/break-on-exception-throw-in-promise-with-catch-expected.txt: Added.
+        * inspector/debugger/break-on-exception-throw-in-promise-with-catch.html: Added.
+        * inspector/debugger/break-on-exception-throw-in-promise-then-expected.txt: Added.
+        * inspector/debugger/break-on-exception-throw-in-promise-then.html: Added.
+        * inspector/debugger/break-on-exception-throw-in-promise-then-with-catch-expected.txt: Added.
+        * inspector/debugger/break-on-exception-throw-in-promise-then-with-catch.html: Added.
+        * inspector/debugger/break-on-exception-throw-in-promise-rethrow-in-catch-expected.txt: Added.
+        * inspector/debugger/break-on-exception-throw-in-promise-rethrow-in-catch.html: Added.
+
+        * inspector/debugger/break-on-exception-window-onerror-expected.txt: Added.
+        * inspector/debugger/break-on-exception-window-onerror.html: Added.
+
+        * inspector/debugger/break-on-uncaught-exception-expected.txt: Added.
+        * inspector/debugger/break-on-uncaught-exception.html: Added.
+        * inspector/debugger/break-on-uncaught-exception-catch-expected.txt: Added.
+        * inspector/debugger/break-on-uncaught-exception-catch.html: Added.
+        * inspector/debugger/break-on-uncaught-exception-finally-expected.txt: Added.
+        * inspector/debugger/break-on-uncaught-exception-finally.html: Added.
+        * inspector/debugger/break-on-uncaught-exception-native-expected.txt: Added.
+        * inspector/debugger/break-on-uncaught-exception-native.html: Added.
+
+        * inspector/debugger/break-on-uncaught-exception-throw-in-promise-expected.txt: Added.
+        * inspector/debugger/break-on-uncaught-exception-throw-in-promise.html: Added.
+        * inspector/debugger/break-on-uncaught-exception-throw-in-promise-with-catch-expected.txt: Added.
+        * inspector/debugger/break-on-uncaught-exception-throw-in-promise-with-catch.html: Added.
+        * inspector/debugger/break-on-uncaught-exception-throw-in-promise-then-expected.txt: Added.
+        * inspector/debugger/break-on-uncaught-exception-throw-in-promise-then.html: Added.
+        * inspector/debugger/break-on-uncaught-exception-throw-in-promise-then-with-catch-expected.txt: Added.
+        * inspector/debugger/break-on-uncaught-exception-throw-in-promise-then-with-catch.html: Added.
+        * inspector/debugger/break-on-uncaught-exception-throw-in-promise-rethrow-in-catch-expected.txt: Added.
+        * inspector/debugger/break-on-uncaught-exception-throw-in-promise-rethrow-in-catch.html: Added.
+
+        * inspector/debugger/break-on-uncaught-exception-window-onerror-expected.txt: Added.
+        * inspector/debugger/break-on-uncaught-exception-window-onerror.html: Added.
+
+        * inspector/debugger/resources/break-on-exception-tests.js: Added.
+        (doThrow):
+        (testCatch):
+        (testFinally):
+        (testThrowingThruNativeCode):
+        (testThrowingInPromise):
+        (testThrowingInPromiseWithCatch):
+        (testThrowingInPromiseThen):
+        (testThrowingInPromiseThenWithCatch):
+        (testThrowingInPromiseWithRethrowInCatch):
+
 2015-06-05  Eric Carlson  <eric.carlson@apple.com>
 
         Layout tests fullscreen/video-controls-drag.html and media/video-fullscreeen-only-controls.html
index fc68001..99851d2 100644 (file)
@@ -525,3 +525,25 @@ webkit.org/b/144540 fast/frames/flattening/crash-remove-iframe-during-object-bef
 webkit.org/b/145007 js/regress-141098.html [ Skip ]
 
 webkit.org/b/145390 storage/indexeddb/deleteIndex-bug110792.html [ Pass Failure ]
+
+webkit.org/b/145090 inspector/debugger/break-on-exception.html [ Skip ]
+webkit.org/b/145090 inspector/debugger/break-on-exception-catch.html [ Skip ]
+webkit.org/b/145090 inspector/debugger/break-on-exception-finally.html [ Skip ]
+webkit.org/b/145090 inspector/debugger/break-on-exception-native.html [ Skip ]
+webkit.org/b/145090 inspector/debugger/break-on-exception-throw-in-promise.html [ Skip ]
+webkit.org/b/145090 inspector/debugger/break-on-exception-throw-in-promise-with-catch.html [ Skip ]
+webkit.org/b/145090 inspector/debugger/break-on-exception-throw-in-promise-then.html [ Skip ]
+webkit.org/b/145090 inspector/debugger/break-on-exception-throw-in-promise-then-with-catch.html [ Skip ]
+webkit.org/b/145090 inspector/debugger/break-on-exception-throw-in-promise-rethrow-in-catch.html [ Skip ]
+webkit.org/b/145090 inspector/debugger/break-on-exception-window-onerror.html [ Skip ]
+webkit.org/b/145090 inspector/debugger/break-on-uncaught-exception.html [ Skip ]
+webkit.org/b/145090 inspector/debugger/break-on-uncaught-exception-catch.html [ Skip ]
+webkit.org/b/145090 inspector/debugger/break-on-uncaught-exception-finally.html [ Skip ]
+webkit.org/b/145090 inspector/debugger/break-on-uncaught-exception-native.html [ Skip ]
+webkit.org/b/145090 inspector/debugger/break-on-uncaught-exception-throw-in-promise.html [ Skip ]
+webkit.org/b/145090 inspector/debugger/break-on-uncaught-exception-throw-in-promise-with-catch.html [ Skip ]
+webkit.org/b/145090 inspector/debugger/break-on-uncaught-exception-throw-in-promise-then.html [ Skip ]
+webkit.org/b/145090 inspector/debugger/break-on-uncaught-exception-throw-in-promise-then-with-catch.html [ Skip ]
+webkit.org/b/145090 inspector/debugger/break-on-uncaught-exception-throw-in-promise-rethrow-in-catch.html [ Skip ]
+webkit.org/b/145090 inspector/debugger/break-on-uncaught-exception-window-onerror.html [ Skip ]
+
index 81e8556..a886d2b 100644 (file)
@@ -1,5 +1,5 @@
 CONSOLE MESSAGE: line 5: Exception to trigger unwinding in MutationObserver
-CONSOLE MESSAGE: Pending exception before MutationObservers are called.
+CONSOLE MESSAGE: line 22: Pending exception before MutationObservers are called.
 Regression test for https://webkit.org/b/131530. This test should not crash.
 
 Mutate that node
index 6c299eb..be0534f 100644 (file)
@@ -143,8 +143,20 @@ InspectorTestProxy.clearResults = function()
     }
 }
 
+InspectorTestProxy.needToSanitizeUncaughtExceptionURLs = false;
+
 InspectorTestProxy.reportUncaughtException = function(message, url, lineNumber)
 {
+    if (InspectorTestProxy.needToSanitizeUncaughtExceptionURLs) {
+        if (typeof url == "string") {
+            var lastSlash = url.lastIndexOf("/");
+            var lastBackSlash = url.lastIndexOf("\\");
+            var lastPathSeparator = Math.max(lastSlash, lastBackSlash);
+            if (lastPathSeparator > 0)
+                url = url.substr(lastPathSeparator + 1);
+        }
+    }
+
     var result = "Uncaught exception in test page: " + message + " [" + url + ":" + lineNumber + "]";
     InspectorTestProxy.addResult(result);
     InspectorTestProxy.completeTest();
diff --git a/LayoutTests/inspector/debugger/break-on-exception-catch-expected.txt b/LayoutTests/inspector/debugger/break-on-exception-catch-expected.txt
new file mode 100644 (file)
index 0000000..3a81e30
--- /dev/null
@@ -0,0 +1,8 @@
+CONSOLE MESSAGE: line 12: testCatch
+CONSOLE MESSAGE: line 7: throwing TestError
+CONSOLE MESSAGE: line 16: catch TestError
+CONSOLE MESSAGE: line 18: DONE
+Checking pause locations when pausing on all exceptions.
+
+PAUSE #1 AT: doThrow:8:22
+
diff --git a/LayoutTests/inspector/debugger/break-on-exception-catch.html b/LayoutTests/inspector/debugger/break-on-exception-catch.html
new file mode 100644 (file)
index 0000000..6883aea
--- /dev/null
@@ -0,0 +1,72 @@
+<!doctype html>
+<html>
+<head>
+<script type="text/javascript" src="../../http/tests/inspector/inspector-test.js"></script>
+<script type="text/javascript" src="./resources/break-on-exception-tests.js"></script>
+<script>
+function test() {
+    function doExceptionTest(testName, exceptionBreakType, resumeAction)
+    {
+        var pauses = 0;
+        var index = 0;
+
+        function runTestCase(test) {
+            InspectorTest.evaluateInPage("setTimeout(" + test + ", 50)");
+        }
+
+        WebInspector.debuggerManager.addEventListener(WebInspector.DebuggerManager.Event.ScriptAdded, function(event) {
+            var scriptObject = event.data.script;
+            if (!/break-on-exception-tests\.js$/.test(scriptObject.url))
+                return;
+
+            if (exceptionBreakType == 'AllExceptions')
+                WebInspector.debuggerManager.allExceptionsBreakpoint.disabled = false;
+            else
+                WebInspector.debuggerManager.allUncaughtExceptionsBreakpoint.disabled = false;
+
+            runTestCase(testName);
+        });
+
+        WebInspector.debuggerManager.addEventListener(WebInspector.DebuggerManager.Event.CallFramesDidChange, function(event) {
+            var callFrame = WebInspector.debuggerManager.activeCallFrame;
+            if (callFrame) {
+                // Pausing.
+                InspectorTest.assert(WebInspector.debuggerManager.pauseReason == "exception");
+
+                var funcName = callFrame.functionName || "<anonymous>";
+                var location = callFrame.sourceCodeLocation;
+                var line = location.lineNumber + 1;
+                var column = location.columnNumber + 1;
+
+                InspectorTest.log("PAUSE #" + (++pauses) + " AT: " + funcName + ":" + line + ":" + column);
+                WebInspector.debuggerManager.resume();
+
+            } else {
+                // Resuming.
+                if (resumeAction == 'FinishOnResume')
+                    InspectorTest.completeTest();
+            }
+        });
+
+        // This is a signal mechanism for the web process to tell us that the test is done.
+        // The web process fires the signal by doing console.log("DONE").
+        WebInspector.logManager.addEventListener(WebInspector.LogManager.Event.MessageAdded, function(event) {
+            var message = event.data.message;
+            if (!message.parameters || message.parameters.length !== 1)
+                return;
+            if (message.parameters[0].type !== "string" || message.parameters[0].description !== "DONE")
+                return;
+            InspectorTest.completeTest();
+        });
+
+        InspectorTest.reloadPage();
+    }
+
+    doExceptionTest('testCatch', 'AllExceptions', 'IgnoreResume');
+}
+</script>
+</head>
+<body onload="runTest()">
+    <p>Checking pause locations when pausing on all exceptions.</p>
+</body>
+</html>
diff --git a/LayoutTests/inspector/debugger/break-on-exception-expected.txt b/LayoutTests/inspector/debugger/break-on-exception-expected.txt
new file mode 100644 (file)
index 0000000..a843f7c
--- /dev/null
@@ -0,0 +1,7 @@
+CONSOLE MESSAGE: line 7: throwing TestError
+CONSOLE MESSAGE: line 8: TestError
+Checking pause locations when pausing on all exceptions.
+
+PAUSE #1 AT: doThrow:8:22
+Uncaught exception in test page: TestError [break-on-exception-tests.js:8]
+
diff --git a/LayoutTests/inspector/debugger/break-on-exception-finally-expected.txt b/LayoutTests/inspector/debugger/break-on-exception-finally-expected.txt
new file mode 100644 (file)
index 0000000..b1bbdfd
--- /dev/null
@@ -0,0 +1,9 @@
+CONSOLE MESSAGE: line 22: testFinally
+CONSOLE MESSAGE: line 7: throwing TestError
+CONSOLE MESSAGE: line 26: finally
+CONSOLE MESSAGE: line 8: TestError
+Checking pause locations when pausing on all exceptions.
+
+PAUSE #1 AT: doThrow:8:22
+Uncaught exception in test page: TestError [break-on-exception-tests.js:8]
+
diff --git a/LayoutTests/inspector/debugger/break-on-exception-finally.html b/LayoutTests/inspector/debugger/break-on-exception-finally.html
new file mode 100644 (file)
index 0000000..a735fd9
--- /dev/null
@@ -0,0 +1,72 @@
+<!doctype html>
+<html>
+<head>
+<script type="text/javascript" src="../../http/tests/inspector/inspector-test.js"></script>
+<script type="text/javascript" src="./resources/break-on-exception-tests.js"></script>
+<script>
+function test() {
+    function doExceptionTest(testName, exceptionBreakType, resumeAction)
+    {
+        var pauses = 0;
+        var index = 0;
+
+        function runTestCase(test) {
+            InspectorTest.evaluateInPage("setTimeout(" + test + ", 50)");
+        }
+
+        WebInspector.debuggerManager.addEventListener(WebInspector.DebuggerManager.Event.ScriptAdded, function(event) {
+            var scriptObject = event.data.script;
+            if (!/break-on-exception-tests\.js$/.test(scriptObject.url))
+                return;
+
+            if (exceptionBreakType == 'AllExceptions')
+                WebInspector.debuggerManager.allExceptionsBreakpoint.disabled = false;
+            else
+                WebInspector.debuggerManager.allUncaughtExceptionsBreakpoint.disabled = false;
+
+            runTestCase(testName);
+        });
+
+        WebInspector.debuggerManager.addEventListener(WebInspector.DebuggerManager.Event.CallFramesDidChange, function(event) {
+            var callFrame = WebInspector.debuggerManager.activeCallFrame;
+            if (callFrame) {
+                // Pausing.
+                InspectorTest.assert(WebInspector.debuggerManager.pauseReason == "exception");
+
+                var funcName = callFrame.functionName || "<anonymous>";
+                var location = callFrame.sourceCodeLocation;
+                var line = location.lineNumber + 1;
+                var column = location.columnNumber + 1;
+
+                InspectorTest.log("PAUSE #" + (++pauses) + " AT: " + funcName + ":" + line + ":" + column);
+                WebInspector.debuggerManager.resume();
+
+            } else {
+                // Resuming.
+                if (resumeAction == 'FinishOnResume')
+                    InspectorTest.completeTest();
+            }
+        });
+
+        // This is a signal mechanism for the web process to tell us that the test is done.
+        // The web process fires the signal by doing console.log("DONE").
+        WebInspector.logManager.addEventListener(WebInspector.LogManager.Event.MessageAdded, function(event) {
+            var message = event.data.message;
+            if (!message.parameters || message.parameters.length !== 1)
+                return;
+            if (message.parameters[0].type !== "string" || message.parameters[0].description !== "DONE")
+                return;
+            InspectorTest.completeTest();
+        });
+
+        InspectorTest.reloadPage();
+    }
+
+    doExceptionTest('testFinally', 'AllExceptions', 'IgnoreResume');
+}
+</script>
+</head>
+<body onload="runTest()">
+    <p>Checking pause locations when pausing on all exceptions.</p>
+</body>
+</html>
diff --git a/LayoutTests/inspector/debugger/break-on-exception-native-expected.txt b/LayoutTests/inspector/debugger/break-on-exception-native-expected.txt
new file mode 100644 (file)
index 0000000..6c58e50
--- /dev/null
@@ -0,0 +1,8 @@
+CONSOLE MESSAGE: line 31: testThrowingThruNativeCode
+CONSOLE MESSAGE: line 7: throwing TestError
+CONSOLE MESSAGE: line 8: TestError
+Checking pause locations when pausing on all exceptions.
+
+PAUSE #1 AT: doThrow:8:22
+Uncaught exception in test page: TestError [break-on-exception-tests.js:8]
+
diff --git a/LayoutTests/inspector/debugger/break-on-exception-native.html b/LayoutTests/inspector/debugger/break-on-exception-native.html
new file mode 100644 (file)
index 0000000..c5e305d
--- /dev/null
@@ -0,0 +1,72 @@
+<!doctype html>
+<html>
+<head>
+<script type="text/javascript" src="../../http/tests/inspector/inspector-test.js"></script>
+<script type="text/javascript" src="./resources/break-on-exception-tests.js"></script>
+<script>
+function test() {
+    function doExceptionTest(testName, exceptionBreakType, resumeAction)
+    {
+        var pauses = 0;
+        var index = 0;
+
+        function runTestCase(test) {
+            InspectorTest.evaluateInPage("setTimeout(" + test + ", 50)");
+        }
+
+        WebInspector.debuggerManager.addEventListener(WebInspector.DebuggerManager.Event.ScriptAdded, function(event) {
+            var scriptObject = event.data.script;
+            if (!/break-on-exception-tests\.js$/.test(scriptObject.url))
+                return;
+
+            if (exceptionBreakType == 'AllExceptions')
+                WebInspector.debuggerManager.allExceptionsBreakpoint.disabled = false;
+            else
+                WebInspector.debuggerManager.allUncaughtExceptionsBreakpoint.disabled = false;
+
+            runTestCase(testName);
+        });
+
+        WebInspector.debuggerManager.addEventListener(WebInspector.DebuggerManager.Event.CallFramesDidChange, function(event) {
+            var callFrame = WebInspector.debuggerManager.activeCallFrame;
+            if (callFrame) {
+                // Pausing.
+                InspectorTest.assert(WebInspector.debuggerManager.pauseReason == "exception");
+
+                var funcName = callFrame.functionName || "<anonymous>";
+                var location = callFrame.sourceCodeLocation;
+                var line = location.lineNumber + 1;
+                var column = location.columnNumber + 1;
+
+                InspectorTest.log("PAUSE #" + (++pauses) + " AT: " + funcName + ":" + line + ":" + column);
+                WebInspector.debuggerManager.resume();
+
+            } else {
+                // Resuming.
+                if (resumeAction == 'FinishOnResume')
+                    InspectorTest.completeTest();
+            }
+        });
+
+        // This is a signal mechanism for the web process to tell us that the test is done.
+        // The web process fires the signal by doing console.log("DONE").
+        WebInspector.logManager.addEventListener(WebInspector.LogManager.Event.MessageAdded, function(event) {
+            var message = event.data.message;
+            if (!message.parameters || message.parameters.length !== 1)
+                return;
+            if (message.parameters[0].type !== "string" || message.parameters[0].description !== "DONE")
+                return;
+            InspectorTest.completeTest();
+        });
+
+        InspectorTest.reloadPage();
+    }
+
+    doExceptionTest('testThrowingThruNativeCode', 'AllExceptions', 'IgnoreResume');
+}
+</script>
+</head>
+<body onload="runTest()">
+    <p>Checking pause locations when pausing on all exceptions.</p>
+</body>
+</html>
diff --git a/LayoutTests/inspector/debugger/break-on-exception-throw-in-promise-expected.txt b/LayoutTests/inspector/debugger/break-on-exception-throw-in-promise-expected.txt
new file mode 100644 (file)
index 0000000..4a00a7a
--- /dev/null
@@ -0,0 +1,7 @@
+CONSOLE MESSAGE: line 36: testThrowingInPromise
+CONSOLE MESSAGE: line 38: in promise
+CONSOLE MESSAGE: line 7: throwing TestError
+Checking pause locations when pausing on all exceptions.
+
+PAUSE #1 AT: doThrow:8:22
+
diff --git a/LayoutTests/inspector/debugger/break-on-exception-throw-in-promise-rethrow-in-catch-expected.txt b/LayoutTests/inspector/debugger/break-on-exception-throw-in-promise-rethrow-in-catch-expected.txt
new file mode 100644 (file)
index 0000000..4b8afc8
--- /dev/null
@@ -0,0 +1,9 @@
+CONSOLE MESSAGE: line 80: testThrowingInPromiseWithRethrowInCatch
+CONSOLE MESSAGE: line 82: in promise
+CONSOLE MESSAGE: line 7: throwing TestError
+CONSOLE MESSAGE: line 85: in promise.catch
+Checking pause locations when pausing on all exceptions.
+
+PAUSE #1 AT: doThrow:8:22
+PAUSE #2 AT: promiseCatch:86:16
+
diff --git a/LayoutTests/inspector/debugger/break-on-exception-throw-in-promise-rethrow-in-catch.html b/LayoutTests/inspector/debugger/break-on-exception-throw-in-promise-rethrow-in-catch.html
new file mode 100644 (file)
index 0000000..a49f022
--- /dev/null
@@ -0,0 +1,72 @@
+<!doctype html>
+<html>
+<head>
+<script type="text/javascript" src="../../http/tests/inspector/inspector-test.js"></script>
+<script type="text/javascript" src="./resources/break-on-exception-tests.js"></script>
+<script>
+function test() {
+    function doExceptionTest(testName, exceptionBreakType, resumeAction)
+    {
+        var pauses = 0;
+        var index = 0;
+
+        function runTestCase(test) {
+            InspectorTest.evaluateInPage("setTimeout(" + test + ", 50)");
+        }
+
+        WebInspector.debuggerManager.addEventListener(WebInspector.DebuggerManager.Event.ScriptAdded, function(event) {
+            var scriptObject = event.data.script;
+            if (!/break-on-exception-tests\.js$/.test(scriptObject.url))
+                return;
+
+            if (exceptionBreakType == 'AllExceptions')
+                WebInspector.debuggerManager.allExceptionsBreakpoint.disabled = false;
+            else
+                WebInspector.debuggerManager.allUncaughtExceptionsBreakpoint.disabled = false;
+
+            runTestCase(testName);
+        });
+
+        WebInspector.debuggerManager.addEventListener(WebInspector.DebuggerManager.Event.CallFramesDidChange, function(event) {
+            var callFrame = WebInspector.debuggerManager.activeCallFrame;
+            if (callFrame) {
+                // Pausing.
+                InspectorTest.assert(WebInspector.debuggerManager.pauseReason == "exception");
+
+                var funcName = callFrame.functionName || "<anonymous>";
+                var location = callFrame.sourceCodeLocation;
+                var line = location.lineNumber + 1;
+                var column = location.columnNumber + 1;
+
+                InspectorTest.log("PAUSE #" + (++pauses) + " AT: " + funcName + ":" + line + ":" + column);
+                WebInspector.debuggerManager.resume();
+
+            } else {
+                // Resuming.
+                if (resumeAction == 'FinishOnResume')
+                    InspectorTest.completeTest();
+            }
+        });
+
+        // This is a signal mechanism for the web process to tell us that the test is done.
+        // The web process fires the signal by doing console.log("DONE").
+        WebInspector.logManager.addEventListener(WebInspector.LogManager.Event.MessageAdded, function(event) {
+            var message = event.data.message;
+            if (!message.parameters || message.parameters.length !== 1)
+                return;
+            if (message.parameters[0].type !== "string" || message.parameters[0].description !== "DONE")
+                return;
+            InspectorTest.completeTest();
+        });
+
+        InspectorTest.reloadPage();
+    }
+
+    doExceptionTest('testThrowingInPromiseWithRethrowInCatch', 'AllExceptions', 'FinishOnResume');
+}
+</script>
+</head>
+<body onload="runTest()">
+    <p>Checking pause locations when pausing on all exceptions.</p>
+</body>
+</html>
diff --git a/LayoutTests/inspector/debugger/break-on-exception-throw-in-promise-then-expected.txt b/LayoutTests/inspector/debugger/break-on-exception-throw-in-promise-then-expected.txt
new file mode 100644 (file)
index 0000000..0670a4d
--- /dev/null
@@ -0,0 +1,8 @@
+CONSOLE MESSAGE: line 55: testThrowingInPromiseThen
+CONSOLE MESSAGE: line 57: in promise
+CONSOLE MESSAGE: line 60: in promise.then
+CONSOLE MESSAGE: line 7: throwing TestError
+Checking pause locations when pausing on all exceptions.
+
+PAUSE #1 AT: doThrow:8:22
+
diff --git a/LayoutTests/inspector/debugger/break-on-exception-throw-in-promise-then-with-catch-expected.txt b/LayoutTests/inspector/debugger/break-on-exception-throw-in-promise-then-with-catch-expected.txt
new file mode 100644 (file)
index 0000000..ae7431c
--- /dev/null
@@ -0,0 +1,10 @@
+CONSOLE MESSAGE: line 66: testThrowingInPromiseThenWithCatch
+CONSOLE MESSAGE: line 68: in promise
+CONSOLE MESSAGE: line 71: in promise.then
+CONSOLE MESSAGE: line 7: throwing TestError
+CONSOLE MESSAGE: line 74: in promise.catch
+CONSOLE MESSAGE: line 75: DONE
+Checking pause locations when pausing on all exceptions.
+
+PAUSE #1 AT: doThrow:8:22
+
diff --git a/LayoutTests/inspector/debugger/break-on-exception-throw-in-promise-then-with-catch.html b/LayoutTests/inspector/debugger/break-on-exception-throw-in-promise-then-with-catch.html
new file mode 100644 (file)
index 0000000..b474424
--- /dev/null
@@ -0,0 +1,72 @@
+<!doctype html>
+<html>
+<head>
+<script type="text/javascript" src="../../http/tests/inspector/inspector-test.js"></script>
+<script type="text/javascript" src="./resources/break-on-exception-tests.js"></script>
+<script>
+function test() {
+    function doExceptionTest(testName, exceptionBreakType, resumeAction)
+    {
+        var pauses = 0;
+        var index = 0;
+
+        function runTestCase(test) {
+            InspectorTest.evaluateInPage("setTimeout(" + test + ", 50)");
+        }
+
+        WebInspector.debuggerManager.addEventListener(WebInspector.DebuggerManager.Event.ScriptAdded, function(event) {
+            var scriptObject = event.data.script;
+            if (!/break-on-exception-tests\.js$/.test(scriptObject.url))
+                return;
+
+            if (exceptionBreakType == 'AllExceptions')
+                WebInspector.debuggerManager.allExceptionsBreakpoint.disabled = false;
+            else
+                WebInspector.debuggerManager.allUncaughtExceptionsBreakpoint.disabled = false;
+
+            runTestCase(testName);
+        });
+
+        WebInspector.debuggerManager.addEventListener(WebInspector.DebuggerManager.Event.CallFramesDidChange, function(event) {
+            var callFrame = WebInspector.debuggerManager.activeCallFrame;
+            if (callFrame) {
+                // Pausing.
+                InspectorTest.assert(WebInspector.debuggerManager.pauseReason == "exception");
+
+                var funcName = callFrame.functionName || "<anonymous>";
+                var location = callFrame.sourceCodeLocation;
+                var line = location.lineNumber + 1;
+                var column = location.columnNumber + 1;
+
+                InspectorTest.log("PAUSE #" + (++pauses) + " AT: " + funcName + ":" + line + ":" + column);
+                WebInspector.debuggerManager.resume();
+
+            } else {
+                // Resuming.
+                if (resumeAction == 'FinishOnResume')
+                    InspectorTest.completeTest();
+            }
+        });
+
+        // This is a signal mechanism for the web process to tell us that the test is done.
+        // The web process fires the signal by doing console.log("DONE").
+        WebInspector.logManager.addEventListener(WebInspector.LogManager.Event.MessageAdded, function(event) {
+            var message = event.data.message;
+            if (!message.parameters || message.parameters.length !== 1)
+                return;
+            if (message.parameters[0].type !== "string" || message.parameters[0].description !== "DONE")
+                return;
+            InspectorTest.completeTest();
+        });
+
+        InspectorTest.reloadPage();
+    }
+
+    doExceptionTest('testThrowingInPromiseThenWithCatch', 'AllExceptions', 'IgnoreResume');
+}
+</script>
+</head>
+<body onload="runTest()">
+    <p>Checking pause locations when pausing on all exceptions.</p>
+</body>
+</html>
diff --git a/LayoutTests/inspector/debugger/break-on-exception-throw-in-promise-then.html b/LayoutTests/inspector/debugger/break-on-exception-throw-in-promise-then.html
new file mode 100644 (file)
index 0000000..cad68a2
--- /dev/null
@@ -0,0 +1,72 @@
+<!doctype html>
+<html>
+<head>
+<script type="text/javascript" src="../../http/tests/inspector/inspector-test.js"></script>
+<script type="text/javascript" src="./resources/break-on-exception-tests.js"></script>
+<script>
+function test() {
+    function doExceptionTest(testName, exceptionBreakType, resumeAction)
+    {
+        var pauses = 0;
+        var index = 0;
+
+        function runTestCase(test) {
+            InspectorTest.evaluateInPage("setTimeout(" + test + ", 50)");
+        }
+
+        WebInspector.debuggerManager.addEventListener(WebInspector.DebuggerManager.Event.ScriptAdded, function(event) {
+            var scriptObject = event.data.script;
+            if (!/break-on-exception-tests\.js$/.test(scriptObject.url))
+                return;
+
+            if (exceptionBreakType == 'AllExceptions')
+                WebInspector.debuggerManager.allExceptionsBreakpoint.disabled = false;
+            else
+                WebInspector.debuggerManager.allUncaughtExceptionsBreakpoint.disabled = false;
+
+            runTestCase(testName);
+        });
+
+        WebInspector.debuggerManager.addEventListener(WebInspector.DebuggerManager.Event.CallFramesDidChange, function(event) {
+            var callFrame = WebInspector.debuggerManager.activeCallFrame;
+            if (callFrame) {
+                // Pausing.
+                InspectorTest.assert(WebInspector.debuggerManager.pauseReason == "exception");
+
+                var funcName = callFrame.functionName || "<anonymous>";
+                var location = callFrame.sourceCodeLocation;
+                var line = location.lineNumber + 1;
+                var column = location.columnNumber + 1;
+
+                InspectorTest.log("PAUSE #" + (++pauses) + " AT: " + funcName + ":" + line + ":" + column);
+                WebInspector.debuggerManager.resume();
+
+            } else {
+                // Resuming.
+                if (resumeAction == 'FinishOnResume')
+                    InspectorTest.completeTest();
+            }
+        });
+
+        // This is a signal mechanism for the web process to tell us that the test is done.
+        // The web process fires the signal by doing console.log("DONE").
+        WebInspector.logManager.addEventListener(WebInspector.LogManager.Event.MessageAdded, function(event) {
+            var message = event.data.message;
+            if (!message.parameters || message.parameters.length !== 1)
+                return;
+            if (message.parameters[0].type !== "string" || message.parameters[0].description !== "DONE")
+                return;
+            InspectorTest.completeTest();
+        });
+
+        InspectorTest.reloadPage();
+    }
+
+    doExceptionTest('testThrowingInPromiseThen', 'AllExceptions', 'FinishOnResume');
+}
+</script>
+</head>
+<body onload="runTest()">
+    <p>Checking pause locations when pausing on all exceptions.</p>
+</body>
+</html>
diff --git a/LayoutTests/inspector/debugger/break-on-exception-throw-in-promise-with-catch-expected.txt b/LayoutTests/inspector/debugger/break-on-exception-throw-in-promise-with-catch-expected.txt
new file mode 100644 (file)
index 0000000..1b78daa
--- /dev/null
@@ -0,0 +1,9 @@
+CONSOLE MESSAGE: line 44: testThrowingInPromiseWithCatch
+CONSOLE MESSAGE: line 46: in promise
+CONSOLE MESSAGE: line 7: throwing TestError
+CONSOLE MESSAGE: line 49: in promise.catch
+CONSOLE MESSAGE: line 50: DONE
+Checking pause locations when pausing on all exceptions.
+
+PAUSE #1 AT: doThrow:8:22
+
diff --git a/LayoutTests/inspector/debugger/break-on-exception-throw-in-promise-with-catch.html b/LayoutTests/inspector/debugger/break-on-exception-throw-in-promise-with-catch.html
new file mode 100644 (file)
index 0000000..02d47bc
--- /dev/null
@@ -0,0 +1,72 @@
+<!doctype html>
+<html>
+<head>
+<script type="text/javascript" src="../../http/tests/inspector/inspector-test.js"></script>
+<script type="text/javascript" src="./resources/break-on-exception-tests.js"></script>
+<script>
+function test() {
+    function doExceptionTest(testName, exceptionBreakType, resumeAction)
+    {
+        var pauses = 0;
+        var index = 0;
+
+        function runTestCase(test) {
+            InspectorTest.evaluateInPage("setTimeout(" + test + ", 50)");
+        }
+
+        WebInspector.debuggerManager.addEventListener(WebInspector.DebuggerManager.Event.ScriptAdded, function(event) {
+            var scriptObject = event.data.script;
+            if (!/break-on-exception-tests\.js$/.test(scriptObject.url))
+                return;
+
+            if (exceptionBreakType == 'AllExceptions')
+                WebInspector.debuggerManager.allExceptionsBreakpoint.disabled = false;
+            else
+                WebInspector.debuggerManager.allUncaughtExceptionsBreakpoint.disabled = false;
+
+            runTestCase(testName);
+        });
+
+        WebInspector.debuggerManager.addEventListener(WebInspector.DebuggerManager.Event.CallFramesDidChange, function(event) {
+            var callFrame = WebInspector.debuggerManager.activeCallFrame;
+            if (callFrame) {
+                // Pausing.
+                InspectorTest.assert(WebInspector.debuggerManager.pauseReason == "exception");
+
+                var funcName = callFrame.functionName || "<anonymous>";
+                var location = callFrame.sourceCodeLocation;
+                var line = location.lineNumber + 1;
+                var column = location.columnNumber + 1;
+
+                InspectorTest.log("PAUSE #" + (++pauses) + " AT: " + funcName + ":" + line + ":" + column);
+                WebInspector.debuggerManager.resume();
+
+            } else {
+                // Resuming.
+                if (resumeAction == 'FinishOnResume')
+                    InspectorTest.completeTest();
+            }
+        });
+
+        // This is a signal mechanism for the web process to tell us that the test is done.
+        // The web process fires the signal by doing console.log("DONE").
+        WebInspector.logManager.addEventListener(WebInspector.LogManager.Event.MessageAdded, function(event) {
+            var message = event.data.message;
+            if (!message.parameters || message.parameters.length !== 1)
+                return;
+            if (message.parameters[0].type !== "string" || message.parameters[0].description !== "DONE")
+                return;
+            InspectorTest.completeTest();
+        });
+
+        InspectorTest.reloadPage();
+    }
+
+    doExceptionTest('testThrowingInPromiseWithCatch', 'AllExceptions', 'IgnoreResume');
+}
+</script>
+</head>
+<body onload="runTest()">
+    <p>Checking pause locations when pausing on all exceptions.</p>
+</body>
+</html>
diff --git a/LayoutTests/inspector/debugger/break-on-exception-throw-in-promise.html b/LayoutTests/inspector/debugger/break-on-exception-throw-in-promise.html
new file mode 100644 (file)
index 0000000..09f49ff
--- /dev/null
@@ -0,0 +1,72 @@
+<!doctype html>
+<html>
+<head>
+<script type="text/javascript" src="../../http/tests/inspector/inspector-test.js"></script>
+<script type="text/javascript" src="./resources/break-on-exception-tests.js"></script>
+<script>
+function test() {
+    function doExceptionTest(testName, exceptionBreakType, resumeAction)
+    {
+        var pauses = 0;
+        var index = 0;
+
+        function runTestCase(test) {
+            InspectorTest.evaluateInPage("setTimeout(" + test + ", 50)");
+        }
+
+        WebInspector.debuggerManager.addEventListener(WebInspector.DebuggerManager.Event.ScriptAdded, function(event) {
+            var scriptObject = event.data.script;
+            if (!/break-on-exception-tests\.js$/.test(scriptObject.url))
+                return;
+
+            if (exceptionBreakType == 'AllExceptions')
+                WebInspector.debuggerManager.allExceptionsBreakpoint.disabled = false;
+            else
+                WebInspector.debuggerManager.allUncaughtExceptionsBreakpoint.disabled = false;
+
+            runTestCase(testName);
+        });
+
+        WebInspector.debuggerManager.addEventListener(WebInspector.DebuggerManager.Event.CallFramesDidChange, function(event) {
+            var callFrame = WebInspector.debuggerManager.activeCallFrame;
+            if (callFrame) {
+                // Pausing.
+                InspectorTest.assert(WebInspector.debuggerManager.pauseReason == "exception");
+
+                var funcName = callFrame.functionName || "<anonymous>";
+                var location = callFrame.sourceCodeLocation;
+                var line = location.lineNumber + 1;
+                var column = location.columnNumber + 1;
+
+                InspectorTest.log("PAUSE #" + (++pauses) + " AT: " + funcName + ":" + line + ":" + column);
+                WebInspector.debuggerManager.resume();
+
+            } else {
+                // Resuming.
+                if (resumeAction == 'FinishOnResume')
+                    InspectorTest.completeTest();
+            }
+        });
+
+        // This is a signal mechanism for the web process to tell us that the test is done.
+        // The web process fires the signal by doing console.log("DONE").
+        WebInspector.logManager.addEventListener(WebInspector.LogManager.Event.MessageAdded, function(event) {
+            var message = event.data.message;
+            if (!message.parameters || message.parameters.length !== 1)
+                return;
+            if (message.parameters[0].type !== "string" || message.parameters[0].description !== "DONE")
+                return;
+            InspectorTest.completeTest();
+        });
+
+        InspectorTest.reloadPage();
+    }
+
+    doExceptionTest('testThrowingInPromise', 'AllExceptions', 'FinishOnResume');
+}
+</script>
+</head>
+<body onload="runTest()">
+    <p>Checking pause locations when pausing on all exceptions.</p>
+</body>
+</html>
diff --git a/LayoutTests/inspector/debugger/break-on-exception-window-onerror-expected.txt b/LayoutTests/inspector/debugger/break-on-exception-window-onerror-expected.txt
new file mode 100644 (file)
index 0000000..d4be619
--- /dev/null
@@ -0,0 +1,8 @@
+CONSOLE MESSAGE: line 7: throwing TestError
+CONSOLE MESSAGE: line 8: window.onerror: TestError
+CONSOLE MESSAGE: line 9: DONE
+CONSOLE MESSAGE: line 8: TestError
+Checking pause locations when pausing on all exceptions.
+
+PAUSE #1 AT: doThrow:8:22
+
diff --git a/LayoutTests/inspector/debugger/break-on-exception-window-onerror.html b/LayoutTests/inspector/debugger/break-on-exception-window-onerror.html
new file mode 100644 (file)
index 0000000..d1f8ce7
--- /dev/null
@@ -0,0 +1,77 @@
+<!doctype html>
+<html>
+<head>
+<script type="text/javascript" src="../../http/tests/inspector/inspector-test.js"></script>
+<script type="text/javascript" src="./resources/break-on-exception-tests.js"></script>
+<script>
+window.onerror = function(e) {
+    console.log("window.onerror: " + e);
+    console.log("DONE");
+}
+
+function test() {
+    function doExceptionTest(testName, exceptionBreakType, resumeAction)
+    {
+        var pauses = 0;
+        var index = 0;
+
+        function runTestCase(test) {
+            InspectorTest.evaluateInPage("setTimeout(" + test + ", 50)");
+        }
+
+        WebInspector.debuggerManager.addEventListener(WebInspector.DebuggerManager.Event.ScriptAdded, function(event) {
+            var scriptObject = event.data.script;
+            if (!/break-on-exception-tests\.js$/.test(scriptObject.url))
+                return;
+
+            if (exceptionBreakType == 'AllExceptions')
+                WebInspector.debuggerManager.allExceptionsBreakpoint.disabled = false;
+            else
+                WebInspector.debuggerManager.allUncaughtExceptionsBreakpoint.disabled = false;
+
+            runTestCase(testName);
+        });
+
+        WebInspector.debuggerManager.addEventListener(WebInspector.DebuggerManager.Event.CallFramesDidChange, function(event) {
+            var callFrame = WebInspector.debuggerManager.activeCallFrame;
+            if (callFrame) {
+                // Pausing.
+                InspectorTest.assert(WebInspector.debuggerManager.pauseReason == "exception");
+
+                var funcName = callFrame.functionName || "<anonymous>";
+                var location = callFrame.sourceCodeLocation;
+                var line = location.lineNumber + 1;
+                var column = location.columnNumber + 1;
+
+                InspectorTest.log("PAUSE #" + (++pauses) + " AT: " + funcName + ":" + line + ":" + column);
+                WebInspector.debuggerManager.resume();
+
+            } else {
+                // Resuming.
+                if (resumeAction == 'FinishOnResume')
+                    InspectorTest.completeTest();
+            }
+        });
+
+        // This is a signal mechanism for the web process to tell us that the test is done.
+        // The web process fires the signal by doing console.log("DONE").
+        WebInspector.logManager.addEventListener(WebInspector.LogManager.Event.MessageAdded, function(event) {
+            var message = event.data.message;
+            if (!message.parameters || message.parameters.length !== 1)
+                return;
+            if (message.parameters[0].type !== "string" || message.parameters[0].description !== "DONE")
+                return;
+            InspectorTest.completeTest();
+        });
+
+        InspectorTest.reloadPage();
+    }
+
+    doExceptionTest('doThrow', 'AllExceptions', 'IgnoreResume');
+}
+</script>
+</head>
+<body onload="runTest()">
+    <p>Checking pause locations when pausing on all exceptions.</p>
+</body>
+</html>
diff --git a/LayoutTests/inspector/debugger/break-on-exception.html b/LayoutTests/inspector/debugger/break-on-exception.html
new file mode 100644 (file)
index 0000000..410e156
--- /dev/null
@@ -0,0 +1,72 @@
+<!doctype html>
+<html>
+<head>
+<script type="text/javascript" src="../../http/tests/inspector/inspector-test.js"></script>
+<script type="text/javascript" src="./resources/break-on-exception-tests.js"></script>
+<script>
+function test() {
+    function doExceptionTest(testName, exceptionBreakType, resumeAction)
+    {
+        var pauses = 0;
+        var index = 0;
+
+        function runTestCase(test) {
+            InspectorTest.evaluateInPage("setTimeout(" + test + ", 50)");
+        }
+
+        WebInspector.debuggerManager.addEventListener(WebInspector.DebuggerManager.Event.ScriptAdded, function(event) {
+            var scriptObject = event.data.script;
+            if (!/break-on-exception-tests\.js$/.test(scriptObject.url))
+                return;
+
+            if (exceptionBreakType == 'AllExceptions')
+                WebInspector.debuggerManager.allExceptionsBreakpoint.disabled = false;
+            else
+                WebInspector.debuggerManager.allUncaughtExceptionsBreakpoint.disabled = false;
+
+            runTestCase(testName);
+        });
+
+        WebInspector.debuggerManager.addEventListener(WebInspector.DebuggerManager.Event.CallFramesDidChange, function(event) {
+            var callFrame = WebInspector.debuggerManager.activeCallFrame;
+            if (callFrame) {
+                // Pausing.
+                InspectorTest.assert(WebInspector.debuggerManager.pauseReason == "exception");
+
+                var funcName = callFrame.functionName || "<anonymous>";
+                var location = callFrame.sourceCodeLocation;
+                var line = location.lineNumber + 1;
+                var column = location.columnNumber + 1;
+
+                InspectorTest.log("PAUSE #" + (++pauses) + " AT: " + funcName + ":" + line + ":" + column);
+                WebInspector.debuggerManager.resume();
+
+            } else {
+                // Resuming.
+                if (resumeAction == 'FinishOnResume')
+                    InspectorTest.completeTest();
+            }
+        });
+
+        // This is a signal mechanism for the web process to tell us that the test is done.
+        // The web process fires the signal by doing console.log("DONE").
+        WebInspector.logManager.addEventListener(WebInspector.LogManager.Event.MessageAdded, function(event) {
+            var message = event.data.message;
+            if (!message.parameters || message.parameters.length !== 1)
+                return;
+            if (message.parameters[0].type !== "string" || message.parameters[0].description !== "DONE")
+                return;
+            InspectorTest.completeTest();
+        });
+
+        InspectorTest.reloadPage();
+    }
+
+    doExceptionTest('doThrow', 'AllExceptions', 'IgnoreResume');
+}
+</script>
+</head>
+<body onload="runTest()">
+    <p>Checking pause locations when pausing on all exceptions.</p>
+</body>
+</html>
diff --git a/LayoutTests/inspector/debugger/break-on-uncaught-exception-catch-expected.txt b/LayoutTests/inspector/debugger/break-on-uncaught-exception-catch-expected.txt
new file mode 100644 (file)
index 0000000..0cbeae7
--- /dev/null
@@ -0,0 +1,5 @@
+CONSOLE MESSAGE: line 12: testCatch
+CONSOLE MESSAGE: line 7: throwing TestError
+CONSOLE MESSAGE: line 16: catch TestError
+CONSOLE MESSAGE: line 18: DONE
+Checking pause locations when pausing on uncaught exceptions.
diff --git a/LayoutTests/inspector/debugger/break-on-uncaught-exception-catch.html b/LayoutTests/inspector/debugger/break-on-uncaught-exception-catch.html
new file mode 100644 (file)
index 0000000..767ab95
--- /dev/null
@@ -0,0 +1,72 @@
+<!doctype html>
+<html>
+<head>
+<script type="text/javascript" src="../../http/tests/inspector/inspector-test.js"></script>
+<script type="text/javascript" src="./resources/break-on-exception-tests.js"></script>
+<script>
+function test() {
+    function doExceptionTest(testName, exceptionBreakType, resumeAction)
+    {
+        var pauses = 0;
+        var index = 0;
+
+        function runTestCase(test) {
+            InspectorTest.evaluateInPage("setTimeout(" + test + ", 50)");
+        }
+
+        WebInspector.debuggerManager.addEventListener(WebInspector.DebuggerManager.Event.ScriptAdded, function(event) {
+            var scriptObject = event.data.script;
+            if (!/break-on-exception-tests\.js$/.test(scriptObject.url))
+                return;
+
+            if (exceptionBreakType == 'AllExceptions')
+                WebInspector.debuggerManager.allExceptionsBreakpoint.disabled = false;
+            else
+                WebInspector.debuggerManager.allUncaughtExceptionsBreakpoint.disabled = false;
+
+            runTestCase(testName);
+        });
+
+        WebInspector.debuggerManager.addEventListener(WebInspector.DebuggerManager.Event.CallFramesDidChange, function(event) {
+            var callFrame = WebInspector.debuggerManager.activeCallFrame;
+            if (callFrame) {
+                // Pausing.
+                InspectorTest.assert(WebInspector.debuggerManager.pauseReason == "exception");
+
+                var funcName = callFrame.functionName || "<anonymous>";
+                var location = callFrame.sourceCodeLocation;
+                var line = location.lineNumber + 1;
+                var column = location.columnNumber + 1;
+
+                InspectorTest.log("PAUSE #" + (++pauses) + " AT: " + funcName + ":" + line + ":" + column);
+                WebInspector.debuggerManager.resume();
+
+            } else {
+                // Resuming.
+                if (resumeAction == 'FinishOnResume')
+                    InspectorTest.completeTest();
+            }
+        });
+
+        // This is a signal mechanism for the web process to tell us that the test is done.
+        // The web process fires the signal by doing console.log("DONE").
+        WebInspector.logManager.addEventListener(WebInspector.LogManager.Event.MessageAdded, function(event) {
+            var message = event.data.message;
+            if (!message.parameters || message.parameters.length !== 1)
+                return;
+            if (message.parameters[0].type !== "string" || message.parameters[0].description !== "DONE")
+                return;
+            InspectorTest.completeTest();
+        });
+
+        InspectorTest.reloadPage();
+    }
+
+    doExceptionTest('testCatch', 'UncaughtExceptions', 'IgnoreResume');
+}
+</script>
+</head>
+<body onload="runTest()">
+    <p>Checking pause locations when pausing on uncaught exceptions.</p>
+</body>
+</html>
diff --git a/LayoutTests/inspector/debugger/break-on-uncaught-exception-expected.txt b/LayoutTests/inspector/debugger/break-on-uncaught-exception-expected.txt
new file mode 100644 (file)
index 0000000..31dca28
--- /dev/null
@@ -0,0 +1,7 @@
+CONSOLE MESSAGE: line 7: throwing TestError
+CONSOLE MESSAGE: line 8: TestError
+Checking pause locations when pausing on uncaught exceptions.
+
+PAUSE #1 AT: doThrow:8:22
+Uncaught exception in test page: TestError [break-on-exception-tests.js:8]
+
diff --git a/LayoutTests/inspector/debugger/break-on-uncaught-exception-finally-expected.txt b/LayoutTests/inspector/debugger/break-on-uncaught-exception-finally-expected.txt
new file mode 100644 (file)
index 0000000..25bd1aa
--- /dev/null
@@ -0,0 +1,9 @@
+CONSOLE MESSAGE: line 22: testFinally
+CONSOLE MESSAGE: line 7: throwing TestError
+CONSOLE MESSAGE: line 26: finally
+CONSOLE MESSAGE: line 8: TestError
+Checking pause locations when pausing on uncaught exceptions.
+
+PAUSE #1 AT: doThrow:8:22
+Uncaught exception in test page: TestError [break-on-exception-tests.js:8]
+
diff --git a/LayoutTests/inspector/debugger/break-on-uncaught-exception-finally.html b/LayoutTests/inspector/debugger/break-on-uncaught-exception-finally.html
new file mode 100644 (file)
index 0000000..45db331
--- /dev/null
@@ -0,0 +1,72 @@
+<!doctype html>
+<html>
+<head>
+<script type="text/javascript" src="../../http/tests/inspector/inspector-test.js"></script>
+<script type="text/javascript" src="./resources/break-on-exception-tests.js"></script>
+<script>
+function test() {
+    function doExceptionTest(testName, exceptionBreakType, resumeAction)
+    {
+        var pauses = 0;
+        var index = 0;
+
+        function runTestCase(test) {
+            InspectorTest.evaluateInPage("setTimeout(" + test + ", 50)");
+        }
+
+        WebInspector.debuggerManager.addEventListener(WebInspector.DebuggerManager.Event.ScriptAdded, function(event) {
+            var scriptObject = event.data.script;
+            if (!/break-on-exception-tests\.js$/.test(scriptObject.url))
+                return;
+
+            if (exceptionBreakType == 'AllExceptions')
+                WebInspector.debuggerManager.allExceptionsBreakpoint.disabled = false;
+            else
+                WebInspector.debuggerManager.allUncaughtExceptionsBreakpoint.disabled = false;
+
+            runTestCase(testName);
+        });
+
+        WebInspector.debuggerManager.addEventListener(WebInspector.DebuggerManager.Event.CallFramesDidChange, function(event) {
+            var callFrame = WebInspector.debuggerManager.activeCallFrame;
+            if (callFrame) {
+                // Pausing.
+                InspectorTest.assert(WebInspector.debuggerManager.pauseReason == "exception");
+
+                var funcName = callFrame.functionName || "<anonymous>";
+                var location = callFrame.sourceCodeLocation;
+                var line = location.lineNumber + 1;
+                var column = location.columnNumber + 1;
+
+                InspectorTest.log("PAUSE #" + (++pauses) + " AT: " + funcName + ":" + line + ":" + column);
+                WebInspector.debuggerManager.resume();
+
+            } else {
+                // Resuming.
+                if (resumeAction == 'FinishOnResume')
+                    InspectorTest.completeTest();
+            }
+        });
+
+        // This is a signal mechanism for the web process to tell us that the test is done.
+        // The web process fires the signal by doing console.log("DONE").
+        WebInspector.logManager.addEventListener(WebInspector.LogManager.Event.MessageAdded, function(event) {
+            var message = event.data.message;
+            if (!message.parameters || message.parameters.length !== 1)
+                return;
+            if (message.parameters[0].type !== "string" || message.parameters[0].description !== "DONE")
+                return;
+            InspectorTest.completeTest();
+        });
+
+        InspectorTest.reloadPage();
+    }
+
+    doExceptionTest('testFinally', 'UncaughtExceptions', 'IgnoreResume');
+}
+</script>
+</head>
+<body onload="runTest()">
+    <p>Checking pause locations when pausing on uncaught exceptions.</p>
+</body>
+</html>
diff --git a/LayoutTests/inspector/debugger/break-on-uncaught-exception-native-expected.txt b/LayoutTests/inspector/debugger/break-on-uncaught-exception-native-expected.txt
new file mode 100644 (file)
index 0000000..e51ccc8
--- /dev/null
@@ -0,0 +1,8 @@
+CONSOLE MESSAGE: line 31: testThrowingThruNativeCode
+CONSOLE MESSAGE: line 7: throwing TestError
+CONSOLE MESSAGE: line 8: TestError
+Checking pause locations when pausing on uncaught exceptions.
+
+PAUSE #1 AT: doThrow:8:22
+Uncaught exception in test page: TestError [break-on-exception-tests.js:8]
+
diff --git a/LayoutTests/inspector/debugger/break-on-uncaught-exception-native.html b/LayoutTests/inspector/debugger/break-on-uncaught-exception-native.html
new file mode 100644 (file)
index 0000000..a5ab906
--- /dev/null
@@ -0,0 +1,72 @@
+<!doctype html>
+<html>
+<head>
+<script type="text/javascript" src="../../http/tests/inspector/inspector-test.js"></script>
+<script type="text/javascript" src="./resources/break-on-exception-tests.js"></script>
+<script>
+function test() {
+    function doExceptionTest(testName, exceptionBreakType, resumeAction)
+    {
+        var pauses = 0;
+        var index = 0;
+
+        function runTestCase(test) {
+            InspectorTest.evaluateInPage("setTimeout(" + test + ", 50)");
+        }
+
+        WebInspector.debuggerManager.addEventListener(WebInspector.DebuggerManager.Event.ScriptAdded, function(event) {
+            var scriptObject = event.data.script;
+            if (!/break-on-exception-tests\.js$/.test(scriptObject.url))
+                return;
+
+            if (exceptionBreakType == 'AllExceptions')
+                WebInspector.debuggerManager.allExceptionsBreakpoint.disabled = false;
+            else
+                WebInspector.debuggerManager.allUncaughtExceptionsBreakpoint.disabled = false;
+
+            runTestCase(testName);
+        });
+
+        WebInspector.debuggerManager.addEventListener(WebInspector.DebuggerManager.Event.CallFramesDidChange, function(event) {
+            var callFrame = WebInspector.debuggerManager.activeCallFrame;
+            if (callFrame) {
+                // Pausing.
+                InspectorTest.assert(WebInspector.debuggerManager.pauseReason == "exception");
+
+                var funcName = callFrame.functionName || "<anonymous>";
+                var location = callFrame.sourceCodeLocation;
+                var line = location.lineNumber + 1;
+                var column = location.columnNumber + 1;
+
+                InspectorTest.log("PAUSE #" + (++pauses) + " AT: " + funcName + ":" + line + ":" + column);
+                WebInspector.debuggerManager.resume();
+
+            } else {
+                // Resuming.
+                if (resumeAction == 'FinishOnResume')
+                    InspectorTest.completeTest();
+            }
+        });
+
+        // This is a signal mechanism for the web process to tell us that the test is done.
+        // The web process fires the signal by doing console.log("DONE").
+        WebInspector.logManager.addEventListener(WebInspector.LogManager.Event.MessageAdded, function(event) {
+            var message = event.data.message;
+            if (!message.parameters || message.parameters.length !== 1)
+                return;
+            if (message.parameters[0].type !== "string" || message.parameters[0].description !== "DONE")
+                return;
+            InspectorTest.completeTest();
+        });
+
+        InspectorTest.reloadPage();
+    }
+
+    doExceptionTest('testThrowingThruNativeCode', 'UncaughtExceptions', 'IgnoreResume');
+}
+</script>
+</head>
+<body onload="runTest()">
+    <p>Checking pause locations when pausing on uncaught exceptions.</p>
+</body>
+</html>
diff --git a/LayoutTests/inspector/debugger/break-on-uncaught-exception-throw-in-promise-expected.txt b/LayoutTests/inspector/debugger/break-on-uncaught-exception-throw-in-promise-expected.txt
new file mode 100644 (file)
index 0000000..c697901
--- /dev/null
@@ -0,0 +1,7 @@
+CONSOLE MESSAGE: line 36: testThrowingInPromise
+CONSOLE MESSAGE: line 38: in promise
+CONSOLE MESSAGE: line 7: throwing TestError
+Checking pause locations when pausing on uncaught exceptions.
+
+PAUSE #1 AT: doThrow:8:22
+
diff --git a/LayoutTests/inspector/debugger/break-on-uncaught-exception-throw-in-promise-rethrow-in-catch-expected.txt b/LayoutTests/inspector/debugger/break-on-uncaught-exception-throw-in-promise-rethrow-in-catch-expected.txt
new file mode 100644 (file)
index 0000000..c068a9a
--- /dev/null
@@ -0,0 +1,9 @@
+CONSOLE MESSAGE: line 80: testThrowingInPromiseWithRethrowInCatch
+CONSOLE MESSAGE: line 82: in promise
+CONSOLE MESSAGE: line 7: throwing TestError
+CONSOLE MESSAGE: line 85: in promise.catch
+Checking pause locations when pausing on uncaught exceptions.
+
+PAUSE #1 AT: doThrow:8:22
+PAUSE #2 AT: promiseCatch:86:16
+
diff --git a/LayoutTests/inspector/debugger/break-on-uncaught-exception-throw-in-promise-rethrow-in-catch.html b/LayoutTests/inspector/debugger/break-on-uncaught-exception-throw-in-promise-rethrow-in-catch.html
new file mode 100644 (file)
index 0000000..5e7d9db
--- /dev/null
@@ -0,0 +1,72 @@
+<!doctype html>
+<html>
+<head>
+<script type="text/javascript" src="../../http/tests/inspector/inspector-test.js"></script>
+<script type="text/javascript" src="./resources/break-on-exception-tests.js"></script>
+<script>
+function test() {
+    function doExceptionTest(testName, exceptionBreakType, resumeAction)
+    {
+        var pauses = 0;
+        var index = 0;
+
+        function runTestCase(test) {
+            InspectorTest.evaluateInPage("setTimeout(" + test + ", 50)");
+        }
+
+        WebInspector.debuggerManager.addEventListener(WebInspector.DebuggerManager.Event.ScriptAdded, function(event) {
+            var scriptObject = event.data.script;
+            if (!/break-on-exception-tests\.js$/.test(scriptObject.url))
+                return;
+
+            if (exceptionBreakType == 'AllExceptions')
+                WebInspector.debuggerManager.allExceptionsBreakpoint.disabled = false;
+            else
+                WebInspector.debuggerManager.allUncaughtExceptionsBreakpoint.disabled = false;
+
+            runTestCase(testName);
+        });
+
+        WebInspector.debuggerManager.addEventListener(WebInspector.DebuggerManager.Event.CallFramesDidChange, function(event) {
+            var callFrame = WebInspector.debuggerManager.activeCallFrame;
+            if (callFrame) {
+                // Pausing.
+                InspectorTest.assert(WebInspector.debuggerManager.pauseReason == "exception");
+
+                var funcName = callFrame.functionName || "<anonymous>";
+                var location = callFrame.sourceCodeLocation;
+                var line = location.lineNumber + 1;
+                var column = location.columnNumber + 1;
+
+                InspectorTest.log("PAUSE #" + (++pauses) + " AT: " + funcName + ":" + line + ":" + column);
+                WebInspector.debuggerManager.resume();
+
+            } else {
+                // Resuming.
+                if (resumeAction == 'FinishOnResume')
+                    InspectorTest.completeTest();
+            }
+        });
+
+        // This is a signal mechanism for the web process to tell us that the test is done.
+        // The web process fires the signal by doing console.log("DONE").
+        WebInspector.logManager.addEventListener(WebInspector.LogManager.Event.MessageAdded, function(event) {
+            var message = event.data.message;
+            if (!message.parameters || message.parameters.length !== 1)
+                return;
+            if (message.parameters[0].type !== "string" || message.parameters[0].description !== "DONE")
+                return;
+            InspectorTest.completeTest();
+        });
+
+        InspectorTest.reloadPage();
+    }
+
+    doExceptionTest('testThrowingInPromiseWithRethrowInCatch', 'UncaughtExceptions', 'FinishOnResume');
+}
+</script>
+</head>
+<body onload="runTest()">
+    <p>Checking pause locations when pausing on uncaught exceptions.</p>
+</body>
+</html>
diff --git a/LayoutTests/inspector/debugger/break-on-uncaught-exception-throw-in-promise-then-expected.txt b/LayoutTests/inspector/debugger/break-on-uncaught-exception-throw-in-promise-then-expected.txt
new file mode 100644 (file)
index 0000000..dbb461f
--- /dev/null
@@ -0,0 +1,8 @@
+CONSOLE MESSAGE: line 55: testThrowingInPromiseThen
+CONSOLE MESSAGE: line 57: in promise
+CONSOLE MESSAGE: line 60: in promise.then
+CONSOLE MESSAGE: line 7: throwing TestError
+Checking pause locations when pausing on uncaught exceptions.
+
+PAUSE #1 AT: doThrow:8:22
+
diff --git a/LayoutTests/inspector/debugger/break-on-uncaught-exception-throw-in-promise-then-with-catch-expected.txt b/LayoutTests/inspector/debugger/break-on-uncaught-exception-throw-in-promise-then-with-catch-expected.txt
new file mode 100644 (file)
index 0000000..e99505d
--- /dev/null
@@ -0,0 +1,10 @@
+CONSOLE MESSAGE: line 66: testThrowingInPromiseThenWithCatch
+CONSOLE MESSAGE: line 68: in promise
+CONSOLE MESSAGE: line 71: in promise.then
+CONSOLE MESSAGE: line 7: throwing TestError
+CONSOLE MESSAGE: line 74: in promise.catch
+CONSOLE MESSAGE: line 75: DONE
+Checking pause locations when pausing on uncaught exceptions.
+
+PAUSE #1 AT: doThrow:8:22
+
diff --git a/LayoutTests/inspector/debugger/break-on-uncaught-exception-throw-in-promise-then-with-catch.html b/LayoutTests/inspector/debugger/break-on-uncaught-exception-throw-in-promise-then-with-catch.html
new file mode 100644 (file)
index 0000000..b9c7095
--- /dev/null
@@ -0,0 +1,72 @@
+<!doctype html>
+<html>
+<head>
+<script type="text/javascript" src="../../http/tests/inspector/inspector-test.js"></script>
+<script type="text/javascript" src="./resources/break-on-exception-tests.js"></script>
+<script>
+function test() {
+    function doExceptionTest(testName, exceptionBreakType, resumeAction)
+    {
+        var pauses = 0;
+        var index = 0;
+
+        function runTestCase(test) {
+            InspectorTest.evaluateInPage("setTimeout(" + test + ", 50)");
+        }
+
+        WebInspector.debuggerManager.addEventListener(WebInspector.DebuggerManager.Event.ScriptAdded, function(event) {
+            var scriptObject = event.data.script;
+            if (!/break-on-exception-tests\.js$/.test(scriptObject.url))
+                return;
+
+            if (exceptionBreakType == 'AllExceptions')
+                WebInspector.debuggerManager.allExceptionsBreakpoint.disabled = false;
+            else
+                WebInspector.debuggerManager.allUncaughtExceptionsBreakpoint.disabled = false;
+
+            runTestCase(testName);
+        });
+
+        WebInspector.debuggerManager.addEventListener(WebInspector.DebuggerManager.Event.CallFramesDidChange, function(event) {
+            var callFrame = WebInspector.debuggerManager.activeCallFrame;
+            if (callFrame) {
+                // Pausing.
+                InspectorTest.assert(WebInspector.debuggerManager.pauseReason == "exception");
+
+                var funcName = callFrame.functionName || "<anonymous>";
+                var location = callFrame.sourceCodeLocation;
+                var line = location.lineNumber + 1;
+                var column = location.columnNumber + 1;
+
+                InspectorTest.log("PAUSE #" + (++pauses) + " AT: " + funcName + ":" + line + ":" + column);
+                WebInspector.debuggerManager.resume();
+
+            } else {
+                // Resuming.
+                if (resumeAction == 'FinishOnResume')
+                    InspectorTest.completeTest();
+            }
+        });
+
+        // This is a signal mechanism for the web process to tell us that the test is done.
+        // The web process fires the signal by doing console.log("DONE").
+        WebInspector.logManager.addEventListener(WebInspector.LogManager.Event.MessageAdded, function(event) {
+            var message = event.data.message;
+            if (!message.parameters || message.parameters.length !== 1)
+                return;
+            if (message.parameters[0].type !== "string" || message.parameters[0].description !== "DONE")
+                return;
+            InspectorTest.completeTest();
+        });
+
+        InspectorTest.reloadPage();
+    }
+
+    doExceptionTest('testThrowingInPromiseThenWithCatch', 'UncaughtExceptions', 'IgnoreResume');
+}
+</script>
+</head>
+<body onload="runTest()">
+    <p>Checking pause locations when pausing on uncaught exceptions.</p>
+</body>
+</html>
diff --git a/LayoutTests/inspector/debugger/break-on-uncaught-exception-throw-in-promise-then.html b/LayoutTests/inspector/debugger/break-on-uncaught-exception-throw-in-promise-then.html
new file mode 100644 (file)
index 0000000..51349b9
--- /dev/null
@@ -0,0 +1,72 @@
+<!doctype html>
+<html>
+<head>
+<script type="text/javascript" src="../../http/tests/inspector/inspector-test.js"></script>
+<script type="text/javascript" src="./resources/break-on-exception-tests.js"></script>
+<script>
+function test() {
+    function doExceptionTest(testName, exceptionBreakType, resumeAction)
+    {
+        var pauses = 0;
+        var index = 0;
+
+        function runTestCase(test) {
+            InspectorTest.evaluateInPage("setTimeout(" + test + ", 50)");
+        }
+
+        WebInspector.debuggerManager.addEventListener(WebInspector.DebuggerManager.Event.ScriptAdded, function(event) {
+            var scriptObject = event.data.script;
+            if (!/break-on-exception-tests\.js$/.test(scriptObject.url))
+                return;
+
+            if (exceptionBreakType == 'AllExceptions')
+                WebInspector.debuggerManager.allExceptionsBreakpoint.disabled = false;
+            else
+                WebInspector.debuggerManager.allUncaughtExceptionsBreakpoint.disabled = false;
+
+            runTestCase(testName);
+        });
+
+        WebInspector.debuggerManager.addEventListener(WebInspector.DebuggerManager.Event.CallFramesDidChange, function(event) {
+            var callFrame = WebInspector.debuggerManager.activeCallFrame;
+            if (callFrame) {
+                // Pausing.
+                InspectorTest.assert(WebInspector.debuggerManager.pauseReason == "exception");
+
+                var funcName = callFrame.functionName || "<anonymous>";
+                var location = callFrame.sourceCodeLocation;
+                var line = location.lineNumber + 1;
+                var column = location.columnNumber + 1;
+
+                InspectorTest.log("PAUSE #" + (++pauses) + " AT: " + funcName + ":" + line + ":" + column);
+                WebInspector.debuggerManager.resume();
+
+            } else {
+                // Resuming.
+                if (resumeAction == 'FinishOnResume')
+                    InspectorTest.completeTest();
+            }
+        });
+
+        // This is a signal mechanism for the web process to tell us that the test is done.
+        // The web process fires the signal by doing console.log("DONE").
+        WebInspector.logManager.addEventListener(WebInspector.LogManager.Event.MessageAdded, function(event) {
+            var message = event.data.message;
+            if (!message.parameters || message.parameters.length !== 1)
+                return;
+            if (message.parameters[0].type !== "string" || message.parameters[0].description !== "DONE")
+                return;
+            InspectorTest.completeTest();
+        });
+
+        InspectorTest.reloadPage();
+    }
+
+    doExceptionTest('testThrowingInPromiseThen', 'UncaughtExceptions', 'FinishOnResume');
+}
+</script>
+</head>
+<body onload="runTest()">
+    <p>Checking pause locations when pausing on uncaught exceptions.</p>
+</body>
+</html>
diff --git a/LayoutTests/inspector/debugger/break-on-uncaught-exception-throw-in-promise-with-catch-expected.txt b/LayoutTests/inspector/debugger/break-on-uncaught-exception-throw-in-promise-with-catch-expected.txt
new file mode 100644 (file)
index 0000000..ed81552
--- /dev/null
@@ -0,0 +1,9 @@
+CONSOLE MESSAGE: line 44: testThrowingInPromiseWithCatch
+CONSOLE MESSAGE: line 46: in promise
+CONSOLE MESSAGE: line 7: throwing TestError
+CONSOLE MESSAGE: line 49: in promise.catch
+CONSOLE MESSAGE: line 50: DONE
+Checking pause locations when pausing on uncaught exceptions.
+
+PAUSE #1 AT: doThrow:8:22
+
diff --git a/LayoutTests/inspector/debugger/break-on-uncaught-exception-throw-in-promise-with-catch.html b/LayoutTests/inspector/debugger/break-on-uncaught-exception-throw-in-promise-with-catch.html
new file mode 100644 (file)
index 0000000..f510b2e
--- /dev/null
@@ -0,0 +1,72 @@
+<!doctype html>
+<html>
+<head>
+<script type="text/javascript" src="../../http/tests/inspector/inspector-test.js"></script>
+<script type="text/javascript" src="./resources/break-on-exception-tests.js"></script>
+<script>
+function test() {
+    function doExceptionTest(testName, exceptionBreakType, resumeAction)
+    {
+        var pauses = 0;
+        var index = 0;
+
+        function runTestCase(test) {
+            InspectorTest.evaluateInPage("setTimeout(" + test + ", 50)");
+        }
+
+        WebInspector.debuggerManager.addEventListener(WebInspector.DebuggerManager.Event.ScriptAdded, function(event) {
+            var scriptObject = event.data.script;
+            if (!/break-on-exception-tests\.js$/.test(scriptObject.url))
+                return;
+
+            if (exceptionBreakType == 'AllExceptions')
+                WebInspector.debuggerManager.allExceptionsBreakpoint.disabled = false;
+            else
+                WebInspector.debuggerManager.allUncaughtExceptionsBreakpoint.disabled = false;
+
+            runTestCase(testName);
+        });
+
+        WebInspector.debuggerManager.addEventListener(WebInspector.DebuggerManager.Event.CallFramesDidChange, function(event) {
+            var callFrame = WebInspector.debuggerManager.activeCallFrame;
+            if (callFrame) {
+                // Pausing.
+                InspectorTest.assert(WebInspector.debuggerManager.pauseReason == "exception");
+
+                var funcName = callFrame.functionName || "<anonymous>";
+                var location = callFrame.sourceCodeLocation;
+                var line = location.lineNumber + 1;
+                var column = location.columnNumber + 1;
+
+                InspectorTest.log("PAUSE #" + (++pauses) + " AT: " + funcName + ":" + line + ":" + column);
+                WebInspector.debuggerManager.resume();
+
+            } else {
+                // Resuming.
+                if (resumeAction == 'FinishOnResume')
+                    InspectorTest.completeTest();
+            }
+        });
+
+        // This is a signal mechanism for the web process to tell us that the test is done.
+        // The web process fires the signal by doing console.log("DONE").
+        WebInspector.logManager.addEventListener(WebInspector.LogManager.Event.MessageAdded, function(event) {
+            var message = event.data.message;
+            if (!message.parameters || message.parameters.length !== 1)
+                return;
+            if (message.parameters[0].type !== "string" || message.parameters[0].description !== "DONE")
+                return;
+            InspectorTest.completeTest();
+        });
+
+        InspectorTest.reloadPage();
+    }
+
+    doExceptionTest('testThrowingInPromiseWithCatch', 'UncaughtExceptions', 'IgnoreResume');
+}
+</script>
+</head>
+<body onload="runTest()">
+    <p>Checking pause locations when pausing on uncaught exceptions.</p>
+</body>
+</html>
diff --git a/LayoutTests/inspector/debugger/break-on-uncaught-exception-throw-in-promise.html b/LayoutTests/inspector/debugger/break-on-uncaught-exception-throw-in-promise.html
new file mode 100644 (file)
index 0000000..d14799b
--- /dev/null
@@ -0,0 +1,72 @@
+<!doctype html>
+<html>
+<head>
+<script type="text/javascript" src="../../http/tests/inspector/inspector-test.js"></script>
+<script type="text/javascript" src="./resources/break-on-exception-tests.js"></script>
+<script>
+function test() {
+    function doExceptionTest(testName, exceptionBreakType, resumeAction)
+    {
+        var pauses = 0;
+        var index = 0;
+
+        function runTestCase(test) {
+            InspectorTest.evaluateInPage("setTimeout(" + test + ", 50)");
+        }
+
+        WebInspector.debuggerManager.addEventListener(WebInspector.DebuggerManager.Event.ScriptAdded, function(event) {
+            var scriptObject = event.data.script;
+            if (!/break-on-exception-tests\.js$/.test(scriptObject.url))
+                return;
+
+            if (exceptionBreakType == 'AllExceptions')
+                WebInspector.debuggerManager.allExceptionsBreakpoint.disabled = false;
+            else
+                WebInspector.debuggerManager.allUncaughtExceptionsBreakpoint.disabled = false;
+
+            runTestCase(testName);
+        });
+
+        WebInspector.debuggerManager.addEventListener(WebInspector.DebuggerManager.Event.CallFramesDidChange, function(event) {
+            var callFrame = WebInspector.debuggerManager.activeCallFrame;
+            if (callFrame) {
+                // Pausing.
+                InspectorTest.assert(WebInspector.debuggerManager.pauseReason == "exception");
+
+                var funcName = callFrame.functionName || "<anonymous>";
+                var location = callFrame.sourceCodeLocation;
+                var line = location.lineNumber + 1;
+                var column = location.columnNumber + 1;
+
+                InspectorTest.log("PAUSE #" + (++pauses) + " AT: " + funcName + ":" + line + ":" + column);
+                WebInspector.debuggerManager.resume();
+
+            } else {
+                // Resuming.
+                if (resumeAction == 'FinishOnResume')
+                    InspectorTest.completeTest();
+            }
+        });
+
+        // This is a signal mechanism for the web process to tell us that the test is done.
+        // The web process fires the signal by doing console.log("DONE").
+        WebInspector.logManager.addEventListener(WebInspector.LogManager.Event.MessageAdded, function(event) {
+            var message = event.data.message;
+            if (!message.parameters || message.parameters.length !== 1)
+                return;
+            if (message.parameters[0].type !== "string" || message.parameters[0].description !== "DONE")
+                return;
+            InspectorTest.completeTest();
+        });
+
+        InspectorTest.reloadPage();
+    }
+
+    doExceptionTest('testThrowingInPromise', 'UncaughtExceptions', 'FinishOnResume');
+}
+</script>
+</head>
+<body onload="runTest()">
+    <p>Checking pause locations when pausing on uncaught exceptions.</p>
+</body>
+</html>
diff --git a/LayoutTests/inspector/debugger/break-on-uncaught-exception-window-onerror-expected.txt b/LayoutTests/inspector/debugger/break-on-uncaught-exception-window-onerror-expected.txt
new file mode 100644 (file)
index 0000000..127e54b
--- /dev/null
@@ -0,0 +1,8 @@
+CONSOLE MESSAGE: line 7: throwing TestError
+CONSOLE MESSAGE: line 8: window.onerror: TestError
+CONSOLE MESSAGE: line 9: DONE
+CONSOLE MESSAGE: line 8: TestError
+Checking pause locations when pausing on uncaught exceptions.
+
+PAUSE #1 AT: doThrow:8:22
+
diff --git a/LayoutTests/inspector/debugger/break-on-uncaught-exception-window-onerror.html b/LayoutTests/inspector/debugger/break-on-uncaught-exception-window-onerror.html
new file mode 100644 (file)
index 0000000..7e8a4f0
--- /dev/null
@@ -0,0 +1,77 @@
+<!doctype html>
+<html>
+<head>
+<script type="text/javascript" src="../../http/tests/inspector/inspector-test.js"></script>
+<script type="text/javascript" src="./resources/break-on-exception-tests.js"></script>
+<script>
+window.onerror = function(e) {
+    console.log("window.onerror: " + e);
+    console.log("DONE");
+}
+
+function test() {
+    function doExceptionTest(testName, exceptionBreakType, resumeAction)
+    {
+        var pauses = 0;
+        var index = 0;
+
+        function runTestCase(test) {
+            InspectorTest.evaluateInPage("setTimeout(" + test + ", 50)");
+        }
+
+        WebInspector.debuggerManager.addEventListener(WebInspector.DebuggerManager.Event.ScriptAdded, function(event) {
+            var scriptObject = event.data.script;
+            if (!/break-on-exception-tests\.js$/.test(scriptObject.url))
+                return;
+
+            if (exceptionBreakType == 'AllExceptions')
+                WebInspector.debuggerManager.allExceptionsBreakpoint.disabled = false;
+            else
+                WebInspector.debuggerManager.allUncaughtExceptionsBreakpoint.disabled = false;
+
+            runTestCase(testName);
+        });
+
+        WebInspector.debuggerManager.addEventListener(WebInspector.DebuggerManager.Event.CallFramesDidChange, function(event) {
+            var callFrame = WebInspector.debuggerManager.activeCallFrame;
+            if (callFrame) {
+                // Pausing.
+                InspectorTest.assert(WebInspector.debuggerManager.pauseReason == "exception");
+
+                var funcName = callFrame.functionName || "<anonymous>";
+                var location = callFrame.sourceCodeLocation;
+                var line = location.lineNumber + 1;
+                var column = location.columnNumber + 1;
+
+                InspectorTest.log("PAUSE #" + (++pauses) + " AT: " + funcName + ":" + line + ":" + column);
+                WebInspector.debuggerManager.resume();
+
+            } else {
+                // Resuming.
+                if (resumeAction == 'FinishOnResume')
+                    InspectorTest.completeTest();
+            }
+        });
+
+        // This is a signal mechanism for the web process to tell us that the test is done.
+        // The web process fires the signal by doing console.log("DONE").
+        WebInspector.logManager.addEventListener(WebInspector.LogManager.Event.MessageAdded, function(event) {
+            var message = event.data.message;
+            if (!message.parameters || message.parameters.length !== 1)
+                return;
+            if (message.parameters[0].type !== "string" || message.parameters[0].description !== "DONE")
+                return;
+            InspectorTest.completeTest();
+        });
+
+        InspectorTest.reloadPage();
+    }
+
+    doExceptionTest('doThrow', 'UncaughtExceptions', 'IgnoreResume');
+}
+</script>
+</head>
+<body onload="runTest()">
+    <p>Checking pause locations when pausing on uncaught exceptions.</p>
+</body>
+</html>
diff --git a/LayoutTests/inspector/debugger/break-on-uncaught-exception.html b/LayoutTests/inspector/debugger/break-on-uncaught-exception.html
new file mode 100644 (file)
index 0000000..bc5a42e
--- /dev/null
@@ -0,0 +1,72 @@
+<!doctype html>
+<html>
+<head>
+<script type="text/javascript" src="../../http/tests/inspector/inspector-test.js"></script>
+<script type="text/javascript" src="./resources/break-on-exception-tests.js"></script>
+<script>
+function test() {
+    function doExceptionTest(testName, exceptionBreakType, resumeAction)
+    {
+        var pauses = 0;
+        var index = 0;
+
+        function runTestCase(test) {
+            InspectorTest.evaluateInPage("setTimeout(" + test + ", 50)");
+        }
+
+        WebInspector.debuggerManager.addEventListener(WebInspector.DebuggerManager.Event.ScriptAdded, function(event) {
+            var scriptObject = event.data.script;
+            if (!/break-on-exception-tests\.js$/.test(scriptObject.url))
+                return;
+
+            if (exceptionBreakType == 'AllExceptions')
+                WebInspector.debuggerManager.allExceptionsBreakpoint.disabled = false;
+            else
+                WebInspector.debuggerManager.allUncaughtExceptionsBreakpoint.disabled = false;
+
+            runTestCase(testName);
+        });
+
+        WebInspector.debuggerManager.addEventListener(WebInspector.DebuggerManager.Event.CallFramesDidChange, function(event) {
+            var callFrame = WebInspector.debuggerManager.activeCallFrame;
+            if (callFrame) {
+                // Pausing.
+                InspectorTest.assert(WebInspector.debuggerManager.pauseReason == "exception");
+
+                var funcName = callFrame.functionName || "<anonymous>";
+                var location = callFrame.sourceCodeLocation;
+                var line = location.lineNumber + 1;
+                var column = location.columnNumber + 1;
+
+                InspectorTest.log("PAUSE #" + (++pauses) + " AT: " + funcName + ":" + line + ":" + column);
+                WebInspector.debuggerManager.resume();
+
+            } else {
+                // Resuming.
+                if (resumeAction == 'FinishOnResume')
+                    InspectorTest.completeTest();
+            }
+        });
+
+        // This is a signal mechanism for the web process to tell us that the test is done.
+        // The web process fires the signal by doing console.log("DONE").
+        WebInspector.logManager.addEventListener(WebInspector.LogManager.Event.MessageAdded, function(event) {
+            var message = event.data.message;
+            if (!message.parameters || message.parameters.length !== 1)
+                return;
+            if (message.parameters[0].type !== "string" || message.parameters[0].description !== "DONE")
+                return;
+            InspectorTest.completeTest();
+        });
+
+        InspectorTest.reloadPage();
+    }
+
+    doExceptionTest('doThrow', 'UncaughtExceptions', 'IgnoreResume');
+}
+</script>
+</head>
+<body onload="runTest()">
+    <p>Checking pause locations when pausing on uncaught exceptions.</p>
+</body>
+</html>
diff --git a/LayoutTests/inspector/debugger/resources/break-on-exception-tests.js b/LayoutTests/inspector/debugger/resources/break-on-exception-tests.js
new file mode 100644 (file)
index 0000000..af95e42
--- /dev/null
@@ -0,0 +1,88 @@
+InspectorTestProxy.needToSanitizeUncaughtExceptionURLs = true;
+
+var arr = [ 1, 2, 3 ];
+var mapData = [[ "a", arr ]];
+
+function doThrow() {
+    console.log("throwing TestError");
+    throw "TestError";
+}
+
+function testCatch() {
+    console.log("testCatch");
+    try {
+        doThrow();
+    } catch (e) {
+        console.log("catch " + e);
+    }
+    console.log("DONE");
+}
+
+function testFinally() {
+    console.log("testFinally");
+    try {
+        doThrow();
+    } finally {
+        console.log("finally");
+    }
+}
+
+function testThrowingThruNativeCode() {
+    console.log("testThrowingThruNativeCode");
+    (new Map(mapData)).forEach(doThrow);
+}
+
+function testThrowingInPromise() {
+    console.log("testThrowingInPromise");
+    new Promise(function promise(resolve, reject) {
+        console.log("in promise");
+        doThrow();
+    });
+}
+
+function testThrowingInPromiseWithCatch() {
+    console.log("testThrowingInPromiseWithCatch");
+    new Promise(function promise(resolve, reject) {
+        console.log("in promise");
+        doThrow();
+    }).catch(function promiseCatch(e) {
+        console.log("in promise.catch");
+        console.log("DONE");
+    });
+}
+
+function testThrowingInPromiseThen() {
+    console.log("testThrowingInPromiseThen");
+    new Promise(function promise(resolve, reject) {
+        console.log("in promise");
+        resolve();
+    }).then(function promiseThen(x) {
+        console.log("in promise.then");
+        doThrow();
+    });
+}
+
+function testThrowingInPromiseThenWithCatch() {
+    console.log("testThrowingInPromiseThenWithCatch");
+    new Promise(function promise(resolve, reject) {
+        console.log("in promise");
+        resolve();
+    }).then(function promiseThen(x) {
+        console.log("in promise.then");
+        doThrow();
+    }).catch(function promiseCatch(e) {
+        console.log("in promise.catch");
+        console.log("DONE");
+    });
+}
+
+function testThrowingInPromiseWithRethrowInCatch() {
+    console.log("testThrowingInPromiseWithRethrowInCatch");
+    new Promise(function promise(resolve, reject) {
+        console.log("in promise");
+        doThrow();
+    }).catch(function promiseCatch(e) {
+        console.log("in promise.catch");
+        throw e;
+    });
+}
index 0325fec..cc8282c 100644 (file)
@@ -30,6 +30,7 @@
 #include "APICast.h"
 #include "CallFrame.h"
 #include "Completion.h"
+#include "Exception.h"
 #include "GCActivityCallback.h"
 #include "InitializeThreading.h"
 #include "JSGlobalObject.h"
@@ -63,12 +64,12 @@ JSValueRef JSEvaluateScript(JSContextRef ctx, JSStringRef script, JSObjectRef th
     JSGlobalObject* globalObject = exec->vmEntryGlobalObject();
     SourceCode source = makeSource(script->string(), sourceURL ? sourceURL->string() : String(), TextPosition(OrdinalNumber::fromOneBasedInt(startingLineNumber), OrdinalNumber::first()));
 
-    JSValue evaluationException;
-    JSValue returnValue = evaluate(globalObject->globalExec(), source, jsThisObject, &evaluationException);
+    Exception* evaluationException;
+    JSValue returnValue = evaluate(globalObject->globalExec(), source, jsThisObject, evaluationException);
 
     if (evaluationException) {
         if (exception)
-            *exception = toRef(exec, evaluationException);
+            *exception = toRef(exec, evaluationException->value());
 #if ENABLE(REMOTE_INSPECTOR)
         // FIXME: If we have a debugger attached we could learn about ParseError exceptions through
         // ScriptDebugServer::sourceParsed and this path could produce a duplicate warning. The
@@ -107,7 +108,8 @@ bool JSCheckScriptSyntax(JSContextRef ctx, JSStringRef script, JSStringRef sourc
         if (exception)
             *exception = toRef(exec, syntaxException);
 #if ENABLE(REMOTE_INSPECTOR)
-        exec->vmEntryGlobalObject()->inspectorController().reportAPIException(exec, syntaxException);
+        Exception* exception = Exception::create(exec->vm(), syntaxException);
+        exec->vmEntryGlobalObject()->inspectorController().reportAPIException(exec, exception);
 #endif
         return false;
     }
index a284c9f..faf38ff 100644 (file)
@@ -34,6 +34,7 @@
 #include "CopiedSpaceInlines.h"
 #include "DateConstructor.h"
 #include "ErrorConstructor.h"
+#include "Exception.h"
 #include "FunctionConstructor.h"
 #include "Identifier.h"
 #include "InitializeThreading.h"
 
 using namespace JSC;
 
+enum class ExceptionStatus {
+    DidThrow,
+    DidNotThrow
+};
+
+static ExceptionStatus handleExceptionIfNeeded(ExecState* exec, JSValueRef* returnedExceptionRef)
+{
+    if (exec->hadException()) {
+        Exception* exception = exec->exception();
+        if (returnedExceptionRef)
+            *returnedExceptionRef = toRef(exec, exception->value());
+        exec->clearException();
+#if ENABLE(REMOTE_INSPECTOR)
+        exec->vmEntryGlobalObject()->inspectorController().reportAPIException(exec, exception);
+#endif
+        return ExceptionStatus::DidThrow;
+    }
+    return ExceptionStatus::DidNotThrow;
+}
+
 JSClassRef JSClassCreate(const JSClassDefinition* definition)
 {
     initializeThreading();
@@ -148,16 +169,8 @@ JSObjectRef JSObjectMakeFunction(JSContextRef ctx, JSStringRef name, unsigned pa
     args.append(jsString(exec, body->string()));
 
     JSObject* result = constructFunction(exec, exec->lexicalGlobalObject(), args, nameID, sourceURL ? sourceURL->string() : String(), TextPosition(OrdinalNumber::fromOneBasedInt(startingLineNumber), OrdinalNumber::first()));
-    if (exec->hadException()) {
-        JSValue exceptionValue = exec->exception();
-        if (exception)
-            *exception = toRef(exec, exceptionValue);
-        exec->clearException();
-#if ENABLE(REMOTE_INSPECTOR)
-        exec->vmEntryGlobalObject()->inspectorController().reportAPIException(exec, exceptionValue);
-#endif
+    if (handleExceptionIfNeeded(exec, exception) == ExceptionStatus::DidThrow)
         result = 0;
-    }
     return toRef(result);
 }
 
@@ -180,16 +193,8 @@ JSObjectRef JSObjectMakeArray(JSContextRef ctx, size_t argumentCount, const JSVa
     } else
         result = constructEmptyArray(exec, 0);
 
-    if (exec->hadException()) {
-        JSValue exceptionValue = exec->exception();
-        if (exception)
-            *exception = toRef(exec, exceptionValue);
-        exec->clearException();
-#if ENABLE(REMOTE_INSPECTOR)
-        exec->vmEntryGlobalObject()->inspectorController().reportAPIException(exec, exceptionValue);
-#endif
+    if (handleExceptionIfNeeded(exec, exception) == ExceptionStatus::DidThrow)
         result = 0;
-    }
 
     return toRef(result);
 }
@@ -208,16 +213,8 @@ JSObjectRef JSObjectMakeDate(JSContextRef ctx, size_t argumentCount, const JSVal
         argList.append(toJS(exec, arguments[i]));
 
     JSObject* result = constructDate(exec, exec->lexicalGlobalObject(), argList);
-    if (exec->hadException()) {
-        JSValue exceptionValue = exec->exception();
-        if (exception)
-            *exception = toRef(exec, exceptionValue);
-        exec->clearException();
-#if ENABLE(REMOTE_INSPECTOR)
-        exec->vmEntryGlobalObject()->inspectorController().reportAPIException(exec, exceptionValue);
-#endif
+    if (handleExceptionIfNeeded(exec, exception) == ExceptionStatus::DidThrow)
         result = 0;
-    }
 
     return toRef(result);
 }
@@ -235,16 +232,8 @@ JSObjectRef JSObjectMakeError(JSContextRef ctx, size_t argumentCount, const JSVa
     Structure* errorStructure = exec->lexicalGlobalObject()->errorStructure();
     JSObject* result = ErrorInstance::create(exec, errorStructure, message);
 
-    if (exec->hadException()) {
-        JSValue exceptionValue = exec->exception();
-        if (exception)
-            *exception = toRef(exec, exceptionValue);
-        exec->clearException();
-#if ENABLE(REMOTE_INSPECTOR)
-        exec->vmEntryGlobalObject()->inspectorController().reportAPIException(exec, exceptionValue);
-#endif
+    if (handleExceptionIfNeeded(exec, exception) == ExceptionStatus::DidThrow)
         result = 0;
-    }
 
     return toRef(result);
 }
@@ -263,16 +252,8 @@ JSObjectRef JSObjectMakeRegExp(JSContextRef ctx, size_t argumentCount, const JSV
         argList.append(toJS(exec, arguments[i]));
 
     JSObject* result = constructRegExp(exec, exec->lexicalGlobalObject(),  argList);
-    if (exec->hadException()) {
-        JSValue exceptionValue = exec->exception();
-        if (exception)
-            *exception = toRef(exec, exceptionValue);
-        exec->clearException();
-#if ENABLE(REMOTE_INSPECTOR)
-        exec->vmEntryGlobalObject()->inspectorController().reportAPIException(exec, exceptionValue);
-#endif
+    if (handleExceptionIfNeeded(exec, exception) == ExceptionStatus::DidThrow)
         result = 0;
-    }
     
     return toRef(result);
 }
@@ -339,15 +320,7 @@ JSValueRef JSObjectGetProperty(JSContextRef ctx, JSObjectRef object, JSStringRef
     JSObject* jsObject = toJS(object);
 
     JSValue jsValue = jsObject->get(exec, propertyName->identifier(&exec->vm()));
-    if (exec->hadException()) {
-        JSValue exceptionValue = exec->exception();
-        if (exception)
-            *exception = toRef(exec, exceptionValue);
-        exec->clearException();
-#if ENABLE(REMOTE_INSPECTOR)
-        exec->vmEntryGlobalObject()->inspectorController().reportAPIException(exec, exceptionValue);
-#endif
-    }
+    handleExceptionIfNeeded(exec, exception);
     return toRef(exec, jsValue);
 }
 
@@ -372,15 +345,7 @@ void JSObjectSetProperty(JSContextRef ctx, JSObjectRef object, JSStringRef prope
         jsObject->methodTable()->put(jsObject, exec, name, jsValue, slot);
     }
 
-    if (exec->hadException()) {
-        JSValue exceptionValue = exec->exception();
-        if (exception)
-            *exception = toRef(exec, exceptionValue);
-        exec->clearException();
-#if ENABLE(REMOTE_INSPECTOR)
-        exec->vmEntryGlobalObject()->inspectorController().reportAPIException(exec, exceptionValue);
-#endif
-    }
+    handleExceptionIfNeeded(exec, exception);
 }
 
 JSValueRef JSObjectGetPropertyAtIndex(JSContextRef ctx, JSObjectRef object, unsigned propertyIndex, JSValueRef* exception)
@@ -395,15 +360,7 @@ JSValueRef JSObjectGetPropertyAtIndex(JSContextRef ctx, JSObjectRef object, unsi
     JSObject* jsObject = toJS(object);
 
     JSValue jsValue = jsObject->get(exec, propertyIndex);
-    if (exec->hadException()) {
-        JSValue exceptionValue = exec->exception();
-        if (exception)
-            *exception = toRef(exec, exceptionValue);
-        exec->clearException();
-#if ENABLE(REMOTE_INSPECTOR)
-        exec->vmEntryGlobalObject()->inspectorController().reportAPIException(exec, exceptionValue);
-#endif
-    }
+    handleExceptionIfNeeded(exec, exception);
     return toRef(exec, jsValue);
 }
 
@@ -421,15 +378,7 @@ void JSObjectSetPropertyAtIndex(JSContextRef ctx, JSObjectRef object, unsigned p
     JSValue jsValue = toJS(exec, value);
     
     jsObject->methodTable()->putByIndex(jsObject, exec, propertyIndex, jsValue, false);
-    if (exec->hadException()) {
-        JSValue exceptionValue = exec->exception();
-        if (exception)
-            *exception = toRef(exec, exceptionValue);
-        exec->clearException();
-#if ENABLE(REMOTE_INSPECTOR)
-        exec->vmEntryGlobalObject()->inspectorController().reportAPIException(exec, exceptionValue);
-#endif
-    }
+    handleExceptionIfNeeded(exec, exception);
 }
 
 bool JSObjectDeleteProperty(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName, JSValueRef* exception)
@@ -444,15 +393,7 @@ bool JSObjectDeleteProperty(JSContextRef ctx, JSObjectRef object, JSStringRef pr
     JSObject* jsObject = toJS(object);
 
     bool result = jsObject->methodTable()->deleteProperty(jsObject, exec, propertyName->identifier(&exec->vm()));
-    if (exec->hadException()) {
-        JSValue exceptionValue = exec->exception();
-        if (exception)
-            *exception = toRef(exec, exceptionValue);
-        exec->clearException();
-#if ENABLE(REMOTE_INSPECTOR)
-        exec->vmEntryGlobalObject()->inspectorController().reportAPIException(exec, exceptionValue);
-#endif
-    }
+    handleExceptionIfNeeded(exec, exception);
     return result;
 }
 
@@ -616,16 +557,8 @@ JSValueRef JSObjectCallAsFunction(JSContextRef ctx, JSObjectRef object, JSObject
         return 0;
 
     JSValueRef result = toRef(exec, call(exec, jsObject, callType, callData, jsThisObject, argList));
-    if (exec->hadException()) {
-        JSValue exceptionValue = exec->exception();
-        if (exception)
-            *exception = toRef(exec, exceptionValue);
-        exec->clearException();
-#if ENABLE(REMOTE_INSPECTOR)
-        exec->vmEntryGlobalObject()->inspectorController().reportAPIException(exec, exceptionValue);
-#endif
+    if (handleExceptionIfNeeded(exec, exception) == ExceptionStatus::DidThrow)
         result = 0;
-    }
     return result;
 }
 
@@ -657,16 +590,8 @@ JSObjectRef JSObjectCallAsConstructor(JSContextRef ctx, JSObjectRef object, size
     for (size_t i = 0; i < argumentCount; i++)
         argList.append(toJS(exec, arguments[i]));
     JSObjectRef result = toRef(construct(exec, jsObject, constructType, constructData, argList));
-    if (exec->hadException()) {
-        JSValue exceptionValue = exec->exception();
-        if (exception)
-            *exception = toRef(exec, exceptionValue);
-        exec->clearException();
-#if ENABLE(REMOTE_INSPECTOR)
-        exec->vmEntryGlobalObject()->inspectorController().reportAPIException(exec, exceptionValue);
-#endif
+    if (handleExceptionIfNeeded(exec, exception) == ExceptionStatus::DidThrow)
         result = 0;
-    }
     return result;
 }
 
index fb90a93..99d7f31 100644 (file)
@@ -27,6 +27,7 @@
 
 #include "APICast.h"
 #include "Completion.h"
+#include "Exception.h"
 #include "JSBasePrivate.h"
 #include "VM.h"
 #include "JSScriptRefPrivate.h"
@@ -142,12 +143,12 @@ JSValueRef JSScriptEvaluate(JSContextRef context, JSScriptRef script, JSValueRef
         RELEASE_ASSERT_NOT_REACHED();
         return 0;
     }
-    JSValue internalException;
+    Exception* internalException;
     JSValue thisValue = thisValueRef ? toJS(exec, thisValueRef) : jsUndefined();
-    JSValue result = evaluate(exec, SourceCode(script), thisValue, &internalException);
+    JSValue result = evaluate(exec, SourceCode(script), thisValue, internalException);
     if (internalException) {
         if (exception)
-            *exception = toRef(exec, internalException);
+            *exception = toRef(exec, internalException->value());
         return 0;
     }
     ASSERT(result);
index 126c90f..11be6b6 100644 (file)
@@ -28,6 +28,7 @@
 #import "APICast.h"
 #import "DateInstance.h"
 #import "Error.h"
+#import "Exception.h"
 #import "JavaScriptCore.h"
 #import "JSContextInternal.h"
 #import "JSVirtualMachineInternal.h"
@@ -645,9 +646,10 @@ JSContainerConvertor::Task JSContainerConvertor::take()
 }
 
 #if ENABLE(REMOTE_INSPECTOR)
-static void reportExceptionToInspector(JSGlobalContextRef context, JSC::JSValue exception)
+static void reportExceptionToInspector(JSGlobalContextRef context, JSC::JSValue exceptionValue)
 {
     JSC::ExecState* exec = toJS(context);
+    JSC::Exception* exception = JSC::Exception::create(exec->vm(), exceptionValue);
     exec->vmEntryGlobalObject()->inspectorController().reportAPIException(exec, exception);
 }
 #endif
index 0619e39..759a65a 100644 (file)
@@ -28,6 +28,7 @@
 
 #include "APICast.h"
 #include "DateInstance.h"
+#include "Exception.h"
 #include "JSAPIWrapperObject.h"
 #include "JSCInlines.h"
 #include "JSCJSValue.h"
 
 using namespace JSC;
 
+enum class ExceptionStatus {
+    DidThrow,
+    DidNotThrow
+};
+
+static ExceptionStatus handleExceptionIfNeeded(ExecState* exec, JSValueRef* returnedExceptionRef)
+{
+    if (exec->hadException()) {
+        Exception* exception = exec->exception();
+        if (returnedExceptionRef)
+            *returnedExceptionRef = toRef(exec, exception->value());
+        exec->clearException();
+#if ENABLE(REMOTE_INSPECTOR)
+        exec->vmEntryGlobalObject()->inspectorController().reportAPIException(exec, exception);
+#endif
+        return ExceptionStatus::DidThrow;
+    }
+    return ExceptionStatus::DidNotThrow;
+}
+
 #if PLATFORM(MAC)
 static bool evernoteHackNeeded()
 {
@@ -224,15 +245,8 @@ bool JSValueIsEqual(JSContextRef ctx, JSValueRef a, JSValueRef b, JSValueRef* ex
     JSValue jsB = toJS(exec, b);
 
     bool result = JSValue::equal(exec, jsA, jsB); // false if an exception is thrown
-    if (exec->hadException()) {
-        JSValue exceptionValue = exec->exception();
-        if (exception)
-            *exception = toRef(exec, exceptionValue);
-        exec->clearException();
-#if ENABLE(REMOTE_INSPECTOR)
-        exec->vmEntryGlobalObject()->inspectorController().reportAPIException(exec, exceptionValue);
-#endif
-    }
+    handleExceptionIfNeeded(exec, exception);
+    
     return result;
 }
 
@@ -266,15 +280,7 @@ bool JSValueIsInstanceOfConstructor(JSContextRef ctx, JSValueRef value, JSObject
     if (!jsConstructor->structure()->typeInfo().implementsHasInstance())
         return false;
     bool result = jsConstructor->hasInstance(exec, jsValue); // false if an exception is thrown
-    if (exec->hadException()) {
-        JSValue exceptionValue = exec->exception();
-        if (exception)
-            *exception = toRef(exec, exceptionValue);
-        exec->clearException();
-#if ENABLE(REMOTE_INSPECTOR)
-        exec->vmEntryGlobalObject()->inspectorController().reportAPIException(exec, exceptionValue);
-#endif
-    }
+    handleExceptionIfNeeded(exec, exception);
     return result;
 }
 
@@ -368,16 +374,8 @@ JSStringRef JSValueCreateJSONString(JSContextRef ctx, JSValueRef apiValue, unsig
     String result = JSONStringify(exec, value, indent);
     if (exception)
         *exception = 0;
-    if (exec->hadException()) {
-        JSValue exceptionValue = exec->exception();
-        if (exception)
-            *exception = toRef(exec, exceptionValue);
-        exec->clearException();
-#if ENABLE(REMOTE_INSPECTOR)
-        exec->vmEntryGlobalObject()->inspectorController().reportAPIException(exec, exceptionValue);
-#endif
+    if (handleExceptionIfNeeded(exec, exception) == ExceptionStatus::DidThrow)
         return 0;
-    }
     return OpaqueJSString::create(result).leakRef();
 }
 
@@ -406,16 +404,8 @@ double JSValueToNumber(JSContextRef ctx, JSValueRef value, JSValueRef* exception
     JSValue jsValue = toJS(exec, value);
 
     double number = jsValue.toNumber(exec);
-    if (exec->hadException()) {
-        JSValue exceptionValue = exec->exception();
-        if (exception)
-            *exception = toRef(exec, exceptionValue);
-        exec->clearException();
-#if ENABLE(REMOTE_INSPECTOR)
-        exec->vmEntryGlobalObject()->inspectorController().reportAPIException(exec, exceptionValue);
-#endif
+    if (handleExceptionIfNeeded(exec, exception) == ExceptionStatus::DidThrow)
         number = PNaN;
-    }
     return number;
 }
 
@@ -431,16 +421,8 @@ JSStringRef JSValueToStringCopy(JSContextRef ctx, JSValueRef value, JSValueRef*
     JSValue jsValue = toJS(exec, value);
     
     RefPtr<OpaqueJSString> stringRef(OpaqueJSString::create(jsValue.toString(exec)->value(exec)));
-    if (exec->hadException()) {
-        JSValue exceptionValue = exec->exception();
-        if (exception)
-            *exception = toRef(exec, exceptionValue);
-        exec->clearException();
-#if ENABLE(REMOTE_INSPECTOR)
-        exec->vmEntryGlobalObject()->inspectorController().reportAPIException(exec, exceptionValue);
-#endif
+    if (handleExceptionIfNeeded(exec, exception) == ExceptionStatus::DidThrow)
         stringRef.clear();
-    }
     return stringRef.release().leakRef();
 }
 
@@ -456,16 +438,8 @@ JSObjectRef JSValueToObject(JSContextRef ctx, JSValueRef value, JSValueRef* exce
     JSValue jsValue = toJS(exec, value);
     
     JSObjectRef objectRef = toRef(jsValue.toObject(exec));
-    if (exec->hadException()) {
-        JSValue exceptionValue = exec->exception();
-        if (exception)
-            *exception = toRef(exec, exceptionValue);
-        exec->clearException();
-#if ENABLE(REMOTE_INSPECTOR)
-        exec->vmEntryGlobalObject()->inspectorController().reportAPIException(exec, exceptionValue);
-#endif
+    if (handleExceptionIfNeeded(exec, exception) == ExceptionStatus::DidThrow)
         objectRef = 0;
-    }
     return objectRef;
 }
 
index 203f540..d34d3c3 100644 (file)
@@ -454,6 +454,7 @@ set(JavaScriptCore_RUNTIME_SOURCES
     runtime/ErrorHandlingScope.cpp
     runtime/ErrorInstance.cpp
     runtime/ErrorPrototype.cpp
+    runtime/Exception.cpp
     runtime/ExceptionFuzz.cpp
     runtime/ExceptionHelpers.cpp
     runtime/Executable.cpp
index 2339d12..4a4588a 100644 (file)
@@ -1,3 +1,331 @@
+2015-06-05  Mark Lam  <mark.lam@apple.com>
+
+        finally blocks should not set the exception stack trace when re-throwing the exception.
+        https://bugs.webkit.org/show_bug.cgi?id=145525
+
+        Reviewed by Geoffrey Garen.
+
+        How exceptions presently work:
+        =============================
+        1. op_throw can throw any JSValue.
+        2. the VM tries to capture the stack at the throw point and propagate that as needed.
+        3. finally blocks are implemented using op_catch to catch the thrown value, and throws it again using op_throw.
+
+        What's wrong with how it presently works:
+        ========================================
+        1. finally's makes for bad exception throw line numbers in the Inspector console.
+
+           The op_throw in finally will throw the value anew i.e. it captures a stack from the re-throw point.
+           As a result, the Inspector sees the finally block as the throw point.  The original stack is lost.
+
+        2. finally's breaks the Inspector's "Breaks on Uncaught Exception"
+
+           This is because finally blocks are indistinguishable from catch blocks.  As a result, a try-finally,
+           which should break in the Inspector on the throw, does not because the Inspector thought the
+           exception was "caught".
+
+        3. finally's yields confusing break points when the Inspector "Breaks on All Exceptions"
+
+           a. In a try-finally scenario, the Inspector breaks 2 times: 1 at the throw, 1 at the finally.
+           b. In a for-of loop (which has synthesized finallys), the Inspector will do another break.
+              Similarly for other cases of JS code which synthesize finallys.
+           c. At VM re-entry boundaries (e.g. js throws & returns to native code, which returns to js),
+              the Inspector will do another break if there's an uncaught exception.
+
+        How this patch fixes the issues:
+        ===============================
+        1. We introduce an Exception object that wraps the thrown value and the exception stack.
+
+           When throwing an exception, the VM will check if the thrown value is an Exception
+           object or not.  If it is not an Exception object, then we must be throwing a new
+           exception.  The VM will create an Exception object to wrap the thrown value and
+           capture the current stack for it.
+
+           If the thrown value is already an Exception object, then the requested throw operation
+           must be a re-throw.  The VM will not capture a new stack for it.
+
+        2. op_catch will now populate 2 locals: 1 for the Exception, 1 for the thrown JSValue.
+
+           The VM is aware of the Exception object and uses it for rethrows in finally blocks.
+           JS source code is never aware of the Exception object.
+
+           JS code is aware of the thrown value.  If it throws the caught thrown value, that
+           constitutes a new throw, and a new Exception object will be created for it.
+
+        3. The VM no longer tracks the thrown JSValue and the exception stack.  It will only
+           track a m_exception field which is an Exception*.
+
+        4. The BytecodeGenerator has already been updated in a prior patch to distinguish
+           between Catch, Finally, and SynthesizedFinally blocks.  The interpreter runtime will
+           now report to the debugger whether we have a Catch handler, not just any handlers.
+
+           The debugger will use this detail to determine whether to break or not.  "Break on
+           uncaught exceptions" will only break if no Catch handler was found.
+
+           This solves the issue of the debugger breaking at finally blocks, and for-of statements.
+
+        5. The Exception object will also have a flag to indicate whether the debugger has been
+           notified of the Exception being thrown.  Once the Interpreter notifies the debugger
+           of the Exception object, it will mark this flag and not repeat the notify the debugger
+           again of the same Exception.
+
+           This solves the issue of the debugger breaking at VM re-entry points due to uncaught
+           exceptions.
+
+        6. The life-cycle of the captured exception stack trace will now follow the life-cycle
+           of the Exception object.
+
+        Other changes:
+        7. Change all clients of the VM::exception() to expect an Exception* instead of JSValue.
+
+        8. Fixed a few bugs where thrown exceptions are not cleared before exiting the VM.
+
+        9. Also renamed some variables and classes to better describe what they are.
+
+        * API/JSBase.cpp:
+        (JSEvaluateScript):
+        (JSCheckScriptSyntax):
+
+        * API/JSObjectRef.cpp:
+        (handleExceptionIfNeeded):
+        - The functions below all do the same exception check.  Added this helper
+          to simplify the code.
+        (JSClassCreate):
+        (JSObjectMakeFunction):
+        (JSObjectMakeArray):
+        (JSObjectMakeDate):
+        (JSObjectMakeError):
+        (JSObjectMakeRegExp):
+        (JSObjectGetProperty):
+        (JSObjectSetProperty):
+        (JSObjectGetPropertyAtIndex):
+        (JSObjectSetPropertyAtIndex):
+        (JSObjectDeleteProperty):
+        (JSObjectCallAsFunction):
+        (JSObjectCallAsConstructor):
+
+        * API/JSScriptRef.cpp:
+        * API/JSValue.mm:
+        (JSContainerConvertor::take):
+        (reportExceptionToInspector):
+
+        * API/JSValueRef.cpp:
+        (handleExceptionIfNeeded):
+        - The functions below all do the same exception check.  Added this helper
+          to simplify the code.
+        (evernoteHackNeeded):
+        (JSValueIsEqual):
+        (JSValueIsInstanceOfConstructor):
+        (JSValueCreateJSONString):
+        (JSValueToNumber):
+        (JSValueToStringCopy):
+        (JSValueToObject):
+
+        * CMakeLists.txt:
+        * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj:
+        * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters:
+        * JavaScriptCore.xcodeproj/project.pbxproj:
+        - Added new files Exception.h and Exception.cpp.
+
+        * bindings/ScriptFunctionCall.cpp:
+        (Deprecated::ScriptFunctionCall::call):
+        * bindings/ScriptFunctionCall.h:
+
+        * bytecode/BytecodeList.json:
+        - op_catch now had 2 operands: the exception register, and the thrown value register.
+
+        * bytecode/BytecodeUseDef.h:
+        (JSC::computeDefsForBytecodeOffset):
+        * bytecode/CodeBlock.cpp:
+        (JSC::CodeBlock::dumpBytecode):
+        (JSC::CodeBlock::handlerForBytecodeOffset):
+        * bytecode/CodeBlock.h:
+        - handlerForBytecodeOffset() now can look for just Catch handlers only.
+
+        * bytecode/HandlerInfo.h:
+        - Cleaned up some white space I accidentally added in a previous patch.
+
+        * bytecompiler/BytecodeGenerator.cpp:
+        (JSC::BytecodeGenerator::pushTry):
+        (JSC::BytecodeGenerator::popTryAndEmitCatch):
+        (JSC::BytecodeGenerator::emitThrowReferenceError):
+        (JSC::BytecodeGenerator::emitEnumeration):
+        * bytecompiler/BytecodeGenerator.h:
+        (JSC::BytecodeGenerator::emitThrow):
+        * bytecompiler/NodesCodegen.cpp:
+        (JSC::TryNode::emitBytecode):
+        - Adding support for op_catch's 2 operands.
+
+        * debugger/Debugger.cpp:
+        (JSC::Debugger::hasBreakpoint):
+        (JSC::Debugger::pauseIfNeeded):
+        (JSC::Debugger::exception):
+        * debugger/Debugger.h:
+        * debugger/DebuggerCallFrame.cpp:
+        (JSC::DebuggerCallFrame::thisValue):
+        (JSC::DebuggerCallFrame::evaluate):
+        * debugger/DebuggerCallFrame.h:
+        (JSC::DebuggerCallFrame::isValid):
+        * inspector/InjectedScriptManager.cpp:
+        (Inspector::InjectedScriptManager::createInjectedScript):
+        * inspector/InspectorEnvironment.h:
+        * inspector/JSGlobalObjectInspectorController.cpp:
+        (Inspector::JSGlobalObjectInspectorController::appendAPIBacktrace):
+        (Inspector::JSGlobalObjectInspectorController::reportAPIException):
+        * inspector/JSGlobalObjectInspectorController.h:
+        * inspector/JSGlobalObjectScriptDebugServer.h:
+        * inspector/JSJavaScriptCallFrame.cpp:
+        (Inspector::JSJavaScriptCallFrame::evaluate):
+        * inspector/JavaScriptCallFrame.h:
+        (Inspector::JavaScriptCallFrame::vmEntryGlobalObject):
+        (Inspector::JavaScriptCallFrame::thisValue):
+        (Inspector::JavaScriptCallFrame::evaluate):
+        * inspector/ScriptCallStackFactory.cpp:
+        (Inspector::extractSourceInformationFromException):
+        (Inspector::createScriptCallStackFromException):
+        * inspector/ScriptCallStackFactory.h:
+        * inspector/ScriptDebugServer.cpp:
+        (Inspector::ScriptDebugServer::evaluateBreakpointAction):
+        (Inspector::ScriptDebugServer::handleBreakpointHit):
+        (Inspector::ScriptDebugServer::handleExceptionInBreakpointCondition):
+        * inspector/ScriptDebugServer.h:
+        * interpreter/CallFrame.h:
+        (JSC::ExecState::clearException):
+        (JSC::ExecState::exception):
+        (JSC::ExecState::hadException):
+        (JSC::ExecState::atomicStringTable):
+        (JSC::ExecState::propertyNames):
+        (JSC::ExecState::clearSupplementaryExceptionInfo): Deleted.
+
+        * interpreter/Interpreter.cpp:
+        (JSC::unwindCallFrame):
+        (JSC::Interpreter::stackTraceAsString):
+        (JSC::GetCatchHandlerFunctor::GetCatchHandlerFunctor):
+        (JSC::GetCatchHandlerFunctor::operator()):
+        (JSC::Interpreter::unwind):
+        - Added a check for didNotifyInspectorOfThrow() here to prevent duplicate reports
+          of the same Exception to the debugger.
+
+        (JSC::GetExceptionHandlerFunctor::GetExceptionHandlerFunctor): Deleted.
+        (JSC::GetExceptionHandlerFunctor::operator()): Deleted.
+        - Renamed GetExceptionHandlerFunctor to GetCatchHandlerFunctor since the debugger
+          is only interested in knowing whether we have Catch handlers.
+
+        * interpreter/Interpreter.h:
+        (JSC::SuspendExceptionScope::SuspendExceptionScope):
+        (JSC::SuspendExceptionScope::~SuspendExceptionScope):
+        (JSC::Interpreter::sampler):
+        (JSC::ClearExceptionScope::ClearExceptionScope): Deleted.
+        (JSC::ClearExceptionScope::~ClearExceptionScope): Deleted.
+        - Renamed ClearExceptionScope to SuspendExceptionScope because "clear" implies that
+          we're purging the exception.  Instead, we're merely suspending any handling of
+          that exception for a period defined by the scope.
+
+        * jit/AssemblyHelpers.cpp:
+        (JSC::AssemblyHelpers::emitExceptionCheck):
+
+        * jit/JITExceptions.cpp:
+        (JSC::genericUnwind):
+        - Removed the exception argument.  It is always the value in VM::exception() anyway.
+          genericUnwind() can just get it from the VM, and save everyone some work.
+
+        * jit/JITExceptions.h:
+        * jit/JITOpcodes.cpp:
+        (JSC::JIT::emit_op_catch):
+        * jit/JITOpcodes32_64.cpp:
+        (JSC::JIT::privateCompileCTINativeCall):
+        (JSC::JIT::emit_op_catch):
+        - Add support for the new op_catch operands.
+
+        * jit/JITOperations.cpp:
+        * jit/ThunkGenerators.cpp:
+        (JSC::nativeForGenerator):
+        * jsc.cpp:
+        (functionRun):
+        (functionLoad):
+        (runWithScripts):
+        (runInteractive):
+        * llint/LLIntOffsetsExtractor.cpp:
+        * llint/LLIntSlowPaths.cpp:
+        (JSC::LLInt::LLINT_SLOW_PATH_DECL):
+
+        * llint/LowLevelInterpreter32_64.asm:
+        * llint/LowLevelInterpreter64.asm:
+        - Add support for the new op_catch operands.  Also update the code to handle
+          VM::m_exception being an Exception pointer, not a JSValue.
+
+        * parser/NodeConstructors.h:
+        (JSC::TryNode::TryNode):
+        * parser/Nodes.h:
+        * runtime/CallData.cpp:
+        (JSC::call):
+        * runtime/CallData.h:
+
+        * runtime/Completion.cpp:
+        (JSC::evaluate):
+        * runtime/Completion.h:
+        (JSC::evaluate):
+        - Change evaluate() to take a reference to the returned exception value instead
+          of a pointer.  In all but 2 or 3 cases, we want the returned exception anyway.
+          Might as well simplify the code by requiring the reference.
+
+        * runtime/Error.h:
+        (JSC::throwVMError):
+        (JSC::throwVMTypeError):
+
+        * runtime/Exception.cpp: Added.
+        (JSC::Exception::create):
+        (JSC::Exception::destroy):
+        (JSC::Exception::createStructure):
+        (JSC::Exception::visitChildren):
+        (JSC::Exception::Exception):
+        (JSC::Exception::~Exception):
+        * runtime/Exception.h: Added.
+        (JSC::Exception::valueOffset):
+        (JSC::Exception::cast):
+        (JSC::Exception::value):
+        (JSC::Exception::stack):
+        (JSC::Exception::didNotifyInspectorOfThrow):
+        (JSC::Exception::setDidNotifyInspectorOfThrow):
+
+        * runtime/ExceptionHelpers.cpp:
+        (JSC::createTerminatedExecutionException):
+        (JSC::isTerminatedExecutionException):
+        (JSC::createStackOverflowError):
+        * runtime/ExceptionHelpers.h:
+        * runtime/GetterSetter.cpp:
+        (JSC::callGetter):
+        * runtime/IteratorOperations.cpp:
+        (JSC::iteratorClose):
+        * runtime/JSObject.cpp:
+        * runtime/JSPromiseConstructor.cpp:
+        (JSC::constructPromise):
+        * runtime/JSPromiseDeferred.cpp:
+        (JSC::updateDeferredFromPotentialThenable):
+        (JSC::abruptRejection):
+        * runtime/JSPromiseReaction.cpp:
+        (JSC::ExecutePromiseReactionMicrotask::run):
+
+        * runtime/VM.cpp:
+        (JSC::VM::VM):
+        (JSC::VM::releaseExecutableMemory):
+        (JSC::VM::throwException):
+        (JSC::VM::setStackPointerAtVMEntry):
+        (JSC::VM::getExceptionInfo): Deleted.
+        (JSC::VM::setExceptionInfo): Deleted.
+        (JSC::VM::clearException): Deleted.
+        (JSC::clearExceptionStack): Deleted.
+        * runtime/VM.h:
+        (JSC::VM::targetMachinePCForThrowOffset):
+        (JSC::VM::clearException):
+        (JSC::VM::setException):
+        (JSC::VM::exception):
+        (JSC::VM::addressOfException):
+        (JSC::VM::exceptionStack): Deleted.
+        * runtime/VMEntryScope.cpp:
+        (JSC::VMEntryScope::VMEntryScope):
+        (JSC::VMEntryScope::setEntryScopeDidPopListener):
+
 2015-06-04  Benjamin Poulain  <bpoulain@apple.com>
 
         [JSC] Always track out-of-bounds array access explicitly instead of relying on the slow case
index 36cc737..6c3066a 100644 (file)
     <ClCompile Include="..\runtime\ErrorHandlingScope.cpp" />
     <ClCompile Include="..\runtime\ErrorInstance.cpp" />
     <ClCompile Include="..\runtime\ErrorPrototype.cpp" />
+    <ClCompile Include="..\runtime\Exception.cpp" />
     <ClCompile Include="..\runtime\ExceptionFuzz.cpp" />
     <ClCompile Include="..\runtime\ExceptionHelpers.cpp" />
     <ClCompile Include="..\runtime\Executable.cpp" />
     <ClInclude Include="..\runtime\ErrorHandlingScope.h" />
     <ClInclude Include="..\runtime\ErrorInstance.h" />
     <ClInclude Include="..\runtime\ErrorPrototype.h" />
+    <ClInclude Include="..\runtime\Exception.h" />
     <ClInclude Include="..\runtime\ExceptionFuzz.h" />
     <ClInclude Include="..\runtime\ExceptionHelpers.h" />
     <ClInclude Include="..\runtime\Executable.h" />
   <ImportGroup Label="ExtensionTargets">
     <Import Project="$(VCTargetsPath)\BuildCustomizations\masm.targets" />
   </ImportGroup>
-</Project>
\ No newline at end of file
+</Project>
index 93fe5e2..ec00847 100644 (file)
     <ClCompile Include="..\dfg\DFGValueStrength.cpp">
       <Filter>dfg</Filter>
     </ClCompile>
+    <ClCompile Include="..\runtime\Exception.cpp">
+      <Filter>runtime</Filter>
+    </ClCompile>
     <ClCompile Include="..\runtime\ExceptionFuzz.cpp">
       <Filter>runtime</Filter>
     </ClCompile>
     <ClInclude Include="..\dfg\DFGValueStrength.h">
       <Filter>dfg</Filter>
     </ClInclude>
+    <ClInclude Include="..\runtime\Exception.h">
+      <Filter>runtime</Filter>
+    </ClInclude>
     <ClInclude Include="..\runtime\ExceptionFuzz.h">
       <Filter>runtime</Filter>
     </ClInclude>
       <Filter>jit</Filter>
     </MASM>
   </ItemGroup>
-</Project>
\ No newline at end of file
+</Project>
index e48833c..8e62d1b 100644 (file)
                E49DC16D12EF295300184A1F /* SourceProviderCacheItem.h in Headers */ = {isa = PBXBuildFile; fileRef = E49DC14912EF261A00184A1F /* SourceProviderCacheItem.h */; settings = {ATTRIBUTES = (Private, ); }; };
                FE0D4A061AB8DD0A002F54BF /* ExecutionTimeLimitTest.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FE0D4A041AB8DD0A002F54BF /* ExecutionTimeLimitTest.cpp */; };
                FE0D4A091ABA2437002F54BF /* GlobalContextWithFinalizerTest.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FE0D4A071ABA2437002F54BF /* GlobalContextWithFinalizerTest.cpp */; };
+               FE1C0FFD1B193E9800B53FCA /* Exception.h in Headers */ = {isa = PBXBuildFile; fileRef = FE1C0FFC1B193E9800B53FCA /* Exception.h */; settings = {ATTRIBUTES = (Private, ); }; };
+               FE1C0FFF1B194FD100B53FCA /* Exception.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FE1C0FFE1B194FD100B53FCA /* Exception.cpp */; };
                FE20CE9D15F04A9500DF3430 /* LLIntCLoop.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FE20CE9B15F04A9500DF3430 /* LLIntCLoop.cpp */; };
                FE20CE9E15F04A9500DF3430 /* LLIntCLoop.h in Headers */ = {isa = PBXBuildFile; fileRef = FE20CE9C15F04A9500DF3430 /* LLIntCLoop.h */; settings = {ATTRIBUTES = (Private, ); }; };
                FE384EE51ADDB7AD0055DE2C /* JSDollarVM.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FE384EE11ADDB7AD0055DE2C /* JSDollarVM.cpp */; };
                FE0D4A051AB8DD0A002F54BF /* ExecutionTimeLimitTest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ExecutionTimeLimitTest.h; path = API/tests/ExecutionTimeLimitTest.h; sourceTree = "<group>"; };
                FE0D4A071ABA2437002F54BF /* GlobalContextWithFinalizerTest.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = GlobalContextWithFinalizerTest.cpp; path = API/tests/GlobalContextWithFinalizerTest.cpp; sourceTree = "<group>"; };
                FE0D4A081ABA2437002F54BF /* GlobalContextWithFinalizerTest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = GlobalContextWithFinalizerTest.h; path = API/tests/GlobalContextWithFinalizerTest.h; sourceTree = "<group>"; };
+               FE1C0FFC1B193E9800B53FCA /* Exception.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Exception.h; sourceTree = "<group>"; };
+               FE1C0FFE1B194FD100B53FCA /* Exception.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Exception.cpp; sourceTree = "<group>"; };
                FE20CE9B15F04A9500DF3430 /* LLIntCLoop.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = LLIntCLoop.cpp; path = llint/LLIntCLoop.cpp; sourceTree = "<group>"; };
                FE20CE9C15F04A9500DF3430 /* LLIntCLoop.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = LLIntCLoop.h; path = llint/LLIntCLoop.h; sourceTree = "<group>"; };
                FE384EE11ADDB7AD0055DE2C /* JSDollarVM.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSDollarVM.cpp; sourceTree = "<group>"; };
                                BC02E98B0E183E38000F9297 /* ErrorInstance.h */,
                                BC02E9060E1839DB000F9297 /* ErrorPrototype.cpp */,
                                BC02E9070E1839DB000F9297 /* ErrorPrototype.h */,
+                               FE1C0FFC1B193E9800B53FCA /* Exception.h */,
+                               FE1C0FFE1B194FD100B53FCA /* Exception.cpp */,
                                0F12DE0D1979D5FD0006FF4E /* ExceptionFuzz.cpp */,
                                0F12DE0E1979D5FD0006FF4E /* ExceptionFuzz.h */,
                                1429D8770ED21ACD00B89619 /* ExceptionHelpers.cpp */,
                                FE4D55B81AE716CA0052E459 /* IterationStatus.h in Headers */,
                                FE5068651AE246390009DAB7 /* DeferredSourceDump.h in Headers */,
                                C442CB251A6CDB8C005D3D7C /* JSInputs.json in Headers */,
+                               FE1C0FFD1B193E9800B53FCA /* Exception.h in Headers */,
                                52678F911A04177C006A306D /* ControlFlowProfiler.h in Headers */,
                                52678F8F1A031009006A306D /* BasicBlockLocation.h in Headers */,
                                A5EA710E19F6DF810098F5EC /* InspectorAlternateBackendDispatchers.h in Headers */,
                                7C008CDA187124BB00955C24 /* JSPromiseDeferred.cpp in Sources */,
                                7C008CD2186F8A9300955C24 /* JSPromiseFunctions.cpp in Sources */,
                                7C184E1E17BEE22E007CB63A /* JSPromisePrototype.cpp in Sources */,
+                               FE1C0FFF1B194FD100B53FCA /* Exception.cpp in Sources */,
                                709FB86B1AE335C60039D069 /* WeakSetPrototype.cpp in Sources */,
                                7C008CDE1871258D00955C24 /* JSPromiseReaction.cpp in Sources */,
                                862553D116136DA9009F17D0 /* JSProxy.cpp in Sources */,
index f3a2238..7972226 100644 (file)
@@ -133,11 +133,11 @@ Deprecated::ScriptValue ScriptFunctionCall::call(bool& hadException)
         return Deprecated::ScriptValue();
 
     JSValue result;
-    JSValue exception;
+    Exception* exception;
     if (m_callHandler)
-        result = m_callHandler(m_exec, function, callType, callData, thisObject, m_arguments, &exception);
+        result = m_callHandler(m_exec, function, callType, callData, thisObject, m_arguments, exception);
     else
-        result = JSC::call(m_exec, function, callType, callData, thisObject, m_arguments, &exception);
+        result = JSC::call(m_exec, function, callType, callData, thisObject, m_arguments, exception);
 
     if (exception) {
         hadException = true;
index 7c3e78c..5e7d56e 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, JSC::JSValue* exception);
+    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::Exception*& exception);
     ScriptFunctionCall(const ScriptObject& thisObject, const String& name, ScriptFunctionCallHandler handler = nullptr);
     ScriptValue call(bool& hadException);
     ScriptValue call();
index 8b9a81e..9a1fdd1 100644 (file)
             { "name" : "op_push_with_scope", "length" : 3 },
             { "name" : "op_pop_scope", "length" : 2 },
             { "name" : "op_push_name_scope", "length" : 5 },
-            { "name" : "op_catch", "length" : 2 },
+            { "name" : "op_catch", "length" : 3 },
             { "name" : "op_throw", "length" : 2 },
             { "name" : "op_throw_static_error", "length" : 3 },
             { "name" : "op_debug", "length" : 3 },
index 507f483..250d322 100644 (file)
@@ -303,7 +303,6 @@ void computeDefsForBytecodeOffset(CodeBlock* codeBlock, unsigned bytecodeOffset,
     case op_resolve_scope:
     case op_strcat:
     case op_to_primitive:
-    case op_catch:
     case op_create_this:
     case op_new_array:
     case op_new_array_buffer:
@@ -374,6 +373,7 @@ void computeDefsForBytecodeOffset(CodeBlock* codeBlock, unsigned bytecodeOffset,
         functor(codeBlock, instruction, opcodeID, instruction[1].u.operand);
         return;
     }
+    case op_catch:
     case op_create_lexical_environment: {
         functor(codeBlock, instruction, opcodeID, instruction[1].u.operand);
         functor(codeBlock, instruction, opcodeID, instruction[2].u.operand);
index 4d0c073..1c6b3a3 100644 (file)
@@ -1484,7 +1484,9 @@ void CodeBlock::dumpBytecode(
         }
         case op_catch: {
             int r0 = (++it)->u.operand;
-            printLocationOpAndRegisterOperand(out, exec, location, it, "catch", r0);
+            int r1 = (++it)->u.operand;
+            printLocationAndOp(out, exec, location, it, "catch");
+            out.printf("%s, %s", registerName(r0).data(), registerName(r1).data());
             break;
         }
         case op_throw: {
@@ -2878,7 +2880,7 @@ bool CodeBlock::hasOptimizedReplacement()
 }
 #endif
 
-HandlerInfo* CodeBlock::handlerForBytecodeOffset(unsigned bytecodeOffset)
+HandlerInfo* CodeBlock::handlerForBytecodeOffset(unsigned bytecodeOffset, RequiredHandler requiredHandler)
 {
     RELEASE_ASSERT(bytecodeOffset < instructions().size());
 
@@ -2888,6 +2890,9 @@ HandlerInfo* CodeBlock::handlerForBytecodeOffset(unsigned bytecodeOffset)
     Vector<HandlerInfo>& exceptionHandlers = m_rareData->m_exceptionHandlers;
     for (size_t i = 0; i < exceptionHandlers.size(); ++i) {
         HandlerInfo& handler = exceptionHandlers[i];
+        if ((requiredHandler == RequiredHandler::CatchHandler) && !handler.isCatchHandler())
+            continue;
+
         // Handlers are ordered innermost first, so the first handler we encounter
         // that contains the source address is the correct handler to use.
         if (handler.start <= bytecodeOffset && handler.end > bytecodeOffset)
index af9ac6f..4b81543 100644 (file)
@@ -185,7 +185,11 @@ public:
         return index >= m_numVars;
     }
 
-    HandlerInfo* handlerForBytecodeOffset(unsigned bytecodeOffset);
+    enum class RequiredHandler {
+        CatchHandler,
+        AnyHandler
+    };
+    HandlerInfo* handlerForBytecodeOffset(unsigned bytecodeOffset, RequiredHandler = RequiredHandler::AnyHandler);
     unsigned lineNumberForBytecodeOffset(unsigned bytecodeOffset);
     unsigned columnNumberForBytecodeOffset(unsigned bytecodeOffset);
     void expressionRangeForBytecodeOffset(unsigned bytecodeOffset, int& divot,
index 27996bd..cae7ed9 100644 (file)
@@ -40,7 +40,7 @@ enum class HandlerType {
 struct HandlerInfoBase {
     HandlerType type() const { return static_cast<HandlerType>(typeBits); }
     void setType(HandlerType type) { typeBits = static_cast<uint32_t>(type); }
-    
+
     const char* typeName()
     {
         switch (type()) {
@@ -55,9 +55,9 @@ struct HandlerInfoBase {
         }
         return nullptr;
     }
-    
+
     bool isCatchHandler() const { return type() == HandlerType::Catch; }
-    
+
     uint32_t start;
     uint32_t end;
     uint32_t target;
index 21c3e8a..abba549 100644 (file)
@@ -2528,7 +2528,7 @@ TryData* BytecodeGenerator::pushTry(Label* start)
     return result;
 }
 
-RegisterID* BytecodeGenerator::popTryAndEmitCatch(TryData* tryData, RegisterID* targetRegister, Label* end, HandlerType handlerType)
+void BytecodeGenerator::popTryAndEmitCatch(TryData* tryData, RegisterID* exceptionRegister, RegisterID* thrownValueRegister, Label* end, HandlerType handlerType)
 {
     m_usesExceptions = true;
     
@@ -2546,8 +2546,8 @@ RegisterID* BytecodeGenerator::popTryAndEmitCatch(TryData* tryData, RegisterID*
     tryRange.tryData->handlerType = handlerType;
 
     emitOpcode(op_catch);
-    instructions().append(targetRegister->index());
-    return targetRegister;
+    instructions().append(exceptionRegister->index());
+    instructions().append(thrownValueRegister->index());
 }
 
 void BytecodeGenerator::emitThrowReferenceError(const String& message)
@@ -2760,7 +2760,11 @@ void BytecodeGenerator::emitEnumeration(ThrowableExpressionData* node, Expressio
         // IteratorClose sequence for throw-ed control flow.
         {
             RefPtr<Label> catchHere = emitLabel(newLabel().get());
-            RefPtr<RegisterID> exceptionRegister = popTryAndEmitCatch(tryData, newTemporary(), catchHere.get(), HandlerType::SynthesizedFinally);
+            RefPtr<RegisterID> exceptionRegister = newTemporary();
+            RefPtr<RegisterID> thrownValueRegister = newTemporary();
+            popTryAndEmitCatch(tryData, exceptionRegister.get(),
+                thrownValueRegister.get(), catchHere.get(), HandlerType::SynthesizedFinally);
+
             RefPtr<Label> catchDone = newLabel();
 
             RefPtr<RegisterID> returnMethod = emitGetById(newTemporary(), iterator.get(), propertyNames().returnKeyword);
@@ -2778,7 +2782,8 @@ void BytecodeGenerator::emitEnumeration(ThrowableExpressionData* node, Expressio
             emitThrow(exceptionRegister.get());
 
             // Absorb exception.
-            popTryAndEmitCatch(returnCallTryData, newTemporary(), catchDone.get(), HandlerType::SynthesizedFinally);
+            popTryAndEmitCatch(returnCallTryData, newTemporary(),
+                newTemporary(), catchDone.get(), HandlerType::SynthesizedFinally);
             emitThrow(exceptionRegister.get());
         }
 
index 8d02958..cbc9658 100644 (file)
@@ -553,7 +553,7 @@ namespace JSC {
         // Start a try block. 'start' must have been emitted.
         TryData* pushTry(Label* start);
         // End a try block. 'end' must have been emitted.
-        RegisterID* popTryAndEmitCatch(TryData*, RegisterID* targetRegister, Label* end, HandlerType);
+        void popTryAndEmitCatch(TryData*, RegisterID* exceptionRegister, RegisterID* thrownValueRegister, Label* end, HandlerType);
 
         void emitThrow(RegisterID* exc)
         { 
index 129ffa3..24bb987 100644 (file)
@@ -2881,7 +2881,9 @@ void TryNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
 
         // Uncaught exception path: the catch block.
         RefPtr<Label> here = generator.emitLabel(generator.newLabel().get());
-        RefPtr<RegisterID> exceptionRegister = generator.popTryAndEmitCatch(tryData, generator.newTemporary(), here.get(), HandlerType::Catch);
+        RefPtr<RegisterID> exceptionRegister = generator.newTemporary();
+        RefPtr<RegisterID> thrownValueRegister = generator.newTemporary();
+        generator.popTryAndEmitCatch(tryData, exceptionRegister.get(), thrownValueRegister.get(), here.get(), HandlerType::Catch);
         
         if (m_finallyBlock) {
             // If the catch block throws an exception and we have a finally block, then the finally
@@ -2889,7 +2891,7 @@ void TryNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
             tryData = generator.pushTry(here.get());
         }
 
-        generator.emitPushCatchScope(generator.scopeRegister(), m_exceptionIdent, exceptionRegister.get(), DontDelete);
+        generator.emitPushCatchScope(generator.scopeRegister(), m_thrownValueIdent, thrownValueRegister.get(), DontDelete);
         generator.emitProfileControlFlow(m_tryBlock->endOffset() + 1);
         generator.emitNode(dst, m_catchBlock);
         generator.emitPopScope(generator.scopeRegister());
@@ -2912,10 +2914,12 @@ void TryNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
         generator.emitJump(finallyEndLabel.get());
 
         // Uncaught exception path: invoke the finally block, then re-throw the exception.
-        RefPtr<RegisterID> tempExceptionRegister = generator.popTryAndEmitCatch(tryData, generator.newTemporary(), preFinallyLabel.get(), HandlerType::Finally);
+        RefPtr<RegisterID> exceptionRegister = generator.newTemporary();
+        RefPtr<RegisterID> thrownValueRegister = generator.newTemporary();
+        generator.popTryAndEmitCatch(tryData, exceptionRegister.get(), thrownValueRegister.get(), preFinallyLabel.get(), HandlerType::Finally);
         generator.emitProfileControlFlow(finallyStartOffset);
         generator.emitNode(dst, m_finallyBlock);
-        generator.emitThrow(tempExceptionRegister.get());
+        generator.emitThrow(exceptionRegister.get());
 
         generator.emitLabel(finallyEndLabel.get());
         generator.emitProfileControlFlow(m_finallyBlock->endOffset() + 1);
index 147a7e6..b505f8b 100644 (file)
@@ -487,7 +487,7 @@ bool Debugger::hasBreakpoint(SourceID sourceID, const TextPosition& position, Br
     // so make it looks like the debugger is already paused.
     TemporaryPausedState pausedState(*this);
 
-    JSValue exception;
+    Exception* exception;
     DebuggerCallFrame* debuggerCallFrame = currentDebuggerCallFrame();
     JSValue result = debuggerCallFrame->evaluate(breakpoint->condition, exception);
 
@@ -695,13 +695,13 @@ void Debugger::pauseIfNeeded(CallFrame* callFrame)
     }
 }
 
-void Debugger::exception(CallFrame* callFrame, JSValue exception, bool hasHandler)
+void Debugger::exception(CallFrame* callFrame, JSValue exception, bool hasCatchHandler)
 {
     if (m_isPaused)
         return;
 
     PauseReasonDeclaration reason(*this, PausedForException);
-    if (m_pauseOnExceptionsState == PauseOnAllExceptions || (m_pauseOnExceptionsState == PauseOnUncaughtExceptions && !hasHandler)) {
+    if (m_pauseOnExceptionsState == PauseOnAllExceptions || (m_pauseOnExceptionsState == PauseOnUncaughtExceptions && !hasCatchHandler)) {
         m_pauseOnNextStatement = true;
         setSteppingMode(SteppingModeEnabled);
     }
index d0f8a3f..6aef02d 100644 (file)
@@ -109,7 +109,7 @@ public:
 
     virtual void sourceParsed(ExecState*, SourceProvider*, int errorLineNumber, const WTF::String& errorMessage) = 0;
 
-    void exception(CallFrame*, JSValue exceptionValue, bool hasHandler);
+    void exception(CallFrame*, JSValue exceptionValue, bool hasCatchHandler);
     void atStatement(CallFrame*);
     void callEvent(CallFrame*);
     void returnEvent(CallFrame*);
@@ -124,7 +124,7 @@ public:
 protected:
     virtual bool needPauseHandling(JSGlobalObject*) { return false; }
     virtual void handleBreakpointHit(JSGlobalObject*, const Breakpoint&) { }
-    virtual void handleExceptionInBreakpointCondition(ExecState*, JSValue exception) const { UNUSED_PARAM(exception); }
+    virtual void handleExceptionInBreakpointCondition(ExecState*, Exception*) const { }
     virtual void handlePause(JSGlobalObject*, ReasonForPause) { }
     virtual void notifyDoneProcessingDebuggerEvents() { }
 
index 221e7ec..f92f290 100644 (file)
@@ -32,6 +32,7 @@
 #include "CodeBlock.h"
 #include "DebuggerEvalEnabler.h"
 #include "DebuggerScope.h"
+#include "Exception.h"
 #include "Interpreter.h"
 #include "JSFunction.h"
 #include "JSLexicalEnvironment.h"
@@ -176,7 +177,7 @@ JSValue DebuggerCallFrame::thisValue() const
 }
 
 // Evaluate some JavaScript code in the scope of this frame.
-JSValue DebuggerCallFrame::evaluate(const String& script, JSValue& exception)
+JSValue DebuggerCallFrame::evaluate(const String& script, Exception*& exception)
 {
     ASSERT(isValid());
     CallFrame* callFrame = m_callFrame;
index 1d6b279..5c7d75a 100644 (file)
@@ -38,6 +38,7 @@
 namespace JSC {
 
 class DebuggerScope;
+class Exception;
 class ExecState;
 typedef ExecState CallFrame;
 
@@ -66,7 +67,7 @@ public:
     JS_EXPORT_PRIVATE String functionName() const;
     JS_EXPORT_PRIVATE Type type() const;
     JS_EXPORT_PRIVATE JSValue thisValue() const;
-    JSValue evaluate(const String&, JSValue& exception);
+    JSValue evaluate(const String&, Exception*&);
 
     bool isValid() const { return !!m_callFrame; }
     JS_EXPORT_PRIVATE void invalidate();
index eee0fab..ae3eb68 100644 (file)
@@ -139,9 +139,9 @@ Deprecated::ScriptObject InjectedScriptManager::createInjectedScript(const Strin
     JSGlobalObject* globalObject = scriptState->lexicalGlobalObject();
     JSValue globalThisValue = scriptState->globalThisValue();
 
-    JSValue evaluationException;
+    Exception* evaluationException;
     InspectorEvaluateHandler evaluateHandler = m_environment.evaluateHandler();
-    JSValue functionValue = evaluateHandler(scriptState, sourceCode, globalThisValue, &evaluationException);
+    JSValue functionValue = evaluateHandler(scriptState, sourceCode, globalThisValue, evaluationException);
     if (evaluationException)
         return Deprecated::ScriptObject();
 
index 18df142..5015231 100644 (file)
@@ -33,13 +33,14 @@ class Stopwatch;
 }
 
 namespace JSC {
+class Exception;
 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, JSC::JSValue* exception);
-typedef JSC::JSValue (*InspectorEvaluateHandler)(JSC::ExecState*, const JSC::SourceCode&, JSC::JSValue thisValue, JSC::JSValue* exception);
+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::Exception*& returnedException);
+typedef JSC::JSValue (*InspectorEvaluateHandler)(JSC::ExecState*, const JSC::SourceCode&, JSC::JSValue thisValue, JSC::Exception*& returnedException);
 
 class InspectorEnvironment {
 public:
index f893c7a..57f52c5 100644 (file)
@@ -29,6 +29,7 @@
 #include "Completion.h"
 #include "ConsoleMessage.h"
 #include "ErrorHandlingScope.h"
+#include "Exception.h"
 #include "InjectedScriptHost.h"
 #include "InjectedScriptManager.h"
 #include "InspectorAgent.h"
@@ -188,7 +189,7 @@ void JSGlobalObjectInspectorController::appendAPIBacktrace(ScriptCallStack* call
 #endif
 }
 
-void JSGlobalObjectInspectorController::reportAPIException(ExecState* exec, JSValue exception)
+void JSGlobalObjectInspectorController::reportAPIException(ExecState* exec, Exception* exception)
 {
     if (isTerminatedExecutionException(exception))
         return;
@@ -201,7 +202,7 @@ void JSGlobalObjectInspectorController::reportAPIException(ExecState* exec, JSVa
 
     // FIXME: <http://webkit.org/b/115087> Web Inspector: Should not evaluate JavaScript handling exceptions
     // If this is a custom exception object, call toString on it to try and get a nice string representation for the exception.
-    String errorMessage = exception.toString(exec)->value(exec);
+    String errorMessage = exception->value().toString(exec)->value(exec);
     exec->clearException();
 
     if (JSGlobalObjectConsoleClient::logToSystemConsole()) {
index 9c03e31..6e3f94e 100644 (file)
@@ -43,6 +43,7 @@ class Stopwatch;
 
 namespace JSC {
 class ConsoleClient;
+class Exception;
 class ExecState;
 class JSGlobalObject;
 class JSValue;
@@ -81,7 +82,7 @@ public:
     void setIncludesNativeCallStackWhenReportingExceptions(bool includesNativeCallStack) { m_includeNativeCallStackWithExceptions = includesNativeCallStack; }
 
     void pause();
-    void reportAPIException(JSC::ExecState*, JSC::JSValue exception);
+    void reportAPIException(JSC::ExecState*, JSC::Exception*);
 
     JSC::ConsoleClient* consoleClient() const;
 
index 489bf03..901b673 100644 (file)
@@ -54,7 +54,7 @@ private:
     // NOTE: Currently all exceptions are reported at the API boundary through reportAPIException.
     // Until a time comes where an exception can be caused outside of the API (e.g. setTimeout
     // or some other async operation in a pure JSContext) we can ignore exceptions reported here.
-    virtual void reportException(JSC::ExecState*, JSC::JSValue) const override { }
+    virtual void reportException(JSC::ExecState*, JSC::Exception*) const override { }
 
     ListenerSet m_listeners;
     JSC::JSGlobalObject& m_globalObject;
index 3e5eb30..d27e971 100644 (file)
@@ -28,6 +28,7 @@
 
 #include "DebuggerScope.h"
 #include "Error.h"
+#include "Exception.h"
 #include "JSCJSValue.h"
 #include "JSCellInlines.h"
 #include "JSJavaScriptCallFramePrototype.h"
@@ -75,7 +76,7 @@ JSJavaScriptCallFrame::~JSJavaScriptCallFrame()
 
 JSValue JSJavaScriptCallFrame::evaluate(ExecState* exec)
 {
-    JSValue exception;
+    Exception* exception;
     JSValue result = impl().evaluate(exec->argument(0).toString(exec)->value(exec), exception);
     if (exception)
         exec->vm().throwException(exec, exception);
index 4fc4e6b..b344c33 100644 (file)
@@ -55,7 +55,7 @@ public:
     JSC::JSGlobalObject* vmEntryGlobalObject() const { return m_debuggerCallFrame->vmEntryGlobalObject(); }
 
     JSC::JSValue thisValue() const { return m_debuggerCallFrame->thisValue(); }
-    JSC::JSValue evaluate(const String& script, JSC::JSValue& exception) const  { return m_debuggerCallFrame->evaluate(script, exception); }
+    JSC::JSValue evaluate(const String& script, JSC::Exception*& exception) const  { return m_debuggerCallFrame->evaluate(script, exception); }
 
 private:
     JavaScriptCallFrame(PassRefPtr<JSC::DebuggerCallFrame>);
index f9f6c1c..b37faad 100644 (file)
@@ -34,6 +34,7 @@
 #include "ScriptCallStackFactory.h"
 
 #include "CallFrame.h"
+#include "Exception.h"
 #include "JSCJSValue.h"
 #include "JSCInlines.h"
 #include "ScriptArguments.h"
@@ -128,10 +129,10 @@ static void extractSourceInformationFromException(JSC::ExecState* exec, JSObject
     exec->clearException();
 }
 
-PassRefPtr<ScriptCallStack> createScriptCallStackFromException(JSC::ExecState* exec, JSC::JSValue& exception, size_t maxStackSize)
+PassRefPtr<ScriptCallStack> createScriptCallStackFromException(JSC::ExecState* exec, JSC::Exception* exception, size_t maxStackSize)
 {
     Vector<ScriptCallFrame> frames;
-    RefCountedArray<StackFrame> stackTrace = exec->vm().exceptionStack();
+    RefCountedArray<StackFrame> stackTrace = exception->stack();
     for (size_t i = 0; i < stackTrace.size() && i < maxStackSize; i++) {
         unsigned line;
         unsigned column;
@@ -141,8 +142,8 @@ PassRefPtr<ScriptCallStack> createScriptCallStackFromException(JSC::ExecState* e
     }
 
     // Fallback to getting at least the line and sourceURL from the exception object if it has values and the exceptionStack doesn't.
-    JSObject* exceptionObject = exception.toObject(exec);
-    if (exception.isObject()) {
+    if (exception->value().isObject()) {
+        JSObject* exceptionObject = exception->value().toObject(exec);
         int lineNumber;
         int columnNumber;
         String exceptionSourceURL;
index 07c1586..dc6f3a7 100644 (file)
@@ -35,6 +35,7 @@
 #include <wtf/Forward.h>
 
 namespace JSC {
+class Exception;
 class ExecState;
 class JSValue;
 }
@@ -47,7 +48,7 @@ class ScriptCallStack;
 // FIXME: The subtle differences between these should be eliminated.
 JS_EXPORT_PRIVATE PassRefPtr<ScriptCallStack> createScriptCallStack(JSC::ExecState*, size_t maxStackSize);
 JS_EXPORT_PRIVATE PassRefPtr<ScriptCallStack> createScriptCallStackForConsole(JSC::ExecState*, size_t maxStackSize);
-JS_EXPORT_PRIVATE PassRefPtr<ScriptCallStack> createScriptCallStackFromException(JSC::ExecState*, JSC::JSValue& exception, size_t maxStackSize);
+JS_EXPORT_PRIVATE PassRefPtr<ScriptCallStack> createScriptCallStackFromException(JSC::ExecState*, JSC::Exception*, size_t maxStackSize);
 JS_EXPORT_PRIVATE PassRefPtr<ScriptArguments> createScriptArguments(JSC::ExecState*, unsigned skipArgumentCount);
 
 } // namespace Inspector
index 235f0e0..75d0d8a 100644 (file)
@@ -33,6 +33,7 @@
 
 #include "DebuggerCallFrame.h"
 #include "DebuggerScope.h"
+#include "Exception.h"
 #include "JSJavaScriptCallFrame.h"
 #include "JSLock.h"
 #include "JavaScriptCallFrame.h"
@@ -93,7 +94,7 @@ bool ScriptDebugServer::evaluateBreakpointAction(const ScriptBreakpointAction& b
         break;
     }
     case ScriptBreakpointActionTypeEvaluate: {
-        JSValue exception;
+        Exception* exception;
         debuggerCallFrame->evaluate(breakpointAction.data, exception);
         if (exception)
             reportException(debuggerCallFrame->exec(), exception);
@@ -103,13 +104,13 @@ bool ScriptDebugServer::evaluateBreakpointAction(const ScriptBreakpointAction& b
         dispatchBreakpointActionSound(debuggerCallFrame->exec(), breakpointAction.identifier);
         break;
     case ScriptBreakpointActionTypeProbe: {
-        JSValue exception;
+        Exception* exception;
         JSValue result = debuggerCallFrame->evaluate(breakpointAction.data, exception);
         if (exception)
             reportException(debuggerCallFrame->exec(), exception);
         
         JSC::ExecState* state = debuggerCallFrame->scope()->globalObject()->globalExec();
-        Deprecated::ScriptValue wrappedResult = Deprecated::ScriptValue(state->vm(), exception ? exception : result);
+        Deprecated::ScriptValue wrappedResult = Deprecated::ScriptValue(state->vm(), exception ? exception->value() : result);
         dispatchBreakpointActionProbe(state, breakpointAction, wrappedResult);
         break;
     }
@@ -302,7 +303,7 @@ void ScriptDebugServer::handleBreakpointHit(JSC::JSGlobalObject* globalObject, c
     }
 }
 
-void ScriptDebugServer::handleExceptionInBreakpointCondition(JSC::ExecState* exec, JSC::JSValue exception) const
+void ScriptDebugServer::handleExceptionInBreakpointCondition(JSC::ExecState* exec, JSC::Exception* exception) const
 {
     reportException(exec, exception);
 }
index 297eb31..99eb723 100644 (file)
@@ -79,7 +79,7 @@ protected:
     virtual void didContinue(JSC::JSGlobalObject*) = 0;
     virtual void runEventLoopWhilePaused() = 0;
     virtual bool isContentScript(JSC::ExecState*) const = 0;
-    virtual void reportException(JSC::ExecState*, JSC::JSValue) const = 0;
+    virtual void reportException(JSC::ExecState*, JSC::Exception*) const = 0;
 
     bool evaluateBreakpointAction(const ScriptBreakpointAction&);
 
@@ -101,7 +101,7 @@ private:
     virtual void sourceParsed(JSC::ExecState*, JSC::SourceProvider*, int errorLine, const String& errorMsg) override final;
     virtual bool needPauseHandling(JSC::JSGlobalObject*) override final { return true; }
     virtual void handleBreakpointHit(JSC::JSGlobalObject*, const JSC::Breakpoint&) override final;
-    virtual void handleExceptionInBreakpointCondition(JSC::ExecState*, JSC::JSValue exception) const override final;
+    virtual void handleExceptionInBreakpointCondition(JSC::ExecState*, JSC::Exception*) const override final;
     virtual void handlePause(JSC::JSGlobalObject*, JSC::Debugger::ReasonForPause) override final;
     virtual void notifyDoneProcessingDebuggerEvents() override final;
 
index 609f43d..60fcf96 100644 (file)
 #define CallFrame_h
 
 #include "AbstractPC.h"
-#include "VM.h"
 #include "JSStack.h"
 #include "MacroAssemblerCodeRef.h"
 #include "Register.h"
 #include "StackVisitor.h"
+#include "VM.h"
 #include "VMEntryRecord.h"
 
 namespace JSC  {
@@ -75,13 +75,9 @@ namespace JSC  {
         // But they're used in many places in legacy code, so they're not going away any time soon.
 
         void clearException() { vm().clearException(); }
-        void clearSupplementaryExceptionInfo()
-        {
-            vm().clearExceptionStack();
-        }
 
-        JSValue exception() const { return vm().exception(); }
-        bool hadException() const { return !vm().exception().isEmpty(); }
+        Exception* exception() const { return vm().exception(); }
+        bool hadException() const { return !!vm().exception(); }
 
         AtomicStringTable* atomicStringTable() const { return vm().atomicStringTable(); }
         const CommonIdentifiers& propertyNames() const { return *vm().propertyNames; }
index a614ed5..c997d2c 100644 (file)
@@ -41,6 +41,7 @@
 #include "DebuggerCallFrame.h"
 #include "ErrorInstance.h"
 #include "EvalCodeCache.h"
+#include "Exception.h"
 #include "ExceptionHelpers.h"
 #include "GetterSetter.h"
 #include "JSArray.h"
@@ -435,7 +436,7 @@ static bool unwindCallFrame(StackVisitor& visitor)
 {
     CallFrame* callFrame = visitor->callFrame();
     if (Debugger* debugger = callFrame->vmEntryGlobalObject()->debugger()) {
-        ClearExceptionScope scope(&callFrame->vm());
+        SuspendExceptionScope scope(&callFrame->vm());
         if (jsDynamicCast<JSFunction*>(callFrame->callee()))
             debugger->returnEvent(callFrame);
         else
@@ -583,9 +584,9 @@ JSString* Interpreter::stackTraceAsString(ExecState* exec, Vector<StackFrame> st
     return jsString(&exec->vm(), builder.toString());
 }
 
-class GetExceptionHandlerFunctor {
+class GetCatchHandlerFunctor {
 public:
-    GetExceptionHandlerFunctor()
+    GetCatchHandlerFunctor()
         : m_handler(0)
     {
     }
@@ -599,7 +600,7 @@ public:
             return StackVisitor::Continue;
 
         unsigned bytecodeOffset = visitor->bytecodeOffset();
-        m_handler = codeBlock->handlerForBytecodeOffset(bytecodeOffset);
+        m_handler = codeBlock->handlerForBytecodeOffset(bytecodeOffset, CodeBlock::RequiredHandler::CatchHandler);
         if (m_handler)
             return StackVisitor::Done;
 
@@ -649,11 +650,12 @@ private:
     HandlerInfo*& m_handler;
 };
 
-NEVER_INLINE HandlerInfo* Interpreter::unwind(VMEntryFrame*& vmEntryFrame, CallFrame*& callFrame, JSValue& exceptionValue)
+NEVER_INLINE HandlerInfo* Interpreter::unwind(VMEntryFrame*& vmEntryFrame, CallFrame*& callFrame, Exception* exception)
 {
     CodeBlock* codeBlock = callFrame->codeBlock();
     bool isTermination = false;
 
+    JSValue exceptionValue = exception->value();
     ASSERT(!exceptionValue.isEmpty());
     ASSERT(!exceptionValue.isCell() || exceptionValue.asCell());
     // This shouldn't be possible (hence the assertions), but we're already in the slowest of
@@ -662,32 +664,35 @@ NEVER_INLINE HandlerInfo* Interpreter::unwind(VMEntryFrame*& vmEntryFrame, CallF
         exceptionValue = jsNull();
 
     if (exceptionValue.isObject())
-        isTermination = isTerminatedExecutionException(asObject(exceptionValue));
+        isTermination = isTerminatedExecutionException(exception);
 
-    ASSERT(callFrame->vm().exceptionStack().size());
+    ASSERT(callFrame->vm().exception() && callFrame->vm().exception()->stack().size());
 
     Debugger* debugger = callFrame->vmEntryGlobalObject()->debugger();
-    if (debugger && debugger->needsExceptionCallbacks()) {
-        // We need to clear the exception and the exception stack here in order to see if a new exception happens.
+    if (debugger && debugger->needsExceptionCallbacks() && !exception->didNotifyInspectorOfThrow()) {
+        // We need to clear the exception here in order to see if a new exception happens.
         // Afterwards, the values are put back to continue processing this error.
-        ClearExceptionScope scope(&callFrame->vm());
+        SuspendExceptionScope scope(&callFrame->vm());
         // This code assumes that if the debugger is enabled then there is no inlining.
         // If that assumption turns out to be false then we'll ignore the inlined call
         // frames.
         // https://bugs.webkit.org/show_bug.cgi?id=121754
 
-        bool hasHandler;
+        bool hasCatchHandler;
         if (isTermination)
-            hasHandler = false;
+            hasCatchHandler = false;
         else {
-            GetExceptionHandlerFunctor functor;
+            GetCatchHandlerFunctor functor;
             callFrame->iterate(functor);
-            hasHandler = !!functor.handler();
+            HandlerInfo* handler = functor.handler();
+            ASSERT(!handler || handler->isCatchHandler());
+            hasCatchHandler = !!handler;
         }
 
-        debugger->exception(callFrame, exceptionValue, hasHandler);
+        debugger->exception(callFrame, exceptionValue, hasCatchHandler);
         ASSERT(!callFrame->hadException());
     }
+    exception->setDidNotifyInspectorOfThrow();
 
     // Calculate an exception handler vPC, unwinding call frames as necessary.
     HandlerInfo* handler = 0;
index 99369cd..ef4ec0d 100644 (file)
@@ -98,20 +98,20 @@ namespace JSC {
         void expressionInfo(int& divot, int& startOffset, int& endOffset, unsigned& line, unsigned& column);
     };
 
-    class ClearExceptionScope {
+    class SuspendExceptionScope {
     public:
-        ClearExceptionScope(VM* vm): m_vm(vm)
+        SuspendExceptionScope(VM* vm)
+            : m_vm(vm)
         {
-            vm->getExceptionInfo(oldException, oldExceptionStack);
+            oldException = vm->exception();
             vm->clearException();
         }
-        ~ClearExceptionScope()
+        ~SuspendExceptionScope()
         {
-            m_vm->setExceptionInfo(oldException, oldExceptionStack);
+            m_vm->setException(oldException);
         }
     private:
-        JSC::JSValue oldException;
-        RefCountedArray<JSC::StackFrame> oldExceptionStack;
+        Exception* oldException;
         VM* m_vm;
     };
     
@@ -215,7 +215,7 @@ namespace JSC {
         
         SamplingTool* sampler() { return m_sampler.get(); }
 
-        NEVER_INLINE HandlerInfo* unwind(VMEntryFrame*&, CallFrame*&, JSValue&);
+        NEVER_INLINE HandlerInfo* unwind(VMEntryFrame*&, CallFrame*&, Exception*);
         NEVER_INLINE void debug(CallFrame*, DebugHookID);
         JSString* stackTraceAsString(ExecState*, Vector<StackFrame>);
 
index 443cd6c..09133a8 100644 (file)
@@ -223,7 +223,7 @@ AssemblyHelpers::Jump AssemblyHelpers::emitExceptionCheck(ExceptionCheckKind kin
 #if USE(JSVALUE64)
     result = branchTest64(kind == NormalExceptionCheck ? NonZero : Zero, AbsoluteAddress(vm()->addressOfException()));
 #elif USE(JSVALUE32_64)
-    result = branch32(kind == NormalExceptionCheck ? NotEqual : Equal, AbsoluteAddress(reinterpret_cast<char*>(vm()->addressOfException()) + OBJECT_OFFSETOF(JSValue, u.asBits.tag)), TrustedImm32(JSValue::EmptyValueTag));
+    result = branch32(kind == NormalExceptionCheck ? NotEqual : Equal, AbsoluteAddress(vm()->addressOfException()), TrustedImm32(0));
 #endif
     
     if (width == NormalJumpWidth)
index cf89c0e..4f6d9e8 100644 (file)
 
 namespace JSC {
 
-void genericUnwind(VM* vm, ExecState* callFrame, JSValue exceptionValue)
+void genericUnwind(VM* vm, ExecState* callFrame)
 {
     if (Options::breakOnThrow()) {
         dataLog("In call frame ", RawPointer(callFrame), " for code block ", *callFrame->codeBlock(), "\n");
         CRASH();
     }
     
-    RELEASE_ASSERT(exceptionValue);
+    Exception* exception = vm->exception();
+    RELEASE_ASSERT(exception);
     VMEntryFrame* vmEntryFrame = vm->topVMEntryFrame;
-    HandlerInfo* handler = vm->interpreter->unwind(vmEntryFrame, callFrame, exceptionValue); // This may update vmEntryFrame and callFrame.
+    HandlerInfo* handler = vm->interpreter->unwind(vmEntryFrame, callFrame, exception); // This may update vmEntryFrame and callFrame.
 
     void* catchRoutine;
     Instruction* catchPCForInterpreter = 0;
index e02b515..43b92e7 100644 (file)
@@ -33,7 +33,7 @@ namespace JSC {
 class ExecState;
 class VM;
 
-void genericUnwind(VM*, ExecState*, JSValue exceptionValue);
+void genericUnwind(VM*, ExecState*);
 
 } // namespace JSC
 
index 052ae83..0813b15 100644 (file)
@@ -31,6 +31,7 @@
 #include "BasicBlockLocation.h"
 #include "CopiedSpaceInlines.h"
 #include "Debugger.h"
+#include "Exception.h"
 #include "Heap.h"
 #include "JITInlines.h"
 #include "JSArray.h"
@@ -529,6 +530,9 @@ void JIT::emit_op_catch(Instruction* currentInstruction)
     load64(Address(regT3, VM::exceptionOffset()), regT0);
     store64(TrustedImm64(JSValue::encode(JSValue())), Address(regT3, VM::exceptionOffset()));
     emitPutVirtualRegister(currentInstruction[1].u.operand);
+
+    load64(Address(regT0, Exception::valueOffset()), regT0);
+    emitPutVirtualRegister(currentInstruction[2].u.operand);
 }
 
 void JIT::emit_op_switch_imm(Instruction* currentInstruction)
index 5f9040d..8764cc2 100644 (file)
@@ -32,6 +32,7 @@
 
 #include "CCallHelpers.h"
 #include "Debugger.h"
+#include "Exception.h"
 #include "JITInlines.h"
 #include "JSArray.h"
 #include "JSCell.h"
@@ -97,7 +98,7 @@ JIT::CodeRef JIT::privateCompileCTINativeCall(VM* vm, NativeFunction func)
 #endif // CPU(X86)
 
     // Check for an exception
-    Jump sawException = branch32(NotEqual, AbsoluteAddress(reinterpret_cast<char*>(vm->addressOfException()) + OBJECT_OFFSETOF(JSValue, u.asBits.tag)), TrustedImm32(JSValue::EmptyValueTag)); 
+    Jump sawException = branch32(NotEqual, AbsoluteAddress(vm->addressOfException()), TrustedImm32(0));
 
     emitFunctionEpilogue();
     // Return.
@@ -829,13 +830,19 @@ void JIT::emit_op_catch(Instruction* currentInstruction)
     addPtr(TrustedImm32(stackPointerOffsetFor(codeBlock()) * sizeof(Register)), callFrameRegister, stackPointerRegister);
 
     // Now store the exception returned by operationThrow.
-    load32(Address(regT3, VM::exceptionOffset() + OBJECT_OFFSETOF(JSValue, u.asBits.payload)), regT0);
-    load32(Address(regT3, VM::exceptionOffset() + OBJECT_OFFSETOF(JSValue, u.asBits.tag)), regT1);
-    store32(TrustedImm32(JSValue().payload()), Address(regT3, VM::exceptionOffset() + OBJECT_OFFSETOF(JSValue, u.asBits.payload)));
-    store32(TrustedImm32(JSValue().tag()), Address(regT3, VM::exceptionOffset() + OBJECT_OFFSETOF(JSValue, u.asBits.tag)));
+    load32(Address(regT3, VM::exceptionOffset()), regT2);
+    move(TrustedImm32(JSValue::CellTag), regT1);
+
+    store32(TrustedImm32(0), Address(regT3, VM::exceptionOffset()));
 
     unsigned exception = currentInstruction[1].u.operand;
-    emitStore(exception, regT1, regT0);
+    emitStore(exception, regT1, regT2);
+
+    load32(Address(regT2, Exception::valueOffset() + OBJECT_OFFSETOF(JSValue, u.asBits.payload)), regT0);
+    load32(Address(regT2, Exception::valueOffset() + OBJECT_OFFSETOF(JSValue, u.asBits.tag)), regT1);
+
+    unsigned thrownValue = currentInstruction[2].u.operand;
+    emitStore(thrownValue, regT1, regT0);
 }
 
 void JIT::emit_op_switch_imm(Instruction* currentInstruction)
index 00d23d4..f018329 100644 (file)
@@ -1918,7 +1918,7 @@ void JIT_OPERATION operationThrow(ExecState* exec, EncodedJSValue encodedExcepti
     vm->throwException(exec, exceptionValue);
 
     // Results stored out-of-band in vm.targetMachinePCForThrow, vm.callFrameForThrow & vm.vmEntryFrameForThrow
-    genericUnwind(vm, exec, exceptionValue);
+    genericUnwind(vm, exec);
 }
 
 void JIT_OPERATION operationFlushWriteBarrierBuffer(ExecState* exec, JSCell* cell)
@@ -1957,11 +1957,7 @@ void JIT_OPERATION operationInitGlobalConst(ExecState* exec, Instruction* pc)
 void JIT_OPERATION lookupExceptionHandler(VM* vm, ExecState* exec)
 {
     NativeCallFrameTracer tracer(vm, exec);
-
-    JSValue exceptionValue = vm->exception();
-    ASSERT(exceptionValue);
-    
-    genericUnwind(vm, exec, exceptionValue);
+    genericUnwind(vm, exec);
     ASSERT(vm->targetMachinePCForThrow);
 }
 
@@ -1972,11 +1968,7 @@ void JIT_OPERATION lookupExceptionHandlerFromCallerFrame(VM* vm, ExecState* exec
     ASSERT(callerFrame);
 
     NativeCallFrameTracerWithRestore tracer(vm, vmEntryFrame, callerFrame);
-
-    JSValue exceptionValue = vm->exception();
-    ASSERT(exceptionValue);
-    
-    genericUnwind(vm, callerFrame, exceptionValue);
+    genericUnwind(vm, callerFrame);
     ASSERT(vm->targetMachinePCForThrow);
 }
 
@@ -1984,8 +1976,7 @@ void JIT_OPERATION operationVMHandleException(ExecState* exec)
 {
     VM* vm = &exec->vm();
     NativeCallFrameTracer tracer(vm, exec);
-
-    genericUnwind(vm, exec, vm->exception());
+    genericUnwind(vm, exec);
 }
 
 // This function "should" just take the ExecState*, but doing so would make it more difficult
index b9d6198..6f71ff8 100644 (file)
@@ -349,8 +349,8 @@ static MacroAssemblerCodeRef nativeForGenerator(VM* vm, CodeSpecializationKind k
 #else
     JSInterfaceJIT::Jump exceptionHandler = jit.branch32(
         JSInterfaceJIT::NotEqual,
-        JSInterfaceJIT::AbsoluteAddress(reinterpret_cast<char*>(vm->addressOfException()) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag)),
-        JSInterfaceJIT::TrustedImm32(JSValue::EmptyValueTag));
+        JSInterfaceJIT::AbsoluteAddress(vm->addressOfException()),
+        JSInterfaceJIT::TrustedImm32(0));
 #endif
 
     jit.emitFunctionEpilogue();
index 20f1117..4b3c01c 100644 (file)
@@ -29,6 +29,7 @@
 #include "Completion.h"
 #include "CopiedSpaceInlines.h"
 #include "Disassembler.h"
+#include "Exception.h"
 #include "ExceptionHelpers.h"
 #include "HeapStatistics.h"
 #include "InitializeThreading.h"
@@ -899,13 +900,13 @@ EncodedJSValue JSC_HOST_CALL functionRun(ExecState* exec)
     globalObject->putDirect(
         exec->vm(), Identifier::fromString(globalObject->globalExec(), "arguments"), array);
 
-    JSValue exception;
+    Exception* exception;
     StopWatch stopWatch;
     stopWatch.start();
-    evaluate(globalObject->globalExec(), jscSource(script.data(), fileName), JSValue(), &exception);
+    evaluate(globalObject->globalExec(), jscSource(script.data(), fileName), JSValue(), exception);
     stopWatch.stop();
 
-    if (!!exception) {
+    if (exception) {
         exec->vm().throwException(globalObject->globalExec(), exception);
         return JSValue::encode(jsUndefined());
     }
@@ -922,8 +923,8 @@ EncodedJSValue JSC_HOST_CALL functionLoad(ExecState* exec)
 
     JSGlobalObject* globalObject = exec->lexicalGlobalObject();
     
-    JSValue evaluationException;
-    JSValue result = evaluate(globalObject->globalExec(), jscSource(script.data(), fileName), JSValue(), &evaluationException);
+    Exception* evaluationException;
+    JSValue result = evaluate(globalObject->globalExec(), jscSource(script.data(), fileName), JSValue(), evaluationException);
     if (evaluationException)
         exec->vm().throwException(exec, evaluationException);
     return JSValue::encode(result);
@@ -1285,15 +1286,15 @@ static bool runWithScripts(GlobalObject* globalObject, const Vector<Script>& scr
 
         vm.startSampling();
 
-        JSValue evaluationException;
-        JSValue returnValue = evaluate(globalObject->globalExec(), jscSource(script, fileName), JSValue(), &evaluationException);
+        Exception* evaluationException;
+        JSValue returnValue = evaluate(globalObject->globalExec(), jscSource(script, fileName), JSValue(), evaluationException);
         success = success && !evaluationException;
         if (dump && !evaluationException)
             printf("End: %s\n", returnValue.toString(globalObject->globalExec())->value(globalObject->globalExec()).utf8().data());
         if (evaluationException) {
-            printf("Exception: %s\n", evaluationException.toString(globalObject->globalExec())->value(globalObject->globalExec()).utf8().data());
+            printf("Exception: %s\n", evaluationException->value().toString(globalObject->globalExec())->value(globalObject->globalExec()).utf8().data());
             Identifier stackID = Identifier::fromString(globalObject->globalExec(), "stack");
-            JSValue stackValue = evaluationException.get(globalObject->globalExec(), stackID);
+            JSValue stackValue = evaluationException->value().get(globalObject->globalExec(), stackID);
             if (!stackValue.isUndefinedOrNull())
                 printf("%s\n", stackValue.toString(globalObject->globalExec())->value(globalObject->globalExec()).utf8().data());
         }
@@ -1349,8 +1350,8 @@ static void runInteractive(GlobalObject* globalObject)
         }
         
         
-        JSValue evaluationException;
-        JSValue returnValue = evaluate(globalObject->globalExec(), makeSource(source, interpreterName), JSValue(), &evaluationException);
+        Exception* evaluationException;
+        JSValue returnValue = evaluate(globalObject->globalExec(), makeSource(source, interpreterName), JSValue(), evaluationException);
 #else
         printf("%s", interactivePrompt);
         Vector<char, 256> line;
@@ -1365,11 +1366,11 @@ static void runInteractive(GlobalObject* globalObject)
             break;
         line.append('\0');
 
-        JSValue evaluationException;
-        JSValue returnValue = evaluate(globalObject->globalExec(), jscSource(line.data(), interpreterName), JSValue(), &evaluationException);
+        Exception* evaluationException;
+        JSValue returnValue = evaluate(globalObject->globalExec(), jscSource(line.data(), interpreterName), JSValue(), evaluationException);
 #endif
         if (evaluationException)
-            printf("Exception: %s\n", evaluationException.toString(globalObject->globalExec())->value(globalObject->globalExec()).utf8().data());
+            printf("Exception: %s\n", evaluationException->value().toString(globalObject->globalExec())->value(globalObject->globalExec()).utf8().data());
         else
             printf("%s\n", returnValue.toString(globalObject->globalExec())->value(globalObject->globalExec()).utf8().data());
 
index dea3782..5e16174 100644 (file)
@@ -30,6 +30,7 @@
 #include "CommonSlowPaths.h"
 #include "Debugger.h"
 #include "DirectArguments.h"
+#include "Exception.h"
 #include "Executable.h"
 #include "Heap.h"
 #include "Interpreter.h"
index 8fb2cc9..9ccc1ce 100644 (file)
@@ -1375,8 +1375,7 @@ LLINT_SLOW_PATH_DECL(slow_path_profile_did_call)
 LLINT_SLOW_PATH_DECL(slow_path_handle_exception)
 {
     LLINT_BEGIN_NO_SET_PC();
-    ASSERT(vm.exception());
-    genericUnwind(&vm, exec, vm.exception());
+    genericUnwind(&vm, exec);
     LLINT_END_IMPL();
 }
 
index 5ac24a8..890fc02 100644 (file)
@@ -693,7 +693,7 @@ macro branchIfException(label)
     loadp Callee + PayloadOffset[cfr], t3
     andp MarkedBlockMask, t3
     loadp MarkedBlock::m_weakSet + WeakSet::m_vm[t3], t3
-    bieq VM::m_exception + TagOffset[t3], EmptyValueTag, .noException
+    btiz VM::m_exception[t3], .noException
     jmp label
 .noException:
 end
@@ -1952,15 +1952,20 @@ _llint_op_catch:
     restoreStackPointerAfterCall()
 
     loadi VM::targetInterpreterPCForThrow[t3], PC
-    loadi VM::m_exception + PayloadOffset[t3], t0
-    loadi VM::m_exception + TagOffset[t3], t1
-    storei 0, VM::m_exception + PayloadOffset[t3]
-    storei EmptyValueTag, VM::m_exception + TagOffset[t3]
+    loadi VM::m_exception[t3], t0
+    storei 0, VM::m_exception[t3]
     loadi 4[PC], t2
     storei t0, PayloadOffset[cfr, t2, 8]
+    storei CellTag, TagOffset[cfr, t2, 8]
+
+    loadi Exception::m_value + TagOffset[t0], t1
+    loadi Exception::m_value + PayloadOffset[t0], t0
+    loadi 8[PC], t2
+    storei t0, PayloadOffset[cfr, t2, 8]
     storei t1, TagOffset[cfr, t2, 8]
+
     traceExecution()  # This needs to be here because we don't want to clobber t0, t1, t2, t3 above.
-    dispatch(2)
+    dispatch(3)
 
 _llint_op_end:
     traceExecution()
@@ -2038,7 +2043,7 @@ macro nativeCallTrampoline(executableOffsetToFunction)
     end
     
     functionEpilogue()
-    bineq VM::m_exception + TagOffset[t3], EmptyValueTag, .handleException
+    btinz VM::m_exception[t3], .handleException
     ret
 
 .handleException:
index 0f11e67..7b8a713 100644 (file)
@@ -1820,12 +1820,18 @@ _llint_op_catch:
     loadp VM::targetInterpreterPCForThrow[t3], PC
     subp PB, PC
     rshiftp 3, PC
+
     loadq VM::m_exception[t3], t0
     storeq 0, VM::m_exception[t3]
     loadisFromInstruction(1, t2)
     storeq t0, [cfr, t2, 8]
+
+    loadq Exception::m_value[t0], t3
+    loadisFromInstruction(2, t2)
+    storeq t3, [cfr, t2, 8]
+
     traceExecution()
-    dispatch(2)
+    dispatch(3)
 
 
 _llint_op_end:
index 9546b71..fef0f72 100644 (file)
@@ -811,10 +811,10 @@ namespace JSC {
     {
     }
 
-    inline TryNode::TryNode(const JSTokenLocation& location, StatementNode* tryBlock, const Identifier& exceptionIdent, StatementNode* catchBlock, StatementNode* finallyBlock)
+    inline TryNode::TryNode(const JSTokenLocation& location, StatementNode* tryBlock, const Identifier& thrownValueIdent, StatementNode* catchBlock, StatementNode* finallyBlock)
         : StatementNode(location)
         , m_tryBlock(tryBlock)
-        , m_exceptionIdent(exceptionIdent)
+        , m_thrownValueIdent(thrownValueIdent)
         , m_catchBlock(catchBlock)
         , m_finallyBlock(finallyBlock)
     {
index 2a452ad..92f1a21 100644 (file)
@@ -1511,7 +1511,7 @@ namespace JSC {
         virtual void emitBytecode(BytecodeGenerator&, RegisterID* = 0) override;
 
         StatementNode* m_tryBlock;
-        const Identifier& m_exceptionIdent;
+        const Identifier& m_thrownValueIdent;
         StatementNode* m_catchBlock;
         StatementNode* m_finallyBlock;
     };
index 6d00109..fa76ebe 100644 (file)
@@ -26,6 +26,7 @@
 #include "config.h"
 #include "CallData.h"
 
+#include "Exception.h"
 #include "Executable.h"
 #include "Interpreter.h"
 #include "JSFunction.h"
@@ -39,15 +40,15 @@ 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 call(ExecState* exec, JSValue functionObject, CallType callType, const CallData& callData, JSValue thisValue, const ArgList& args, Exception*& returnedException)
 {
     JSValue result = call(exec, functionObject, callType, callData, thisValue, args);
     if (exec->hadException()) {
-        if (exception)
-            *exception = exec->exception();
+        returnedException = exec->exception();
         exec->clearException();
         return jsUndefined();
-    }
+    } else
+        returnedException = nullptr;
     RELEASE_ASSERT(result);
     return result;
 }
index b6edd37..640554a 100644 (file)
@@ -34,6 +34,7 @@
 namespace JSC {
 
 class ArgList;
+class Exception;
 class ExecState;
 class FunctionExecutable;
 class JSObject;
@@ -58,7 +59,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);
+JS_EXPORT_PRIVATE JSValue call(ExecState*, JSValue functionObject, CallType, const CallData&, JSValue thisValue, const ArgList&, Exception*& returnedException);
 
 } // namespace JSC
 
index 72244b8..b59baab 100644 (file)
@@ -26,6 +26,7 @@
 #include "CallFrame.h"
 #include "CodeProfiling.h"
 #include "Debugger.h"
+#include "Exception.h"
 #include "Interpreter.h"
 #include "JSGlobalObject.h"
 #include "JSLock.h"
@@ -60,19 +61,18 @@ bool checkSyntax(VM& vm, const SourceCode& source, ParserError& error)
         JSParserStrictMode::NotStrict, JSParserCodeType::Program, error);
 }
 
-JSValue evaluate(ExecState* exec, const SourceCode& source, JSValue thisValue, JSValue* returnedException)
+JSValue evaluate(ExecState* exec, const SourceCode& source, JSValue thisValue, Exception*& returnedException)
 {
     JSLockHolder lock(exec);
     RELEASE_ASSERT(exec->vm().atomicStringTable() == wtfThreadData().atomicStringTable());
     RELEASE_ASSERT(!exec->vm().isCollectorBusy());
+    returnedException = nullptr;
 
     CodeProfiling profile(source);
 
     ProgramExecutable* program = ProgramExecutable::create(exec, source);
     if (!program) {
-        if (returnedException)
-            *returnedException = exec->vm().exception();
-
+        returnedException = exec->vm().exception();
         exec->vm().clearException();
         return jsUndefined();
     }
@@ -83,9 +83,7 @@ JSValue evaluate(ExecState* exec, const SourceCode& source, JSValue thisValue, J
     JSValue result = exec->interpreter()->execute(program, exec, thisObj);
 
     if (exec->hadException()) {
-        if (returnedException)
-            *returnedException = exec->exception();
-
+        returnedException = exec->exception();
         exec->clearException();
         return jsUndefined();
     }
index 112331a..b6e7b75 100644 (file)
@@ -26,7 +26,8 @@
 #include "JSCJSValue.h"
 
 namespace JSC {
-    
+
+class Exception;
 class ExecState;
 class JSScope;
 class ParserError;
@@ -35,7 +36,12 @@ class VM;
 
 JS_EXPORT_PRIVATE bool checkSyntax(VM&, const SourceCode&, ParserError&);
 JS_EXPORT_PRIVATE bool checkSyntax(ExecState*, const SourceCode&, JSValue* exception = 0);
-JS_EXPORT_PRIVATE JSValue evaluate(ExecState*, const SourceCode&, JSValue thisValue = JSValue(), JSValue* exception = 0);
+JS_EXPORT_PRIVATE JSValue evaluate(ExecState*, const SourceCode&, JSValue thisValue, Exception*& returnedException);
+inline JSValue evaluate(ExecState* exec, const SourceCode& sourceCode, JSValue thisValue = JSValue())
+{
+    Exception* unused;
+    return evaluate(exec, sourceCode, thisValue, unused);
+}
 
 } // namespace JSC
 
index f53c0a4..017740e 100644 (file)
@@ -76,6 +76,7 @@ JS_EXPORT_PRIVATE JSObject* throwTypeError(ExecState*);
 JS_EXPORT_PRIVATE JSObject* throwSyntaxError(ExecState*);
 
 // Convenience wrappers, wrap result as an EncodedJSValue.
+inline void throwVMError(ExecState* exec, Exception* exception) { exec->vm().throwException(exec, exception); }
 inline EncodedJSValue throwVMError(ExecState* exec, JSValue error) { return JSValue::encode(exec->vm().throwException(exec, error)); }
 inline EncodedJSValue throwVMTypeError(ExecState* exec) { return JSValue::encode(throwTypeError(exec)); }
 inline EncodedJSValue throwVMTypeError(ExecState* exec, const String& errorMessage) { return JSValue::encode(throwTypeError(exec, errorMessage)); }
diff --git a/Source/JavaScriptCore/runtime/Exception.cpp b/Source/JavaScriptCore/runtime/Exception.cpp
new file mode 100644 (file)
index 0000000..9f5e40d
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2015 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "Exception.h"
+
+#include "JSCInlines.h"
+
+namespace JSC {
+
+const ClassInfo Exception::s_info = { "Exception", &Base::s_info, 0, CREATE_METHOD_TABLE(Exception) };
+
+Exception* Exception::create(VM& vm, JSValue thrownValue)
+{
+    Exception* result = new (NotNull, allocateCell<Exception>(vm.heap)) Exception(vm);
+    result->finishCreation(vm, thrownValue);
+    return result;
+}
+
+void Exception::destroy(JSCell* cell)
+{
+    Exception* exception = static_cast<Exception*>(cell);
+    exception->~Exception();
+}
+
+Structure* Exception::createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
+{
+    return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
+}
+
+void Exception::visitChildren(JSCell* cell, SlotVisitor& visitor)
+{
+    Exception* thisObject = jsCast<Exception*>(cell);
+    ASSERT_GC_OBJECT_INHERITS(thisObject, info());
+    Base::visitChildren(thisObject, visitor);
+
+    visitor.append(&thisObject->m_value);
+}
+
+Exception::Exception(VM& vm)
+    : Base(vm, vm.exceptionStructure.get())
+{
+}
+
+Exception::~Exception()
+{
+}
+
+void Exception::finishCreation(VM& vm, JSValue thrownValue)
+{
+    Base::finishCreation(vm);
+
+    m_value.set(vm, this, thrownValue);
+
+    Vector<StackFrame> stackTrace;
+    vm.interpreter->getStackTrace(stackTrace);
+    m_stack = RefCountedArray<StackFrame>(stackTrace);
+}
+
+} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/Exception.h b/Source/JavaScriptCore/runtime/Exception.h
new file mode 100644 (file)
index 0000000..aee4dd2
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2015 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef Exception_h
+#define Exception_h
+
+#include "Interpreter.h"
+#include <wtf/RefCountedArray.h>
+
+namespace JSC {
+    
+class Exception : public JSNonFinalObject {
+public:
+    typedef JSNonFinalObject Base;
+    static const unsigned StructureFlags = StructureIsImmortal | Base::StructureFlags;
+
+    static Exception* create(VM&, JSValue thrownValue);
+
+    static const bool needsDestruction = true;
+    static void destroy(JSCell*);
+
+    static Structure* createStructure(VM&, JSGlobalObject*, JSValue prototype);
+
+    static void visitChildren(JSCell*, SlotVisitor&);
+
+    DECLARE_EXPORT_INFO;
+
+    static ptrdiff_t valueOffset()
+    {
+        return OBJECT_OFFSETOF(Exception, m_value);
+    }
+
+    static Exception* cast(JSValue exceptionAsJSValue)
+    {
+        return jsCast<Exception*>(exceptionAsJSValue.asCell());
+    }
+
+    JSValue value() const { return m_value.get(); }
+    const RefCountedArray<StackFrame>& stack() const { return m_stack; }
+
+    bool didNotifyInspectorOfThrow() const { return m_didNotifyInspectorOfThrow; }
+    void setDidNotifyInspectorOfThrow() { m_didNotifyInspectorOfThrow = true; }
+
+    ~Exception();
+
+private:
+    Exception(VM&);
+    void finishCreation(VM&, JSValue thrownValue);
+
+    WriteBarrier<Unknown> m_value;
+    RefCountedArray<StackFrame> m_stack;
+    bool m_didNotifyInspectorOfThrow { false };
+
+    friend class LLIntOffsetsExtractor;
+};
+
+} // namespace JSC
+
+#endif // Exception_h
index b19fb59..7cdf36a 100644 (file)
@@ -32,6 +32,7 @@
 #include "CodeBlock.h"
 #include "CallFrame.h"
 #include "ErrorHandlingScope.h"
+#include "Exception.h"
 #include "JSGlobalObjectFunctions.h"
 #include "JSNotAnObject.h"
 #include "Interpreter.h"
@@ -59,17 +60,11 @@ JSObject* createTerminatedExecutionException(VM* vm)
     return TerminatedExecutionError::create(*vm);
 }
 
-bool isTerminatedExecutionException(JSObject* object)
+bool isTerminatedExecutionException(Exception* exception)
 {
-    return object->inherits(TerminatedExecutionError::info());
+    return exception->value().inherits(TerminatedExecutionError::info());
 }
 
-bool isTerminatedExecutionException(JSValue value)
-{
-    return value.inherits(TerminatedExecutionError::info());
-}
-
-
 JSObject* createStackOverflowError(ExecState* exec)
 {
     return createRangeError(exec, ASCIILiteral("Maximum call stack size exceeded."));
index d50e1d1..305ebef 100644 (file)
@@ -37,8 +37,7 @@ namespace JSC {
 typedef JSObject* (*ErrorFactory)(ExecState*, const String&, ErrorInstance::SourceAppender);
 
 JSObject* createTerminatedExecutionException(VM*);
-bool isTerminatedExecutionException(JSObject*);
-JS_EXPORT_PRIVATE bool isTerminatedExecutionException(JSValue);
+JS_EXPORT_PRIVATE bool isTerminatedExecutionException(Exception*);
 JS_EXPORT_PRIVATE JSObject* createError(ExecState*, JSValue, const String&, ErrorInstance::SourceAppender);
 JS_EXPORT_PRIVATE JSObject* createStackOverflowError(ExecState*);
 JSObject* createUndefinedVariableError(ExecState*, const Identifier&);
index 8e3374e..2cd66e5 100644 (file)
@@ -24,6 +24,7 @@
 #include "GetterSetter.h"
 
 #include "Error.h"
+#include "Exception.h"
 #include "JSObject.h"
 #include "JSCInlines.h"
 #include <wtf/Assertions.h>
@@ -75,7 +76,7 @@ JSValue callGetter(ExecState* exec, JSValue base, JSValue getterSetter)
     // FIXME: Some callers may invoke get() without checking for an exception first.
     // We work around that by checking here.
     if (exec->hadException())
-        return exec->exception();
+        return exec->exception()->value();
 
     JSObject* getter = jsCast<GetterSetter*>(getterSetter)->getter();
 
index 66a7d68..2e886bf 100644 (file)
@@ -89,7 +89,7 @@ JSValue iteratorStep(ExecState* exec, JSValue iterator)
 
 void iteratorClose(ExecState* exec, JSValue iterator)
 {
-    JSValue exception;
+    Exception* exception = nullptr;
     if (exec->hadException()) {
         exception = exec->exception();
         exec->clearException();
@@ -99,7 +99,7 @@ void iteratorClose(ExecState* exec, JSValue iterator)
         return;
 
     if (returnFunction.isUndefined()) {
-        if (!exception.isEmpty())
+        if (exception)
             exec->vm().throwException(exec, exception);
         return;
     }
@@ -107,7 +107,7 @@ void iteratorClose(ExecState* exec, JSValue iterator)
     CallData returnFunctionCallData;
     CallType returnFunctionCallType = getCallData(returnFunction, returnFunctionCallData);
     if (returnFunctionCallType == CallTypeNone) {
-        if (!exception.isEmpty())
+        if (exception)
             exec->vm().throwException(exec, exception);
         else
             throwTypeError(exec);
@@ -117,7 +117,7 @@ void iteratorClose(ExecState* exec, JSValue iterator)
     MarkedArgumentBuffer returnFunctionArguments;
     JSValue innerResult = call(exec, returnFunction, returnFunctionCallType, returnFunctionCallData, iterator, returnFunctionArguments);
 
-    if (!exception.isEmpty()) {
+    if (exception) {
         exec->vm().throwException(exec, exception);
         return;
     }
index 3a9d0e1..8b34efb 100644 (file)
@@ -31,6 +31,7 @@
 #include "CustomGetterSetter.h"
 #include "DatePrototype.h"
 #include "ErrorConstructor.h"
+#include "Exception.h"
 #include "Executable.h"
 #include "GetterSetter.h"
 #include "IndexingHeaderInlines.h"
index b8a5ada..bb8e4e0 100644 (file)
@@ -29,6 +29,7 @@
 #if ENABLE(PROMISES)
 
 #include "Error.h"
+#include "Exception.h"
 #include "IteratorOperations.h"
 #include "JSCJSValueInlines.h"
 #include "JSCellInlines.h"
@@ -136,7 +137,7 @@ static EncodedJSValue JSC_HOST_CALL constructPromise(ExecState* exec)
 
     // 14. If result is an abrupt completion, call PromiseReject(promise, result.[[value]]).
     if (exec->hadException()) {
-        JSValue exception = exec->exception();
+        JSValue exception = exec->exception()->value();
         exec->clearException();
 
         promise->reject(vm, exception);
index d82a1ce..7fd0c3c 100644 (file)
@@ -29,6 +29,7 @@
 #if ENABLE(PROMISES)
 
 #include "Error.h"
+#include "Exception.h"
 #include "JSCJSValueInlines.h"
 #include "JSCellInlines.h"
 #include "JSPromise.h"
@@ -150,7 +151,7 @@ ThenableStatus updateDeferredFromPotentialThenable(ExecState* exec, JSValue x, J
         // i. Let 'rejectResult' be the result of calling the [[Call]] internal method of
         //    deferred.[[Reject]] with undefined as thisArgument and a List containing
         //    then.[[value]] as argumentsList.
-        JSValue exception = exec->exception();
+        JSValue exception = exec->exception()->value();
         exec->clearException();
 
         performDeferredReject(exec, deferred, exception);
@@ -185,7 +186,7 @@ ThenableStatus updateDeferredFromPotentialThenable(ExecState* exec, JSValue x, J
         // i. Let 'rejectResult' be the result of calling the [[Call]] internal method of
         //    deferred.[[Reject]] with undefined as thisArgument and a List containing
         //    thenCallResult.[[value]] as argumentsList.
-        JSValue exception = exec->exception();
+        JSValue exception = exec->exception()->value();
         exec->clearException();
 
         performDeferredReject(exec, deferred, exception);
@@ -228,7 +229,7 @@ void performDeferredReject(ExecState* exec, JSPromiseDeferred* deferred, JSValue
 JSValue abruptRejection(ExecState* exec, JSPromiseDeferred* deferred)
 {
     ASSERT(exec->hadException());
-    JSValue argument = exec->exception();
+    JSValue argument = exec->exception()->value();
     exec->clearException();
 
     // i. Let 'rejectResult' be the result of calling the [[Call]] internal method
index 689abd2..1a94c71 100644 (file)
@@ -29,6 +29,7 @@
 #if ENABLE(PROMISES)
 
 #include "Error.h"
+#include "Exception.h"
 #include "JSCJSValueInlines.h"
 #include "JSCellInlines.h"
 #include "JSGlobalObject.h"
@@ -88,7 +89,7 @@ void ExecutePromiseReactionMicrotask::run(ExecState* exec)
     //    [[Call]] internal method of deferred.[[Reject]] passing undefined as thisArgument
     //    and a List containing handlerResult.[[value]] as argumentsList.
     if (exec->hadException()) {
-        JSValue exception = exec->exception();
+        JSValue exception = exec->exception()->value();
         exec->clearException();
 
         performDeferredReject(exec, deferred, exception);
index 7126e80..b89d3eb 100644 (file)
@@ -42,6 +42,7 @@
 #include "DFGWorklist.h"
 #include "Disassembler.h"
 #include "ErrorInstance.h"
+#include "Exception.h"
 #include "FTLThunks.h"
 #include "FunctionConstructor.h"
 #include "GCActivityCallback.h"
@@ -235,6 +236,7 @@ VM::VM(VMType vmType, HeapType heapType)
     weakMapDataStructure.set(*this, WeakMapData::createStructure(*this, 0, jsNull()));
     inferredValueStructure.set(*this, InferredValue::createStructure(*this, 0, jsNull()));
     functionRareDataStructure.set(*this, FunctionRareData::createStructure(*this, 0, jsNull()));
+    exceptionStructure.set(*this, Exception::createStructure(*this, 0, jsNull()));
 #if ENABLE(PROMISES)
     promiseDeferredStructure.set(*this, JSPromiseDeferred::createStructure(*this, 0, jsNull()));
     promiseReactionStructure.set(*this, JSPromiseReaction::createStructure(*this, 0, jsNull()));
@@ -545,7 +547,7 @@ void VM::releaseExecutableMemory()
     heap.collectAllGarbage();
 }
 
-JSValue VM::throwException(ExecState* exec, JSValue error)
+void VM::throwException(ExecState* exec, Exception* exception)
 {
     if (Options::breakOnThrow()) {
         dataLog("In call frame ", RawPointer(exec), " for code block ", *exec->codeBlock(), "\n");
@@ -553,37 +555,22 @@ JSValue VM::throwException(ExecState* exec, JSValue error)
     }
     
     ASSERT(exec == topCallFrame || exec == exec->lexicalGlobalObject()->globalExec() || exec == exec->vmEntryGlobalObject()->globalExec());
-    
-    Vector<StackFrame> stackTrace;
-    interpreter->getStackTrace(stackTrace);
-    m_exceptionStack = RefCountedArray<StackFrame>(stackTrace);
-    m_exception = error;
-
-    return error;
-}
-    
-JSObject* VM::throwException(ExecState* exec, JSObject* error)
-{
-    return asObject(throwException(exec, JSValue(error)));
-}
-void VM::getExceptionInfo(JSValue& exception, RefCountedArray<StackFrame>& exceptionStack)
-{
-    exception = m_exception;
-    exceptionStack = m_exceptionStack;
-}
-void VM::setExceptionInfo(JSValue& exception, RefCountedArray<StackFrame>& exceptionStack)
-{
-    m_exception = exception;
-    m_exceptionStack = exceptionStack;
+    setException(exception);
 }
 
-void VM::clearException()
+JSValue VM::throwException(ExecState* exec, JSValue thrownValue)
 {
-    m_exception = JSValue();
+    Exception* exception = jsDynamicCast<Exception*>(thrownValue);
+    if (!exception)
+        exception = Exception::create(*this, thrownValue);
+
+    throwException(exec, exception);
+    return JSValue(exception);
 }
-void VM:: clearExceptionStack()
+
+JSObject* VM::throwException(ExecState* exec, JSObject* error)
 {
-    m_exceptionStack = RefCountedArray<StackFrame>();
+    return asObject(throwException(exec, JSValue(error)));
 }
 
 void VM::setStackPointerAtVMEntry(void* sp)
index 3bbdaf1..478161d 100644 (file)
@@ -58,7 +58,6 @@
 #include <wtf/Forward.h>
 #include <wtf/HashMap.h>
 #include <wtf/HashSet.h>
-#include <wtf/RefCountedArray.h>
 #include <wtf/SimpleStats.h>
 #include <wtf/StackBounds.h>
 #include <wtf/ThreadSafeRefCounted.h>
@@ -78,6 +77,7 @@ class CodeBlock;
 class CodeCache;
 class CommonIdentifiers;
 class ExecState;
+class Exception;
 class HandleStack;
 class TypeProfiler;
 class TypeProfilerLog;
@@ -274,6 +274,7 @@ public:
     Strong<Structure> weakMapDataStructure;
     Strong<Structure> inferredValueStructure;
     Strong<Structure> functionRareDataStructure;
+    Strong<Structure> exceptionStructure;
 #if ENABLE(PROMISES)
     Strong<Structure> promiseDeferredStructure;
     Strong<Structure> promiseReactionStructure;
@@ -372,14 +373,13 @@ public:
         return OBJECT_OFFSETOF(VM, targetMachinePCForThrow);
     }
 
-    JS_EXPORT_PRIVATE void clearException();
-    JS_EXPORT_PRIVATE void clearExceptionStack();
-    void getExceptionInfo(JSValue& exception, RefCountedArray<StackFrame>& exceptionStack);
-    void setExceptionInfo(JSValue& exception, RefCountedArray<StackFrame>& exceptionStack);
-    JSValue exception() const { return m_exception; }
-    JSValue* addressOfException() { return &m_exception; }
-    const RefCountedArray<StackFrame>& exceptionStack() const { return m_exceptionStack; }
+    void clearException() { m_exception = nullptr; }
+    void setException(Exception* exception) { m_exception = exception; }
 
+    Exception* exception() const { return m_exception; }
+    JSCell** addressOfException() { return reinterpret_cast<JSCell**>(&m_exception); }
+
+    JS_EXPORT_PRIVATE void throwException(ExecState*, Exception*);
     JS_EXPORT_PRIVATE JSValue throwException(ExecState*, JSValue);
     JS_EXPORT_PRIVATE JSObject* throwException(ExecState*, JSObject*);
 
@@ -569,12 +569,11 @@ private:
 #endif
 #endif
     void* m_lastStackTop;
-    JSValue m_exception;
+    Exception* m_exception { nullptr };
     bool m_inDefineOwnProperty;
     std::unique_ptr<CodeCache> m_codeCache;
     LegacyProfiler* m_enabledProfiler;
     std::unique_ptr<BuiltinExecutables> m_builtinExecutables;
-    RefCountedArray<StackFrame> m_exceptionStack;
     HashMap<String, RefPtr<WatchpointSet>> m_impurePropertyWatchpointSets;
     std::unique_ptr<TypeProfiler> m_typeProfiler;
     std::unique_ptr<TypeProfilerLog> m_typeProfilerLog;
index a7d36c3..a3bada4 100644 (file)
@@ -49,9 +49,6 @@ VMEntryScope::VMEntryScope(VM& vm, JSGlobalObject* globalObject)
         // observe time xone changes.
         vm.resetDateCache();
     }
-
-    // Clear the captured exception stack between entries
-    vm.clearExceptionStack();
 }
 
 void VMEntryScope::setEntryScopeDidPopListener(void* key, EntryScopeDidPopListener listener)
index 01385a7..ae0a4a9 100644 (file)
@@ -1,3 +1,81 @@
+2015-06-05  Mark Lam  <mark.lam@apple.com>
+
+        finally blocks should not set the exception stack trace when re-throwing the exception.
+        https://bugs.webkit.org/show_bug.cgi?id=145525
+
+        Reviewed by Geoffrey Garen.
+
+        Update to use the new JSC::Exception object.
+
+        Test: inspector/debugger/break-on-exceptions.html
+
+        * ForwardingHeaders/runtime/Exception.h: Added.
+        * bindings/js/JSCallbackData.cpp:
+        (WebCore::JSCallbackData::invokeCallback):
+        * bindings/js/JSCustomXPathNSResolver.cpp:
+        (WebCore::JSCustomXPathNSResolver::lookupNamespaceURI):
+        * bindings/js/JSDOMBinding.cpp:
+        (WebCore::jsArray):
+        (WebCore::reportException):
+        (WebCore::reportCurrentException):
+        * bindings/js/JSDOMBinding.h:
+        * bindings/js/JSErrorHandler.cpp:
+        (WebCore::JSErrorHandler::handleEvent):
+        * bindings/js/JSEventListener.cpp:
+        (WebCore::JSEventListener::handleEvent):
+        * bindings/js/JSMainThreadExecState.cpp:
+        (WebCore::JSMainThreadExecState::didLeaveScriptContext):
+        (WebCore::functionCallHandlerFromAnyThread):
+        (WebCore::evaluateHandlerFromAnyThread):
+        * bindings/js/JSMainThreadExecState.h:
+        (WebCore::JSMainThreadExecState::currentState):
+        (WebCore::JSMainThreadExecState::call):
+        (WebCore::JSMainThreadExecState::evaluate):
+        (WebCore::JSMainThreadExecState::runTask):
+
+        * bindings/js/JSMediaDevicesCustom.cpp:
+        (WebCore::JSMediaDevices::getUserMedia):
+        - Fixed a bug where the exception was not cleared before entering the VM to
+          call JS code.
+
+        * bindings/js/JSMutationCallback.cpp:
+        (WebCore::JSMutationCallback::call):
+        * bindings/js/ReadableJSStream.cpp:
+        (WebCore::getPropertyFromObject):
+        (WebCore::callFunction):
+        (WebCore::ReadableJSStream::Source::start):
+        * bindings/js/ScheduledAction.cpp:
+        (WebCore::ScheduledAction::executeFunctionInContext):
+        * bindings/js/ScriptController.cpp:
+        (WebCore::ScriptController::evaluateInWorld):
+        * bindings/js/SerializedScriptValue.cpp:
+        (WebCore::SerializedScriptValue::create):
+        (WebCore::SerializedScriptValue::deserialize):
+        * bindings/js/WorkerScriptController.cpp:
+        (WebCore::WorkerScriptController::evaluate):
+        (WebCore::WorkerScriptController::setException):
+        (WebCore::WorkerScriptController::scheduleExecutionTermination):
+        * bindings/js/WorkerScriptController.h:
+        (WebCore::WorkerScriptController::workerGlobalScopeWrapper):
+        * bindings/js/WorkerScriptDebugServer.cpp:
+        (WebCore::WorkerScriptDebugServer::runEventLoopWhilePaused):
+        (WebCore::WorkerScriptDebugServer::reportException):
+        * bindings/js/WorkerScriptDebugServer.h:
+        * bindings/objc/WebScriptObject.mm:
+        (WebCore::createJSWrapper):
+        (WebCore::addExceptionToConsole):
+        (-[WebScriptObject callWebScriptMethod:withArguments:]):
+        (-[WebScriptObject evaluateWebScript:]):
+        - Changed to call a version of JSMainThreadExecState::evaluate() that provides
+          a stub returnedException because evaluateWebScript: doesn't need the exception.
+
+        * inspector/PageScriptDebugServer.cpp:
+        (WebCore::PageScriptDebugServer::isContentScript):
+        (WebCore::PageScriptDebugServer::reportException):
+        * inspector/PageScriptDebugServer.h:
+        * workers/WorkerGlobalScope.cpp:
+        (WebCore::WorkerGlobalScope::importScripts):
+
 2015-06-05  Eric Carlson  <eric.carlson@apple.com>
 
         Layout tests fullscreen/video-controls-drag.html and media/video-fullscreeen-only-controls.html
diff --git a/Source/WebCore/ForwardingHeaders/runtime/Exception.h b/Source/WebCore/ForwardingHeaders/runtime/Exception.h
new file mode 100644 (file)
index 0000000..0838a05
--- /dev/null
@@ -0,0 +1,4 @@
+#ifndef WebCore_FWD_Exception_h
+#define WebCore_FWD_Exception_h
+#include <JavaScriptCore/Exception.h>
+#endif
index 451dac6..f95584b 100644 (file)
@@ -73,10 +73,10 @@ JSValue JSCallbackData::invokeCallback(JSValue thisValue, MarkedArgumentBuffer&
 
     InspectorInstrumentationCookie cookie = JSMainThreadExecState::instrumentFunctionCall(context, callType, callData);
 
-    JSValue exception;
+    Exception* exception;
     JSValue result = context->isDocument()
-        ? JSMainThreadExecState::call(exec, function, callType, callData, thisValue, args, &exception)
-        : JSC::call(exec, function, callType, callData, thisValue, args, &exception);
+        ? JSMainThreadExecState::call(exec, function, callType, callData, thisValue, args, exception)
+        : JSC::call(exec, function, callType, callData, thisValue, args, exception);
 
     InspectorInstrumentation::didCallFunction(cookie, context);
 
index 07d22df..124d8cf 100644 (file)
@@ -93,8 +93,8 @@ String JSCustomXPathNSResolver::lookupNamespaceURI(const String& prefix)
     MarkedArgumentBuffer args;
     args.append(jsStringWithCache(exec, prefix));
 
-    JSValue exception;
-    JSValue retval = JSMainThreadExecState::call(exec, function, callType, callData, m_customResolver.get(), args, &exception);
+    Exception* exception;
+    JSValue retval = JSMainThreadExecState::call(exec, function, callType, callData, m_customResolver.get(), args, exception);
 
     String result;
     if (exception)
index 7952871..2215e0f 100644 (file)
@@ -40,6 +40,7 @@
 #include <runtime/DateInstance.h>
 #include <runtime/Error.h>
 #include <runtime/ErrorHandlingScope.h>
+#include <runtime/Exception.h>
 #include <runtime/ExceptionHelpers.h>
 #include <runtime/JSFunction.h>
 #include <stdarg.h>
@@ -138,7 +139,7 @@ JSC::JSValue jsArray(JSC::ExecState* exec, JSDOMGlobalObject* globalObject, Pass
     return JSC::constructArray(exec, 0, globalObject, list);
 }
 
-void reportException(ExecState* exec, JSValue exception, CachedScript* cachedScript)
+void reportException(ExecState* exec, Exception* exception, CachedScript* cachedScript)
 {
     RELEASE_ASSERT(exec->vm().currentThreadIsHoldingAPILock());
     if (isTerminatedExecutionException(exception))
@@ -148,7 +149,6 @@ void reportException(ExecState* exec, JSValue exception, CachedScript* cachedScr
 
     RefPtr<ScriptCallStack> callStack(createScriptCallStackFromException(exec, exception, ScriptCallStack::maxCallStackSizeToCapture));
     exec->clearException();
-    exec->clearSupplementaryExceptionInfo();
 
     JSDOMGlobalObject* globalObject = jsCast<JSDOMGlobalObject*>(exec->lexicalGlobalObject());
     if (JSDOMWindow* window = jsDynamicCast<JSDOMWindow*>(globalObject)) {
@@ -166,14 +166,13 @@ void reportException(ExecState* exec, JSValue exception, CachedScript* cachedScr
     }
 
     String errorMessage;
-    if (ExceptionBase* exceptionBase = toExceptionBase(exception))
+    if (ExceptionBase* exceptionBase = toExceptionBase(exception->value()))
         errorMessage = exceptionBase->message() + ": "  + exceptionBase->description();
     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);
+        errorMessage = exception->value().toString(exec)->value(exec);
         exec->clearException();
-        exec->clearSupplementaryExceptionInfo();
     }
 
     ScriptExecutionContext* scriptExecutionContext = globalObject->scriptExecutionContext();
@@ -182,7 +181,7 @@ void reportException(ExecState* exec, JSValue exception, CachedScript* cachedScr
 
 void reportCurrentException(ExecState* exec)
 {
-    JSValue exception = exec->exception();
+    Exception* exception = exec->exception();
     exec->clearException();
     reportException(exec, exception);
 }
index 3a2bab5..9b12d29 100644 (file)
@@ -247,7 +247,7 @@ void addImpureProperty(const AtomicString&);
 
 const JSC::HashTable& getHashTableForGlobalData(JSC::VM&, const JSC::HashTable& staticTable);
 
-WEBCORE_EXPORT void reportException(JSC::ExecState*, JSC::JSValue exception, CachedScript* = nullptr);
+WEBCORE_EXPORT void reportException(JSC::ExecState*, JSC::Exception*, CachedScript* = nullptr);
 void reportCurrentException(JSC::ExecState*);
 
 JSC::JSValue createDOMException(JSC::ExecState*, ExceptionCode);
index c2ec578..34ea93b 100644 (file)
@@ -98,10 +98,10 @@ void JSErrorHandler::handleEvent(ScriptExecutionContext* scriptExecutionContext,
         VM& vm = globalObject->vm();
         VMEntryScope entryScope(vm, vm.entryScope ? vm.entryScope->globalObject() : globalObject);
 
-        JSValue exception;
+        Exception* exception;
         JSValue returnValue = scriptExecutionContext->isDocument()
-            ? JSMainThreadExecState::call(exec, jsFunction, callType, callData, globalObject, args, &exception)
-            : JSC::call(exec, jsFunction, callType, callData, globalObject, args, &exception);
+            ? JSMainThreadExecState::call(exec, jsFunction, callType, callData, globalObject, args, exception)
+            : JSC::call(exec, jsFunction, callType, callData, globalObject, args, exception);
 
         globalObject->setCurrentEvent(savedEvent);
 
index 1e2cbea..a3262aa 100644 (file)
@@ -124,10 +124,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;
+        Exception* exception;
         JSValue retval = scriptExecutionContext->isDocument()
-            ? JSMainThreadExecState::call(exec, handleEventFunction, callType, callData, thisValue, args, &exception)
-            : JSC::call(exec, handleEventFunction, callType, callData, thisValue, args, &exception);
+            ? JSMainThreadExecState::call(exec, handleEventFunction, callType, callData, thisValue, args, exception)
+            : JSC::call(exec, handleEventFunction, callType, callData, thisValue, args, exception);
 
         InspectorInstrumentation::didCallFunction(cookie, scriptExecutionContext);
 
index 06e92f2..2fa95e7 100644 (file)
@@ -46,18 +46,18 @@ 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* exception)
+JSC::JSValue functionCallHandlerFromAnyThread(JSC::ExecState* exec, JSC::JSValue functionObject, JSC::CallType callType, const JSC::CallData& callData, JSC::JSValue thisValue, const JSC::ArgList& args, JSC::Exception*& returnedException)
 {
     if (isMainThread())
-        return JSMainThreadExecState::call(exec, functionObject, callType, callData, thisValue, args, exception);
-    return JSC::call(exec, functionObject, callType, callData, thisValue, args, exception);
+        return JSMainThreadExecState::call(exec, functionObject, callType, callData, thisValue, args, returnedException);
+    return JSC::call(exec, functionObject, callType, callData, thisValue, args, returnedException);
 }
 
-JSC::JSValue evaluateHandlerFromAnyThread(JSC::ExecState* exec, const JSC::SourceCode& source, JSC::JSValue thisValue, JSC::JSValue* exception)
+JSC::JSValue evaluateHandlerFromAnyThread(JSC::ExecState* exec, const JSC::SourceCode& source, JSC::JSValue thisValue, JSC::Exception*& returnedException)
 {
     if (isMainThread())
-        return JSMainThreadExecState::evaluate(exec, source, thisValue, exception);
-    return JSC::evaluate(exec, source, thisValue, exception);
+        return JSMainThreadExecState::evaluate(exec, source, thisValue, returnedException);
+    return JSC::evaluate(exec, source, thisValue, returnedException);
 }
 
 } // namespace WebCore
index c157b0f..a823a4b 100644 (file)
@@ -50,16 +50,22 @@ 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, JSC::JSValue* exception)
+    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::Exception*& returnedException)
     {
         JSMainThreadExecState currentState(exec);
-        return JSC::call(exec, functionObject, callType, callData, thisValue, args, exception);
+        return JSC::call(exec, functionObject, callType, callData, thisValue, args, returnedException);
     };
 
-    static JSC::JSValue evaluate(JSC::ExecState* exec, const JSC::SourceCode& source, JSC::JSValue thisValue, JSC::JSValue* exception)
+    static JSC::JSValue evaluate(JSC::ExecState* exec, const JSC::SourceCode& source, JSC::JSValue thisValue, JSC::Exception*& returnedException)
     {
         JSMainThreadExecState currentState(exec);
-        return JSC::evaluate(exec, source, thisValue, exception);
+        return JSC::evaluate(exec, source, thisValue, returnedException);
+    };
+
+    static JSC::JSValue evaluate(JSC::ExecState* exec, const JSC::SourceCode& source, JSC::JSValue thisValue = JSC::JSValue())
+    {
+        JSC::Exception* unused;
+        return evaluate(exec, source, thisValue, unused);
     };
 
     static void runTask(JSC::ExecState* exec, JSC::Microtask& task)
@@ -121,8 +127,8 @@ private:
     JSC::ExecState* m_previousState;
 };
 
-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);
+JSC::JSValue functionCallHandlerFromAnyThread(JSC::ExecState*, JSC::JSValue functionObject, JSC::CallType, const JSC::CallData&, JSC::JSValue thisValue, const JSC::ArgList& args, JSC::Exception*& returnedException);
+JSC::JSValue evaluateHandlerFromAnyThread(JSC::ExecState*, const JSC::SourceCode&, JSC::JSValue thisValue, JSC::Exception*& returnedException);
 
 } // namespace WebCore
 
index 91149d8..fe5d9f0 100644 (file)
@@ -39,6 +39,7 @@
 #include "JSDOMPromise.h"
 #include "JSMediaStream.h"
 #include "JSNavigatorUserMediaError.h"
+#include <runtime/Exception.h>
 
 using namespace JSC;
 
@@ -50,7 +51,9 @@ JSValue JSMediaDevices::getUserMedia(ExecState* exec)
 
     Dictionary options(exec, exec->argument(0));
     if (exec->hadException()) {
-        wrapper.reject(exec->exception());
+        Exception* exception = exec->exception();
+        exec->clearException();
+        wrapper.reject(exception->value());
         return wrapper.promise();
     }
 
index 7eb357a..94784e1 100644 (file)
@@ -87,8 +87,8 @@ void JSMutationCallback::call(const Vector<RefPtr<MutationRecord>>& mutations, M
 
     InspectorInstrumentationCookie cookie = JSMainThreadExecState::instrumentFunctionCall(context, callType, callData);
 
-    JSValue exception;
-    JSMainThreadExecState::call(exec, callback, callType, callData, jsObserver, args, &exception);
+    Exception* exception;
+    JSMainThreadExecState::call(exec, callback, callType, callData, jsObserver, args, exception);
 
     InspectorInstrumentation::didCallFunction(cookie, context);
 
index 1a55a5b..77b2afa 100644 (file)
@@ -52,7 +52,7 @@ static inline JSValue getPropertyFromObject(ExecState* exec, JSObject* object, c
     return object->get(exec, Identifier::fromString(exec, identifier));
 }
 
-static inline JSValue callFunction(ExecState* exec, JSValue jsFunction, JSValue thisValue, const ArgList& arguments, JSValue* exception)
+static inline JSValue callFunction(ExecState* exec, JSValue jsFunction, JSValue thisValue, const ArgList& arguments, Exception*& exception)
 {
     CallData callData;
     CallType callType = getCallData(jsFunction, callData);
@@ -88,8 +88,8 @@ void ReadableJSStream::doStart(ExecState& exec)
     MarkedArgumentBuffer arguments;
     arguments.append(jsController(exec, globalObject()));
 
-    JSValue exception;
-    callFunction(&exec, startFunction, m_source.get(), arguments, &exception);
+    Exception* exception;
+    callFunction(&exec, startFunction, m_source.get(), arguments, exception);
 
     if (exception) {
         throwVMError(&exec, exception);
index 060e6fa..adeea60 100644 (file)
@@ -99,11 +99,11 @@ void ScheduledAction::executeFunctionInContext(JSGlobalObject* globalObject, JSV
 
     InspectorInstrumentationCookie cookie = JSMainThreadExecState::instrumentFunctionCall(&context, callType, callData);
 
-    JSValue exception;
+    Exception* exception;
     if (is<Document>(context))
-        JSMainThreadExecState::call(exec, m_function.get(), callType, callData, thisValue, args, &exception);
+        JSMainThreadExecState::call(exec, m_function.get(), callType, callData, thisValue, args, exception);
     else
-        JSC::call(exec, m_function.get(), callType, callData, thisValue, args, &exception);
+        JSC::call(exec, m_function.get(), callType, callData, thisValue, args, exception);
 
     InspectorInstrumentation::didCallFunction(cookie, &context);
 
index e0d50a1..cf299cc 100644 (file)
@@ -160,9 +160,8 @@ Deprecated::ScriptValue ScriptController::evaluateInWorld(const ScriptSourceCode
 
     InspectorInstrumentationCookie cookie = InspectorInstrumentation::willEvaluateScript(m_frame, sourceURL, sourceCode.startLine());
 
-    JSValue evaluationException;
-
-    JSValue returnValue = JSMainThreadExecState::evaluate(exec, jsSourceCode, shell, &evaluationException);
+    Exception* evaluationException;
+    JSValue returnValue = JSMainThreadExecState::evaluate(exec, jsSourceCode, shell, evaluationException);
 
     InspectorInstrumentation::didEvaluateScript(cookie, m_frame);
 
index bc9ebe9..6786119 100644 (file)
@@ -55,6 +55,7 @@
 #include <runtime/BooleanObject.h>
 #include <runtime/DateInstance.h>
 #include <runtime/Error.h>
+#include <runtime/Exception.h>
 #include <runtime/ExceptionHelpers.h>
 #include <runtime/JSArrayBuffer.h>
 #include <runtime/JSArrayBufferView.h>
@@ -2702,7 +2703,7 @@ PassRefPtr<SerializedScriptValue> SerializedScriptValue::create(JSContextRef ori
     RefPtr<SerializedScriptValue> serializedValue = SerializedScriptValue::create(exec, value, nullptr, nullptr);
     if (exec->hadException()) {
         if (exception)
-            *exception = toRef(exec, exec->exception());
+            *exception = toRef(exec, exec->exception()->value());
         exec->clearException();
         return 0;
     }
@@ -2732,7 +2733,7 @@ JSValueRef SerializedScriptValue::deserialize(JSContextRef destinationContext, J
     JSValue value = deserialize(exec, exec->lexicalGlobalObject(), nullptr);
     if (exec->hadException()) {
         if (exception)
-            *exception = toRef(exec, exec->exception());
+            *exception = toRef(exec, exec->exception()->value());
         exec->clearException();
         return nullptr;
     }
index c02e4c2..f8a62d3 100644 (file)
@@ -40,6 +40,7 @@
 #include <heap/StrongInlines.h>
 #include <interpreter/Interpreter.h>
 #include <runtime/Completion.h>
+#include <runtime/Exception.h>
 #include <runtime/ExceptionHelpers.h>
 #include <runtime/Error.h>
 #include <runtime/JSLock.h>
@@ -98,15 +99,15 @@ void WorkerScriptController::evaluate(const ScriptSourceCode& sourceCode)
     if (isExecutionForbidden())
         return;
 
-    Deprecated::ScriptValue exception;
-    evaluate(sourceCode, &exception);
-    if (exception.jsValue()) {
+    Exception* exception;
+    evaluate(sourceCode, exception);
+    if (exception) {
         JSLockHolder lock(vm());
-        reportException(m_workerGlobalScopeWrapper->globalExec(), exception.jsValue());
+        reportException(m_workerGlobalScopeWrapper->globalExec(), exception);
     }
 }
 
-void WorkerScriptController::evaluate(const ScriptSourceCode& sourceCode, Deprecated::ScriptValue* exception)
+void WorkerScriptController::evaluate(const ScriptSourceCode& sourceCode, JSC::Exception*& returnedException)
 {
     if (isExecutionForbidden())
         return;
@@ -116,8 +117,8 @@ void WorkerScriptController::evaluate(const ScriptSourceCode& sourceCode, Deprec
     ExecState* exec = m_workerGlobalScopeWrapper->globalExec();
     JSLockHolder lock(exec);
 
-    JSValue evaluationException;
-    JSC::evaluate(exec, sourceCode.jsSourceCode(), m_workerGlobalScopeWrapper->globalThis(), &evaluationException);
+    JSC::Exception* evaluationException;
+    JSC::evaluate(exec, sourceCode.jsSourceCode(), m_workerGlobalScopeWrapper->globalThis(), evaluationException);
 
     VM& vm = exec->vm();
     if ((evaluationException && isTerminatedExecutionException(evaluationException)) 
@@ -131,16 +132,19 @@ void WorkerScriptController::evaluate(const ScriptSourceCode& sourceCode, Deprec
         int lineNumber = 0;
         int columnNumber = 0;
         String sourceURL = sourceCode.url().string();
-        if (m_workerGlobalScope->sanitizeScriptError(errorMessage, lineNumber, columnNumber, sourceURL, sourceCode.cachedScript()))
-            *exception = Deprecated::ScriptValue(*m_vm, exec->vm().throwException(exec, createError(exec, errorMessage.impl())));
-        else
-            *exception = Deprecated::ScriptValue(*m_vm, evaluationException);
+        if (m_workerGlobalScope->sanitizeScriptError(errorMessage, lineNumber, columnNumber, sourceURL, sourceCode.cachedScript())) {
+            vm.throwException(exec, createError(exec, errorMessage.impl()));
+            evaluationException = vm.exception();
+            vm.clearException();
+        }
     }
+    returnedException = evaluationException;
 }
 
-void WorkerScriptController::setException(const Deprecated::ScriptValue& exception)
+void WorkerScriptController::setException(JSC::Exception* exception)
 {
-    m_workerGlobalScopeWrapper->globalExec()->vm().throwException(m_workerGlobalScopeWrapper->globalExec(), exception.jsValue());
+    JSC::ExecState* exec = m_workerGlobalScopeWrapper->globalExec();
+    exec->vm().throwException(exec, exception);
 }
 
 void WorkerScriptController::scheduleExecutionTermination()
index ec7ba3a..f678099 100644 (file)
@@ -60,9 +60,9 @@ namespace WebCore {
         }
 
         void evaluate(const ScriptSourceCode&);
-        void evaluate(const ScriptSourceCode&, Deprecated::ScriptValue* exception);
+        void evaluate(const ScriptSourceCode&, JSC::Exception*& returnedException);
 
-        void setException(const Deprecated::ScriptValue&);
+        void setException(JSC::Exception*);
 
         // Async request to terminate a JS run execution. Eventually causes termination
         // exception raised during JS execution, if the worker thread happens to run JS.
index 6c00c69..dd759b0 100644 (file)
@@ -99,7 +99,7 @@ void WorkerScriptDebugServer::runEventLoopWhilePaused()
     } while (result != MessageQueueTerminated && !m_doneProcessingDebuggerEvents);
 }
 
-void WorkerScriptDebugServer::reportException(JSC::ExecState* exec, JSC::JSValue exception) const
+void WorkerScriptDebugServer::reportException(JSC::ExecState* exec, JSC::Exception* exception) const
 {
     WebCore::reportException(exec, exception);
 }
index ed8958c..7881f61 100644 (file)
@@ -56,7 +56,7 @@ private:
     virtual void didContinue(JSC::JSGlobalObject*) override { }
     virtual void runEventLoopWhilePaused() override;
     virtual bool isContentScript(JSC::ExecState*) const override { return false; }
-    virtual void reportException(JSC::ExecState*, JSC::JSValue) const override;
+    virtual void reportException(JSC::ExecState*, JSC::Exception*) const override;
 
     WorkerGlobalScope* m_workerGlobalScope;
     ListenerSet m_listeners;
index 3a93ebf..8644b89 100644 (file)
@@ -121,7 +121,7 @@ id createJSWrapper(JSC::JSObject* object, PassRefPtr<JSC::Bindings::RootObject>
     return [[[WebScriptObject alloc] _initWithJSObject:object originRootObject:origin rootObject:root] autorelease];
 }
 
-static void addExceptionToConsole(ExecState* exec, JSC::JSValue& exception)
+static void addExceptionToConsole(ExecState* exec, JSC::Exception* exception)
 {
     JSDOMWindow* window = asJSDOMWindow(exec->vmEntryGlobalObject());
     if (!window || !exception)
@@ -131,7 +131,7 @@ static void addExceptionToConsole(ExecState* exec, JSC::JSValue& exception)
 
 static void addExceptionToConsole(ExecState* exec)
 {
-    JSC::JSValue exception = exec->exception();
+    JSC::Exception* exception = exec->exception();
     exec->clearException();
     addExceptionToConsole(exec, exception);
 }
@@ -342,8 +342,8 @@ static void getListFromNSArray(ExecState *exec, NSArray *array, RootObject* root
     if (![self _isSafeScript])
         return nil;
 
-    JSC::JSValue exception;
-    JSC::JSValue result = JSMainThreadExecState::call(exec, function, callType, callData, [self _imp], argList, &exception);
+    JSC::Exception* exception;
+    JSC::JSValue result = JSMainThreadExecState::call(exec, function, callType, callData, [self _imp], argList, exception);
 
     if (exception) {
         addExceptionToConsole(exec, exception);
@@ -366,7 +366,7 @@ static void getListFromNSArray(ExecState *exec, NSArray *array, RootObject* root
 
     JSLockHolder lock(exec);
     
-    JSC::JSValue returnValue = JSMainThreadExecState::evaluate(exec, makeSource(String(script)), JSC::JSValue(), 0);
+    JSC::JSValue returnValue = JSMainThreadExecState::evaluate(exec, makeSource(String(script)), JSC::JSValue());
 
     id resultObj = [WebScriptObject _convertValueToObjcValue:returnValue originRootObject:[self _originRootObject] rootObject:[self _rootObject]];
     
index 958cbfe..dbd11cd 100644 (file)
@@ -137,7 +137,7 @@ bool PageScriptDebugServer::isContentScript(ExecState* exec) const
     return &currentWorld(exec) != &mainThreadNormalWorld();
 }
 
-void PageScriptDebugServer::reportException(ExecState* exec, JSValue exception) const
+void PageScriptDebugServer::reportException(ExecState* exec, Exception* exception) const
 {
     WebCore::reportException(exec, exception);
 }
index 73d1607..d224f67 100644 (file)
@@ -54,7 +54,7 @@ private:
     virtual void didContinue(JSC::JSGlobalObject*) override;
     virtual void runEventLoopWhilePaused() override;
     virtual bool isContentScript(JSC::ExecState*) const override;
-    virtual void reportException(JSC::ExecState*, JSC::JSValue) const override;
+    virtual void reportException(JSC::ExecState*, JSC::Exception*) const override;
 
     void runEventLoopWhilePausedInternal();
 
index 2a640d1..9635da4 100644 (file)
@@ -197,9 +197,9 @@ void WorkerGlobalScope::importScripts(const Vector<String>& urls, ExceptionCode&
 
         InspectorInstrumentation::scriptImported(scriptExecutionContext(), scriptLoader->identifier(), scriptLoader->script());
 
-        Deprecated::ScriptValue exception;
-        m_script->evaluate(ScriptSourceCode(scriptLoader->script(), scriptLoader->responseURL()), &exception);
-        if (!exception.hasNoValue()) {
+        JSC::Exception* exception;
+        m_script->evaluate(ScriptSourceCode(scriptLoader->script(), scriptLoader->responseURL()), exception);
+        if (exception) {
             m_script->setException(exception);
             return;
         }
index dfd3d01..da0a182 100644 (file)
@@ -1,3 +1,15 @@
+2015-06-05  Mark Lam  <mark.lam@apple.com>
+
+        finally blocks should not set the exception stack trace when re-throwing the exception.
+        https://bugs.webkit.org/show_bug.cgi?id=145525
+
+        Reviewed by Geoffrey Garen.
+
+        * WebView/WebView.mm:
+        (+[WebView _reportException:inContext:]):
+        (WebKitInitializeApplicationCachePathIfNecessary):
+        - Changed to use the new Exception object.
+
 2015-06-03  Anders Carlsson  <andersca@apple.com>
 
         Define WK_ENABLE_FORMAL_DELEGATE_PROTOCOLS on iOS
index 68886cf..183680c 100644 (file)
 #import <CoreFoundation/CFSet.h>
 #import <Foundation/NSURLConnection.h>
 #import <JavaScriptCore/APICast.h>
+#import <JavaScriptCore/Exception.h>
 #import <JavaScriptCore/JSValueRef.h>
 #import <WebCore/AlternativeTextUIController.h>
 #import <WebCore/AnimationController.h>
@@ -724,7 +725,8 @@ static String webKitBundleVersionString()
     if (!toJSDOMWindow(execState->lexicalGlobalObject()))
         return;
 
-    reportException(execState, toJS(execState, exception));
+    Exception* vmException = Exception::cast(toJS(execState, exception));
+    reportException(execState, vmException);
 }
 
 static void WebKitInitializeApplicationCachePathIfNecessary()
index 73a33de..0ed9346 100644 (file)
@@ -1,3 +1,14 @@
+2015-06-05  Mark Lam  <mark.lam@apple.com>
+
+        finally blocks should not set the exception stack trace when re-throwing the exception.
+        https://bugs.webkit.org/show_bug.cgi?id=145525
+
+        Reviewed by Geoffrey Garen.
+
+        * WebView.cpp:
+        (WebView::reportException):
+        - Changed to use the new Exception object.
+
 2015-06-02  Brady Eidson  <beidson@apple.com>
 
         WebKit policy delegate should suggest if a navigation should be allowed to open URLs externally.
index 65f7a0e..9e3d93d 100644 (file)
@@ -72,6 +72,7 @@
 #include "WebVisitedLinkStore.h"
 #include "resource.h"
 #include <JavaScriptCore/APICast.h>
+#include <JavaScriptCore/Exception.h>
 #include <JavaScriptCore/InitializeThreading.h>
 #include <JavaScriptCore/JSCJSValue.h>
 #include <JavaScriptCore/JSLock.h>
@@ -6029,7 +6030,8 @@ HRESULT STDMETHODCALLTYPE WebView::reportException(
     if (!toJSDOMWindow(execState->lexicalGlobalObject()))
         return E_FAIL;
 
-    WebCore::reportException(execState, toJS(execState, exception));
+    JSC::Exception* vmException = JSC::Exception::cast(toJS(execState, exception));
+    WebCore::reportException(execState, vmException);
     return S_OK;
 }
 
index 30e966c..2215225 100644 (file)
@@ -1,3 +1,14 @@
+2015-06-05  Mark Lam  <mark.lam@apple.com>
+
+        finally blocks should not set the exception stack trace when re-throwing the exception.
+        https://bugs.webkit.org/show_bug.cgi?id=145525
+
+        Reviewed by Geoffrey Garen.
+
+        * WebProcess/InjectedBundle/InjectedBundle.cpp:
+        (WebKit::InjectedBundle::reportException):
+        - Changed to use the new Exception object.
+
 2015-06-05  Anders Carlsson  <andersca@apple.com>
 
         Disable the CFNetwork cache in the web process
index 62876d4..9c9d3ee 100644 (file)
@@ -50,6 +50,7 @@
 #include "WebProcessCreationParameters.h"
 #include "WebProcessPoolMessages.h"
 #include <JavaScriptCore/APICast.h>
+#include <JavaScriptCore/Exception.h>
 #include <JavaScriptCore/JSLock.h>
 #include <WebCore/ApplicationCache.h>
 #include <WebCore/ApplicationCacheStorage.h>
@@ -522,7 +523,7 @@ void InjectedBundle::reportException(JSContextRef context, JSValueRef exception)
     if (!toJSDOMWindow(execState->lexicalGlobalObject()))
         return;
 
-    WebCore::reportException(execState, toJS(execState, exception));
+    WebCore::reportException(execState, Exception::cast(toJS(execState, exception)));
 }
 
 void InjectedBundle::didCreatePage(WebPage* page)