aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml/jsruntime
diff options
context:
space:
mode:
authorSimon Hausmann <simon.hausmann@digia.com>2013-09-11 13:23:21 +0200
committerThe Qt Project <gerrit-noreply@qt-project.org>2013-10-02 16:07:33 +0200
commitc860d1399b4ff5f3a5b1b2630bc33112c88c13e8 (patch)
tree3e6cdd7b209cc343dd791827d07bb69a700e7043 /src/qml/jsruntime
parentc1d66eec1dbaf9034e03e3efa0403a774c764373 (diff)
Change exception handling API
This patch changes the exception handling API in the engine slightly, encapsulating any use of direct throw statements and catch blocks with concrete types. In the future we need to be able to change the way these are implemented, in order to ensure that the correct stack unwinding code is triggered for throw and re-throw. This patch separates the C++ exception object thrown from the V4 exception (that includes value, throwing context pointer) and stores the latter inside the engine. In order for that to compile, ExecutionEngine::StackTrace and StackFrame had to move into the QV4 namespace directly. In addition the syntax for catching exceptions changes from try { ... } catch (QV4::Exception &ex) { ex.accept(context); QV4::ScopedValue exceptionValue(scope, ex.value()); } to try { ... } catch (...) { QV4::ScopedValue exception(scope, context->catchException()); } Context::catchException() checks if there's a "current" exception in the engine, and if not assumes that we caught an unrelated exception and consequently re-throws. partiallyUnwind() is also gone and replaced with rethrowException(), in order to encapsulate the re-throw. Lastly, in the future nesting try/catch blocks isn't going to be possible due to limitations in the common C++ ABI with regards to foreign exceptions. Change-Id: Ic81c75b057a2147e3176d8e0b4d326c14278b47d Reviewed-by: Lars Knoll <lars.knoll@digia.com>
Diffstat (limited to 'src/qml/jsruntime')
-rw-r--r--src/qml/jsruntime/qv4context.cpp27
-rw-r--r--src/qml/jsruntime/qv4context_p.h4
-rw-r--r--src/qml/jsruntime/qv4engine.cpp8
-rw-r--r--src/qml/jsruntime/qv4engine_p.h10
-rw-r--r--src/qml/jsruntime/qv4errorobject.cpp4
-rw-r--r--src/qml/jsruntime/qv4errorobject_p.h2
-rw-r--r--src/qml/jsruntime/qv4exception.cpp55
-rw-r--r--src/qml/jsruntime/qv4exception_gcc.cpp13
-rw-r--r--src/qml/jsruntime/qv4exception_p.h27
-rw-r--r--src/qml/jsruntime/qv4function_p.h2
-rw-r--r--src/qml/jsruntime/qv4functionobject.cpp30
-rw-r--r--src/qml/jsruntime/qv4global_p.h10
-rw-r--r--src/qml/jsruntime/qv4globalobject.cpp6
-rw-r--r--src/qml/jsruntime/qv4include.cpp14
-rw-r--r--src/qml/jsruntime/qv4qobjectwrapper.cpp8
-rw-r--r--src/qml/jsruntime/qv4runtime.cpp3
-rw-r--r--src/qml/jsruntime/qv4script.cpp8
-rw-r--r--src/qml/jsruntime/qv4sequenceobject.cpp2
-rw-r--r--src/qml/jsruntime/qv4serialize.cpp4
-rw-r--r--src/qml/jsruntime/qv4value.cpp15
-rw-r--r--src/qml/jsruntime/qv4vme_moth.cpp14
21 files changed, 130 insertions, 136 deletions
diff --git a/src/qml/jsruntime/qv4context.cpp b/src/qml/jsruntime/qv4context.cpp
index 0e08f025c2..78bf662c26 100644
--- a/src/qml/jsruntime/qv4context.cpp
+++ b/src/qml/jsruntime/qv4context.cpp
@@ -48,6 +48,7 @@
#include <qv4argumentsobject_p.h>
#include "qv4function_p.h"
#include "qv4errorobject_p.h"
+#include "qv4exception_p.h"
using namespace QV4;
@@ -597,7 +598,7 @@ ReturnedValue ExecutionContext::getPropertyAndBase(const StringRef name, ObjectR
void ExecutionContext::throwError(const ValueRef value)
{
- __qmljs_throw(this, value);
+ Exception::throwException(this, value);
}
void ExecutionContext::throwError(const QString &message)
@@ -644,6 +645,30 @@ void ExecutionContext::throwUnimplemented(const QString &message)
throwError(v);
}
+ReturnedValue ExecutionContext::catchException(StackTrace *trace)
+{
+ if (!engine->hasException)
+ throw;
+ while (engine->current != this)
+ engine->popContext();
+ if (trace)
+ *trace = engine->exceptionStackTrace;
+ engine->exceptionStackTrace.clear();
+ engine->hasException = false;
+ ReturnedValue res = engine->exceptionValue.asReturnedValue();
+ engine->exceptionValue = Encode::undefined();
+ return res;
+}
+
+void ExecutionContext::rethrowException()
+{
+ if (engine->hasException) {
+ while (engine->current != this)
+ engine->popContext();
+ }
+ throw;
+}
+
void ExecutionContext::throwReferenceError(const ValueRef value)
{
Scope scope(this);
diff --git a/src/qml/jsruntime/qv4context_p.h b/src/qml/jsruntime/qv4context_p.h
index d368dc6c81..2535161713 100644
--- a/src/qml/jsruntime/qv4context_p.h
+++ b/src/qml/jsruntime/qv4context_p.h
@@ -143,6 +143,10 @@ struct Q_QML_EXPORT ExecutionContext
ReturnedValue getPropertyAndBase(const StringRef name, ObjectRef base);
bool deleteProperty(const StringRef name);
+ // Can only be called from within catch(...), rethrows if no JS exception.
+ ReturnedValue catchException(StackTrace *trace = 0);
+ void Q_NORETURN rethrowException();
+
void mark();
inline CallContext *asCallContext();
diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp
index 8032197174..ba7241b081 100644
--- a/src/qml/jsruntime/qv4engine.cpp
+++ b/src/qml/jsruntime/qv4engine.cpp
@@ -67,6 +67,7 @@
#include "qv4qobjectwrapper_p.h"
#include "qv4qmlextensions_p.h"
#include "qv4stacktrace_p.h"
+#include "qv4exception_p.h"
#ifdef V4_ENABLE_JIT
#include "qv4isel_masm_p.h"
@@ -103,6 +104,7 @@ ExecutionEngine::ExecutionEngine(QQmlJS::EvalISelFactory *factory)
MemoryManager::GCBlocker gcBlocker(memoryManager);
exceptionValue = Encode::undefined();
+ hasException = false;
if (!factory) {
@@ -572,7 +574,7 @@ namespace {
{
}
- void resolve(ExecutionEngine::StackFrame *frame, ExecutionContext *context, Function *function)
+ void resolve(StackFrame *frame, ExecutionContext *context, Function *function)
{
if (context->interpreterInstructionPointer) {
qptrdiff offset = *context->interpreterInstructionPointer - 1 - function->codeData;
@@ -589,7 +591,7 @@ namespace {
};
}
-QVector<ExecutionEngine::StackFrame> ExecutionEngine::stackTrace(int frameLimit) const
+QVector<StackFrame> ExecutionEngine::stackTrace(int frameLimit) const
{
LineNumberResolver lineNumbers(this);
@@ -628,7 +630,7 @@ QVector<ExecutionEngine::StackFrame> ExecutionEngine::stackTrace(int frameLimit)
return stack;
}
-ExecutionEngine::StackFrame ExecutionEngine::currentStackFrame() const
+StackFrame ExecutionEngine::currentStackFrame() const
{
StackFrame frame;
frame.line = -1;
diff --git a/src/qml/jsruntime/qv4engine_p.h b/src/qml/jsruntime/qv4engine_p.h
index 79a4d3bef6..9a83ddc2a2 100644
--- a/src/qml/jsruntime/qv4engine_p.h
+++ b/src/qml/jsruntime/qv4engine_p.h
@@ -111,6 +111,7 @@ class MultiplyWrappedQObjectMap;
class RegExp;
class RegExpCache;
struct QmlExtensions;
+struct Exception;
struct Q_QML_EXPORT ExecutionEngine
{
@@ -237,6 +238,8 @@ struct Q_QML_EXPORT ExecutionEngine
RegExpCache *regExpCache;
SafeValue exceptionValue;
+ bool hasException;
+ StackTrace exceptionStackTrace;
// Scarce resources are "exceptionally high cost" QVariant types where allowing the
// normal JavaScript GC to clean them up is likely to lead to out-of-memory or other
@@ -305,13 +308,6 @@ struct Q_QML_EXPORT ExecutionEngine
Returned<Object> *qmlContextObject() const;
- struct StackFrame {
- QString source;
- QString function;
- int line;
- int column;
- };
- typedef QVector<StackFrame> StackTrace;
StackTrace stackTrace(int frameLimit = -1) const;
StackFrame currentStackFrame() const;
QUrl resolvedUrl(const QString &file);
diff --git a/src/qml/jsruntime/qv4errorobject.cpp b/src/qml/jsruntime/qv4errorobject.cpp
index b247c1533d..58375ea51e 100644
--- a/src/qml/jsruntime/qv4errorobject.cpp
+++ b/src/qml/jsruntime/qv4errorobject.cpp
@@ -152,7 +152,7 @@ ErrorObject::ErrorObject(InternalClass *ic, const QString &message, const QStrin
defineDefaultProperty(QStringLiteral("name"), (s = ic->engine->newString(className())));
stackTrace = ic->engine->stackTrace();
- ExecutionEngine::StackFrame frame;
+ StackFrame frame;
frame.source = fileName;
frame.line = line;
frame.column = column;
@@ -177,7 +177,7 @@ ReturnedValue ErrorObject::method_get_stack(SimpleCallContext *ctx)
for (int i = 0; i < This->stackTrace.count(); ++i) {
if (i > 0)
trace += QLatin1Char('\n');
- const ExecutionEngine::StackFrame &frame = This->stackTrace[i];
+ const StackFrame &frame = This->stackTrace[i];
trace += frame.function;
trace += QLatin1Char('@');
trace += frame.source;
diff --git a/src/qml/jsruntime/qv4errorobject_p.h b/src/qml/jsruntime/qv4errorobject_p.h
index d48edfa15e..ff43f54f3e 100644
--- a/src/qml/jsruntime/qv4errorobject_p.h
+++ b/src/qml/jsruntime/qv4errorobject_p.h
@@ -70,7 +70,7 @@ struct ErrorObject: Object {
SyntaxErrorObject *asSyntaxError();
- ExecutionEngine::StackTrace stackTrace;
+ StackTrace stackTrace;
String *stack;
static ReturnedValue method_get_stack(SimpleCallContext *ctx);
diff --git a/src/qml/jsruntime/qv4exception.cpp b/src/qml/jsruntime/qv4exception.cpp
index 64e6bef1fd..f55dc949a9 100644
--- a/src/qml/jsruntime/qv4exception.cpp
+++ b/src/qml/jsruntime/qv4exception.cpp
@@ -58,6 +58,17 @@ using namespace QV4;
void Exception::throwException(ExecutionContext *context, const ValueRef value)
{
+ ExecutionEngine *engine = context->engine;
+ Q_ASSERT(!engine->hasException);
+ engine->hasException = true;
+ engine->exceptionValue = value;
+ QV4::Scope scope(engine);
+ QV4::Scoped<ErrorObject> error(scope, value);
+ if (!!error)
+ engine->exceptionStackTrace = error->stackTrace;
+ else
+ engine->exceptionStackTrace = engine->stackTrace();
+
if (context->engine->debugger)
context->engine->debugger->aboutToThrow(value);
@@ -83,48 +94,16 @@ void Exception::throwException(ExecutionContext *context, const ValueRef value)
printf("stack walked. throwing exception now...\n");
#endif
- throwInternal(context, value);
-}
-
-Exception::Exception(ExecutionContext *throwingContext, const ValueRef exceptionValue)
- : e(throwingContext->engine)
-{
- e->exceptionValue = exceptionValue;
- this->throwingContext = throwingContext->engine->current;
- accepted = false;
- if (ErrorObject *error = exceptionValue->asErrorObject())
- m_stackTrace = error->stackTrace;
- else
- m_stackTrace = throwingContext->engine->stackTrace();
-}
-
-Exception::~Exception()
-{
- assert(accepted);
- e->exceptionValue = Primitive::undefinedValue();
-}
-
-void Exception::accept(ExecutionContext *catchingContext)
-{
- assert(!accepted);
- accepted = true;
- partiallyUnwindContext(catchingContext);
-}
-
-void Exception::partiallyUnwindContext(ExecutionContext *catchingContext)
-{
- if (!throwingContext)
- return;
- ExecutionContext *context = throwingContext;
- while (context != catchingContext)
- context = context->engine->popContext();
- throwingContext = context;
+ throwInternal();
}
#if !defined(V4_CXX_ABI_EXCEPTION)
-void Exception::throwInternal(ExecutionContext *throwingContext, const ValueRef exceptionValue)
+struct DummyException
+{};
+
+void Exception::throwInternal()
{
- throw Exception(throwingContext, exceptionValue);
+ throw DummyException();
}
#endif
diff --git a/src/qml/jsruntime/qv4exception_gcc.cpp b/src/qml/jsruntime/qv4exception_gcc.cpp
index 5eb5fc2178..0d230ea3fb 100644
--- a/src/qml/jsruntime/qv4exception_gcc.cpp
+++ b/src/qml/jsruntime/qv4exception_gcc.cpp
@@ -100,25 +100,30 @@ static void exception_cleanup(_Unwind_Reason_Code, _Unwind_Exception *ex)
}
}
+struct DummyException
+{
+ virtual ~DummyException() {}
+};
+
static void exception_destructor(void *ex)
{
- reinterpret_cast<QV4::Exception *>(ex)->~Exception();
+ reinterpret_cast<DummyException *>(ex)->~DummyException();
}
QT_BEGIN_NAMESPACE
using namespace QV4;
-void Exception::throwInternal(ExecutionContext *throwingContext, const ValueRef exceptionValue)
+void Exception::throwInternal()
{
void *rawException = abi::__cxa_allocate_exception(sizeof(QV4::Exception));
gcc_refcounted_compatible_exception *refCountedException = reinterpret_cast<gcc_refcounted_compatible_exception *>(rawException) - 1;
cxa_exception *exception = &refCountedException->x;
- (void)new (rawException) Exception(throwingContext, exceptionValue);
+ (void)new (rawException) DummyException();
refCountedException->refCount = 1;
- exception->typeInfo = const_cast<std::type_info*>(&typeid(Exception));
+ exception->typeInfo = const_cast<std::type_info*>(&typeid(DummyException));
exception->exceptionDestructor = &exception_destructor;
exception->unexpectedHandler = std::unexpected;
exception->terminateHandler = std::terminate;
diff --git a/src/qml/jsruntime/qv4exception_p.h b/src/qml/jsruntime/qv4exception_p.h
index a373ef205b..1f02d11f65 100644
--- a/src/qml/jsruntime/qv4exception_p.h
+++ b/src/qml/jsruntime/qv4exception_p.h
@@ -38,8 +38,8 @@
** $QT_END_LICENSE$
**
****************************************************************************/
-#ifndef QV4EXCEPTION_GNU_P
-#define QV4EXCEPTION_GNU_P
+#ifndef QV4EXCEPTION_P
+#define QV4EXCEPTION_P
#include <qglobal.h>
#include "qv4value_p.h"
@@ -52,31 +52,12 @@ namespace QV4 {
struct Q_QML_EXPORT Exception {
static void Q_NORETURN throwException(ExecutionContext *throwingContext, const ValueRef exceptionValue);
- ~Exception();
-
- void accept(ExecutionContext *catchingContext);
-
- void partiallyUnwindContext(ExecutionContext *catchingContext);
-
- ReturnedValue value() const { return e->exceptionValue.asReturnedValue(); }
-
- ExecutionEngine::StackTrace stackTrace() const { return m_stackTrace; }
- ExecutionEngine *engine() const { return e; }
-
private:
- void *operator new(size_t, void *p) { return p; }
-
- explicit Exception(ExecutionContext *throwingContext, const ValueRef exceptionValue);
-
- ExecutionEngine *e;
- ExecutionContext *throwingContext;
- bool accepted;
- ExecutionEngine::StackTrace m_stackTrace;
- static void Q_NORETURN throwInternal(ExecutionContext *throwingContext, const ValueRef exceptionValue);
+ static void Q_NORETURN throwInternal();
};
} // namespace QV4
QT_END_NAMESPACE
-#endif // QV4EXCEPTION_GNU_P
+#endif // QV4EXCEPTION_P
diff --git a/src/qml/jsruntime/qv4function_p.h b/src/qml/jsruntime/qv4function_p.h
index ca984e0059..34ab5df73a 100644
--- a/src/qml/jsruntime/qv4function_p.h
+++ b/src/qml/jsruntime/qv4function_p.h
@@ -91,7 +91,7 @@ struct Function {
return codePtr(ctx, data);
} catch (...) {
ctx->engine->jsStackTop = stack;
- throw;
+ ctx->rethrowException();
}
}
diff --git a/src/qml/jsruntime/qv4functionobject.cpp b/src/qml/jsruntime/qv4functionobject.cpp
index 7ef0b96f17..305efba1d6 100644
--- a/src/qml/jsruntime/qv4functionobject.cpp
+++ b/src/qml/jsruntime/qv4functionobject.cpp
@@ -450,9 +450,8 @@ ReturnedValue ScriptFunction::construct(Managed *that, CallData *callData)
SAVE_JS_STACK(f->scope);
try {
result = f->function->code(ctx, f->function->codeData);
- } catch (Exception &ex) {
- ex.partiallyUnwindContext(context);
- throw;
+ } catch (...) {
+ context->rethrowException();
}
CHECK_JS_STACK(f->scope);
ctx->engine->popContext();
@@ -482,9 +481,8 @@ ReturnedValue ScriptFunction::call(Managed *that, CallData *callData)
SAVE_JS_STACK(f->scope);
try {
result = f->function->code(ctx, f->function->codeData);
- } catch (Exception &ex) {
- ex.partiallyUnwindContext(context);
- throw;
+ } catch (...) {
+ context->rethrowException();
}
CHECK_JS_STACK(f->scope);
ctx->engine->popContext();
@@ -553,9 +551,8 @@ ReturnedValue SimpleScriptFunction::construct(Managed *that, CallData *callData)
if (!result)
return obj.asReturnedValue();
return result.asReturnedValue();
- } catch (Exception &ex) {
- ex.partiallyUnwindContext(context);
- throw;
+ } catch (...) {
+ context->rethrowException();
}
}
@@ -581,9 +578,8 @@ ReturnedValue SimpleScriptFunction::call(Managed *that, CallData *callData)
SAVE_JS_STACK(f->scope);
try {
result = f->function->code(ctx, f->function->codeData);
- } catch (Exception &ex) {
- ex.partiallyUnwindContext(context);
- throw;
+ } catch (...) {
+ context->rethrowException();
}
CHECK_JS_STACK(f->scope);
ctx->engine->popContext();
@@ -625,9 +621,8 @@ ReturnedValue BuiltinFunction::call(Managed *that, CallData *callData)
ScopedValue result(scope);
try {
result = f->code(&ctx);
- } catch (Exception &ex) {
- ex.partiallyUnwindContext(context);
- throw;
+ } catch (...) {
+ context->rethrowException();
}
context->engine->popContext();
@@ -650,9 +645,8 @@ ReturnedValue IndexedBuiltinFunction::call(Managed *that, CallData *callData)
ScopedValue result(scope);
try {
result = f->code(&ctx, f->index);
- } catch (Exception &ex) {
- ex.partiallyUnwindContext(context);
- throw;
+ } catch (...) {
+ context->rethrowException();
}
context->engine->popContext();
diff --git a/src/qml/jsruntime/qv4global_p.h b/src/qml/jsruntime/qv4global_p.h
index 01c5245a54..3569247459 100644
--- a/src/qml/jsruntime/qv4global_p.h
+++ b/src/qml/jsruntime/qv4global_p.h
@@ -43,7 +43,7 @@
#define QV4GLOBAL_H
#include <QtCore/qglobal.h>
-
+#include <QString>
#include <qtqmlglobal.h>
#if defined(Q_CC_MSVC)
@@ -232,6 +232,14 @@ struct PropertyAttributes
}
};
+struct StackFrame {
+ QString source;
+ QString function;
+ int line;
+ int column;
+};
+typedef QVector<StackFrame> StackTrace;
+
}
Q_DECLARE_TYPEINFO(QV4::PropertyAttributes, Q_PRIMITIVE_TYPE);
diff --git a/src/qml/jsruntime/qv4globalobject.cpp b/src/qml/jsruntime/qv4globalobject.cpp
index cbf6ddc1c6..a465fdc729 100644
--- a/src/qml/jsruntime/qv4globalobject.cpp
+++ b/src/qml/jsruntime/qv4globalobject.cpp
@@ -412,13 +412,11 @@ ReturnedValue EvalFunction::evalCall(CallData *callData, bool directCall)
ScopedValue result(scope);
try {
result = function->code(ctx, function->codeData);
- } catch (Exception &ex) {
+ } catch (...) {
ctx->strictMode = cstrict;
ctx->currentEvalCode = evalCode.next;
ctx->compilationUnit = oldCompilationUnit;
- if (strictMode)
- ex.partiallyUnwindContext(parentContext);
- throw;
+ ctx->rethrowException();
}
ctx->strictMode = cstrict;
diff --git a/src/qml/jsruntime/qv4include.cpp b/src/qml/jsruntime/qv4include.cpp
index 37db745622..44ba05990b 100644
--- a/src/qml/jsruntime/qv4include.cpp
+++ b/src/qml/jsruntime/qv4include.cpp
@@ -115,8 +115,8 @@ void QV4Include::callback(const QV4::ValueRef callback, const QV4::ValueRef stat
callData->thisObject = v4->globalObject->asReturnedValue();
callData->args[0] = status;
f->call(callData);
- } catch (QV4::Exception &e) {
- e.accept(ctx);
+ } catch (...) {
+ ctx->catchException();
}
}
@@ -162,10 +162,9 @@ void QV4Include::finished()
script.parse();
script.run();
resultObj->put(status, QV4::ScopedValue(scope, QV4::Primitive::fromInt32(Ok)));
- } catch (QV4::Exception &e) {
- e.accept(ctx);
+ } catch (...) {
+ QV4::ScopedValue ex(scope, ctx->catchException());
resultObj->put(status, QV4::ScopedValue(scope, QV4::Primitive::fromInt32(Exception)));
- QV4::ScopedValue ex(scope, e.value());
resultObj->put(QV4::ScopedString(scope, v4->newString("exception")), ex);
}
} else {
@@ -228,10 +227,9 @@ QV4::ReturnedValue QV4Include::method_include(QV4::SimpleCallContext *ctx)
script.parse();
script.run();
result = resultValue(v4, Ok);
- } catch (QV4::Exception &e) {
- e.accept(ctx);
+ } catch (...) {
+ QV4::ScopedValue ex(scope, ctx->catchException());
result = resultValue(v4, Exception);
- QV4::ScopedValue ex(scope, e.value());
result->asObject()->put(QV4::ScopedString(scope, v4->newString("exception")), ex);
}
} else {
diff --git a/src/qml/jsruntime/qv4qobjectwrapper.cpp b/src/qml/jsruntime/qv4qobjectwrapper.cpp
index 8be1343ac5..6e474ecc5d 100644
--- a/src/qml/jsruntime/qv4qobjectwrapper.cpp
+++ b/src/qml/jsruntime/qv4qobjectwrapper.cpp
@@ -453,7 +453,7 @@ bool QObjectWrapper::setQmlProperty(ExecutionContext *ctx, QQmlContextData *qmlC
// binding assignment.
QQmlContextData *callingQmlContext = QV4::QmlContextWrapper::callingContext(ctx->engine);
- QV4::ExecutionEngine::StackFrame frame = ctx->engine->currentStackFrame();
+ QV4::StackFrame frame = ctx->engine->currentStackFrame();
newBinding = new QQmlBinding(value, object, callingQmlContext, frame.source,
qmlSourceCoordinate(frame.line), qmlSourceCoordinate(frame.column));
@@ -723,10 +723,8 @@ struct QObjectSlotDispatcher : public QtPrivate::QSlotObjectBase
try {
f->call(callData);
- } catch (QV4::Exception &e) {
- e.accept(ctx);
- QQmlError error;
- QQmlExpressionPrivate::exceptionToError(e, error);
+ } catch (...) {
+ QQmlError error = QQmlError::catchJavaScriptException(ctx);
if (error.description().isEmpty())
error.setDescription(QString(QLatin1String("Unknown exception occurred during evaluation of connected function: %1")).arg(f->name->toQString()));
QQmlEnginePrivate::get(v4->v8Engine->engine())->warning(error);
diff --git a/src/qml/jsruntime/qv4runtime.cpp b/src/qml/jsruntime/qv4runtime.cpp
index 6002346678..b8b62c1bb7 100644
--- a/src/qml/jsruntime/qv4runtime.cpp
+++ b/src/qml/jsruntime/qv4runtime.cpp
@@ -49,7 +49,6 @@
#include "qv4argumentsobject_p.h"
#include "qv4lookup_p.h"
#include "qv4function_p.h"
-#include "qv4exception_p.h"
#include "private/qlocale_tools_p.h"
#include "qv4scopedvalue_p.h"
@@ -878,7 +877,7 @@ ReturnedValue __qmljs_construct_property(ExecutionContext *context, const ValueR
void __qmljs_throw(ExecutionContext *context, const ValueRef value)
{
- Exception::throwException(context, value);
+ context->throwError(value);
}
ReturnedValue __qmljs_builtin_typeof(ExecutionContext *ctx, const ValueRef value)
diff --git a/src/qml/jsruntime/qv4script.cpp b/src/qml/jsruntime/qv4script.cpp
index 0dddbe87e7..e320656664 100644
--- a/src/qml/jsruntime/qv4script.cpp
+++ b/src/qml/jsruntime/qv4script.cpp
@@ -252,11 +252,11 @@ ReturnedValue Script::run()
QV4::ScopedValue result(valueScope);
try {
result = vmFunction->code(scope, vmFunction->codeData);
- } catch (Exception &e) {
+ } catch (...) {
scope->strictMode = strict;
scope->lookups = oldLookups;
scope->compilationUnit = oldCompilationUnit;
- throw;
+ scope->rethrowException();
}
scope->lookups = oldLookups;
@@ -379,8 +379,8 @@ QV4::ReturnedValue Script::evaluate(ExecutionEngine *engine, const QString &scr
try {
qmlScript.parse();
return qmlScript.run();
- } catch (QV4::Exception &e) {
- e.accept(ctx);
+ } catch (...) {
+ ctx->catchException();
}
return Encode::undefined();
}
diff --git a/src/qml/jsruntime/qv4sequenceobject.cpp b/src/qml/jsruntime/qv4sequenceobject.cpp
index 5c8f7db97e..8d3dd97e83 100644
--- a/src/qml/jsruntime/qv4sequenceobject.cpp
+++ b/src/qml/jsruntime/qv4sequenceobject.cpp
@@ -63,7 +63,7 @@ static void generateWarning(QV4::ExecutionContext *ctx, const QString& descripti
QQmlError retn;
retn.setDescription(description);
- QV4::ExecutionEngine::StackFrame frame = ctx->engine->currentStackFrame();
+ QV4::StackFrame frame = ctx->engine->currentStackFrame();
retn.setLine(frame.line);
retn.setUrl(QUrl(frame.source));
diff --git a/src/qml/jsruntime/qv4serialize.cpp b/src/qml/jsruntime/qv4serialize.cpp
index 7d3214e8f8..d38897c37c 100644
--- a/src/qml/jsruntime/qv4serialize.cpp
+++ b/src/qml/jsruntime/qv4serialize.cpp
@@ -283,8 +283,8 @@ void Serialize::serialize(QByteArray &data, const QV4::ValueRef v, QV8Engine *en
try {
str = s->asString();
val = o->get(str);
- } catch (QV4::Exception &e) {
- e.accept(ctx);
+ } catch (...) {
+ ctx->catchException();
}
serialize(data, val, engine);
diff --git a/src/qml/jsruntime/qv4value.cpp b/src/qml/jsruntime/qv4value.cpp
index 623f9ae3b6..3c9db5edea 100644
--- a/src/qml/jsruntime/qv4value.cpp
+++ b/src/qml/jsruntime/qv4value.cpp
@@ -124,19 +124,24 @@ QString Value::toQStringNoThrow() const
{
ExecutionContext *ctx = objectValue()->internalClass->engine->current;
Scope scope(ctx);
+ ScopedValue ex(scope);
+ bool caughtException = false;
try {
ScopedValue prim(scope, __qmljs_to_primitive(ValueRef::fromRawValue(this), STRING_HINT));
if (prim->isPrimitive())
return prim->toQStringNoThrow();
- } catch (Exception &e) {
- e.accept(ctx);
+ } catch (...) {
+ ex = ctx->catchException();
+ caughtException = true;
+ }
+ // Can't nest try/catch due to CXX ABI limitations for foreign exception nesting.
+ if (caughtException) {
try {
- ScopedValue ex(scope, e.value());
ScopedValue prim(scope, __qmljs_to_primitive(ex, STRING_HINT));
if (prim->isPrimitive())
return prim->toQStringNoThrow();
- } catch(Exception &e) {
- e.accept(ctx);
+ } catch(...) {
+ ctx->catchException();
}
}
return QString();
diff --git a/src/qml/jsruntime/qv4vme_moth.cpp b/src/qml/jsruntime/qv4vme_moth.cpp
index a3fc43b39c..e933376a13 100644
--- a/src/qml/jsruntime/qv4vme_moth.cpp
+++ b/src/qml/jsruntime/qv4vme_moth.cpp
@@ -368,14 +368,17 @@ QV4::ReturnedValue VME::run(QV4::ExecutionContext *context, const uchar *&code,
MOTH_BEGIN_INSTR(EnterTry)
VALUE(instr.exceptionVar) = QV4::Primitive::undefinedValue();
+ bool caughtException = false;
try {
const uchar *tryCode = ((uchar *)&instr.tryOffset) + instr.tryOffset;
run(context, tryCode, stack, stackSize);
code = tryCode;
context->interpreterInstructionPointer = &code;
- } catch (QV4::Exception &ex) {
- ex.accept(context);
- STOREVALUE(instr.exceptionVar, ex.value());
+ } catch (...) {
+ STOREVALUE(instr.exceptionVar, context->catchException());
+ caughtException = true;
+ }
+ if (caughtException) {
try {
QV4::ExecutionContext *catchContext = __qmljs_builtin_push_catch_scope(runtimeStrings[instr.exceptionVarName], VALUEPTR(instr.exceptionVar), context);
const uchar *catchCode = ((uchar *)&instr.catchOffset) + instr.catchOffset;
@@ -383,9 +386,8 @@ QV4::ReturnedValue VME::run(QV4::ExecutionContext *context, const uchar *&code,
code = catchCode;
context->interpreterInstructionPointer = &code;
context = __qmljs_builtin_pop_scope(catchContext);
- } catch (QV4::Exception &ex) {
- ex.accept(context);
- STOREVALUE(instr.exceptionVar, ex.value());
+ } catch (...) {
+ STOREVALUE(instr.exceptionVar, context->catchException());
const uchar *catchCode = ((uchar *)&instr.catchOffset) + instr.catchOffset;
run(context, catchCode, stack, stackSize);
code = catchCode;