From c860d1399b4ff5f3a5b1b2630bc33112c88c13e8 Mon Sep 17 00:00:00 2001 From: Simon Hausmann Date: Wed, 11 Sep 2013 13:23:21 +0200 Subject: [PATCH] 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 --- src/imports/localstorage/plugin.cpp | 8 +-- src/imports/testlib/main.cpp | 4 +- src/qml/compiler/qv4isel_masm.cpp | 20 +++---- src/qml/jsapi/qjsengine.cpp | 5 +- src/qml/jsapi/qjsvalue.cpp | 49 ++++++++--------- src/qml/jsapi/qjsvalueiterator.cpp | 4 +- src/qml/jsruntime/qv4context.cpp | 27 +++++++++- src/qml/jsruntime/qv4context_p.h | 4 ++ src/qml/jsruntime/qv4engine.cpp | 8 +-- src/qml/jsruntime/qv4engine_p.h | 10 ++-- src/qml/jsruntime/qv4errorobject.cpp | 4 +- src/qml/jsruntime/qv4errorobject_p.h | 2 +- src/qml/jsruntime/qv4exception.cpp | 55 ++++++------------- src/qml/jsruntime/qv4exception_gcc.cpp | 13 +++-- src/qml/jsruntime/qv4exception_p.h | 27 ++-------- src/qml/jsruntime/qv4function_p.h | 2 +- src/qml/jsruntime/qv4functionobject.cpp | 30 +++++------ src/qml/jsruntime/qv4global_p.h | 10 +++- src/qml/jsruntime/qv4globalobject.cpp | 6 +-- src/qml/jsruntime/qv4include.cpp | 14 +++-- src/qml/jsruntime/qv4qobjectwrapper.cpp | 8 ++- src/qml/jsruntime/qv4runtime.cpp | 3 +- src/qml/jsruntime/qv4script.cpp | 8 +-- src/qml/jsruntime/qv4sequenceobject.cpp | 2 +- src/qml/jsruntime/qv4serialize.cpp | 4 +- src/qml/jsruntime/qv4value.cpp | 15 ++++-- src/qml/jsruntime/qv4vme_moth.cpp | 14 ++--- src/qml/qml/qqmlcomponent.cpp | 6 +-- src/qml/qml/qqmlerror.cpp | 24 +++++++++ src/qml/qml/qqmlerror.h | 7 +++ src/qml/qml/qqmljavascriptexpression.cpp | 62 ++++------------------ src/qml/qml/qqmljavascriptexpression_p.h | 8 ++- src/qml/qml/qqmltypeloader.cpp | 6 +-- src/qml/qml/qqmlvaluetypewrapper.cpp | 2 +- src/qml/qml/qqmlvmemetaobject.cpp | 6 +-- src/qml/qml/qqmlxmlhttprequest.cpp | 15 ++---- src/qml/qml/v8/qqmlbuiltinfunctions.cpp | 16 +++--- src/qml/types/qquickworkerscript.cpp | 17 +++--- .../auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp | 12 ++--- tools/v4/main.cpp | 13 ++--- 40 files changed, 258 insertions(+), 292 deletions(-) diff --git a/src/imports/localstorage/plugin.cpp b/src/imports/localstorage/plugin.cpp index c4e3d51..4cfc6a0 100644 --- a/src/imports/localstorage/plugin.cpp +++ b/src/imports/localstorage/plugin.cpp @@ -362,9 +362,9 @@ static ReturnedValue qmlsqldatabase_changeVersion(SimpleCallContext *ctx) callData->args[0] = w; try { callback->call(callData); - } catch (Exception &) { + } catch (...) { db.rollback(); - throw; + ctx->rethrowException(); } if (!db.commit()) { db.rollback(); @@ -418,10 +418,10 @@ static ReturnedValue qmlsqldatabase_transaction_shared(SimpleCallContext *ctx, b callData->args[0] = w; try { callback->call(callData); - } catch (Exception &) { + } catch (...) { w->inTransaction = false; db.rollback(); - throw; + ctx->rethrowException(); } w->inTransaction = false; diff --git a/src/imports/testlib/main.cpp b/src/imports/testlib/main.cpp index 3d09547..f73674f 100644 --- a/src/imports/testlib/main.cpp +++ b/src/imports/testlib/main.cpp @@ -114,7 +114,7 @@ public Q_SLOTS: QV4::ExecutionEngine *v4 = QV8Engine::getV4(engine->handle()); QV4::Scope scope(v4); - QVector stack = v4->stackTrace(frameIndex + 2); + QVector stack = v4->stackTrace(frameIndex + 2); if (stack.size() > frameIndex + 1) { QV4::ScopedValue s(scope, v4->newString(stack.at(frameIndex + 1).source)); return QQmlV4Handle(s); @@ -126,7 +126,7 @@ public Q_SLOTS: QQmlEngine *engine = qmlEngine(this); QV4::ExecutionEngine *v4 = QV8Engine::getV4(engine->handle()); - QVector stack = v4->stackTrace(frameIndex + 2); + QVector stack = v4->stackTrace(frameIndex + 2); if (stack.size() > frameIndex + 1) return stack.at(frameIndex + 1).line; return -1; diff --git a/src/qml/compiler/qv4isel_masm.cpp b/src/qml/compiler/qv4isel_masm.cpp index 6afbee2..850dc64 100644 --- a/src/qml/compiler/qv4isel_masm.cpp +++ b/src/qml/compiler/qv4isel_masm.cpp @@ -796,22 +796,24 @@ static void *tryWrapper(ExecutionContext *context, void *localsPtr, MiddleOfFunc exceptionVar = Primitive::undefinedValue(); void *addressToContinueAt = 0; SafeValue *jsStackTop = context->engine->jsStackTop; + bool caughtException = false; try { addressToContinueAt = tryBody(context, localsPtr); - } catch (Exception& ex) { + } catch (...) { context->engine->jsStackTop = jsStackTop; - ex.accept(context); - exceptionVar = ex.value(); + exceptionVar = context->catchException(); + caughtException = true; + } + // Can't nest try { ... } catch (...) {} due to inability of nesting foreign exceptions + // with common CXX ABI. + if (caughtException) { try { - QV4::Scope scope(context); - QV4::ScopedValue exception(scope, ex.value()); - ExecutionContext *catchContext = __qmljs_builtin_push_catch_scope(exceptionVarName, exception, context); + ExecutionContext *catchContext = __qmljs_builtin_push_catch_scope(exceptionVarName, exceptionVar, context); addressToContinueAt = catchBody(catchContext, localsPtr); context = __qmljs_builtin_pop_scope(catchContext); - } catch (Exception& ex) { + } catch (...) { context->engine->jsStackTop = jsStackTop; - exceptionVar = ex.value(); - ex.accept(context); + exceptionVar = context->catchException(); addressToContinueAt = catchBody(context, localsPtr); } } diff --git a/src/qml/jsapi/qjsengine.cpp b/src/qml/jsapi/qjsengine.cpp index 57647a4..d42cabd 100644 --- a/src/qml/jsapi/qjsengine.cpp +++ b/src/qml/jsapi/qjsengine.cpp @@ -269,9 +269,8 @@ QJSValue QJSEngine::evaluate(const QString& program, const QString& fileName, in script.inheritContext = true; script.parse(); result = script.run(); - } catch (QV4::Exception& ex) { - ex.accept(ctx); - result = ex.value(); + } catch (...) { + result = ctx->catchException(); } return new QJSValuePrivate(d->m_v4Engine, result); } diff --git a/src/qml/jsapi/qjsvalue.cpp b/src/qml/jsapi/qjsvalue.cpp index 8bcdccc..ba94afa 100644 --- a/src/qml/jsapi/qjsvalue.cpp +++ b/src/qml/jsapi/qjsvalue.cpp @@ -380,8 +380,8 @@ double QJSValue::toNumber() const QV4::ExecutionContext *ctx = d->engine ? d->engine->current : 0; try { return d->value.toNumber(); - } catch (Exception &e) { - e.accept(ctx); + } catch (...) { + ctx->catchException(); return 0; } } @@ -403,8 +403,8 @@ bool QJSValue::toBool() const QV4::ExecutionContext *ctx = d->engine ? d->engine->current : 0; try { return d->value.toBoolean(); - } catch (Exception &e) { - e.accept(ctx); + } catch (...) { + ctx->catchException(); return false; } } @@ -426,8 +426,8 @@ qint32 QJSValue::toInt() const QV4::ExecutionContext *ctx = d->engine ? d->engine->current : 0; try { return d->value.toInt32(); - } catch (Exception &e) { - e.accept(ctx); + } catch (...) { + ctx->catchException(); return 0; } } @@ -449,8 +449,8 @@ quint32 QJSValue::toUInt() const QV4::ExecutionContext *ctx = d->engine ? d->engine->current : 0; try { return d->value.toUInt32(); - } catch (Exception &e) { - e.accept(ctx); + } catch (...) { + ctx->catchException(); return 0; } } @@ -521,9 +521,8 @@ QJSValue QJSValue::call(const QJSValueList &args) QV4::ExecutionContext *ctx = engine->current; try { result = f->call(callData); - } catch (Exception &e) { - e.accept(ctx); - result = e.value(); + } catch (...) { + result = ctx->catchException(); } return new QJSValuePrivate(engine, result); @@ -578,9 +577,8 @@ QJSValue QJSValue::callWithInstance(const QJSValue &instance, const QJSValueList QV4::ExecutionContext *ctx = engine->current; try { result = f->call(callData); - } catch (Exception &e) { - e.accept(ctx); - result = e.value(); + } catch (...) { + result = ctx->catchException(); } return new QJSValuePrivate(engine, result); @@ -627,9 +625,8 @@ QJSValue QJSValue::callAsConstructor(const QJSValueList &args) QV4::ExecutionContext *ctx = engine->current; try { result = f->construct(callData); - } catch (Exception &e) { - e.accept(ctx); - result = e.value(); + } catch (...) { + result = ctx->catchException(); } return new QJSValuePrivate(engine, result); @@ -819,9 +816,8 @@ QJSValue QJSValue::property(const QString& name) const QV4::ScopedValue result(scope); try { result = o->get(s); - } catch (QV4::Exception &e) { - e.accept(ctx); - result = e.value(); + } catch (...) { + result = ctx->catchException(); } return new QJSValuePrivate(engine, result); } @@ -853,9 +849,8 @@ QJSValue QJSValue::property(quint32 arrayIndex) const QV4::ScopedValue result(scope); try { result = arrayIndex == UINT_MAX ? o->get(engine->id_uintMax) : o->getIndexed(arrayIndex); - } catch (QV4::Exception &e) { - e.accept(ctx); - result = e.value(); + } catch (...) { + result = ctx->catchException(); } return new QJSValuePrivate(engine, result); } @@ -899,8 +894,8 @@ void QJSValue::setProperty(const QString& name, const QJSValue& value) try { QV4::ScopedValue v(scope, value.d->getValue(engine)); o->put(s, v); - } catch (QV4::Exception &e) { - e.accept(ctx); + } catch (...) { + ctx->catchException(); } } @@ -934,8 +929,8 @@ void QJSValue::setProperty(quint32 arrayIndex, const QJSValue& value) o->putIndexed(arrayIndex, v); else o->put(engine->id_uintMax, v); - } catch (QV4::Exception &e) { - e.accept(ctx); + } catch (...) { + ctx->catchException(); } } diff --git a/src/qml/jsapi/qjsvalueiterator.cpp b/src/qml/jsapi/qjsvalueiterator.cpp index e1786f0..fd5f709 100644 --- a/src/qml/jsapi/qjsvalueiterator.cpp +++ b/src/qml/jsapi/qjsvalueiterator.cpp @@ -211,8 +211,8 @@ QJSValue QJSValueIterator::value() const return QJSValue(); } return new QJSValuePrivate(engine, v); - } catch (QV4::Exception &e) { - e.accept(ctx); + } catch (...) { + ctx->catchException(); return QJSValue(); } } diff --git a/src/qml/jsruntime/qv4context.cpp b/src/qml/jsruntime/qv4context.cpp index 0e08f02..78bf662 100644 --- a/src/qml/jsruntime/qv4context.cpp +++ b/src/qml/jsruntime/qv4context.cpp @@ -48,6 +48,7 @@ #include #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 d368dc6..2535161 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 8032197..ba7241b 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::stackTrace(int frameLimit) const +QVector ExecutionEngine::stackTrace(int frameLimit) const { LineNumberResolver lineNumbers(this); @@ -628,7 +630,7 @@ QVector 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 79a4d3b..9a83ddc 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 *qmlContextObject() const; - struct StackFrame { - QString source; - QString function; - int line; - int column; - }; - typedef QVector 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 b247c15..58375ea 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 d48edfa..ff43f54 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 64e6bef..f55dc94 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 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 5eb5fc2..0d230ea 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(ex)->~Exception(); + reinterpret_cast(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(rawException) - 1; cxa_exception *exception = &refCountedException->x; - (void)new (rawException) Exception(throwingContext, exceptionValue); + (void)new (rawException) DummyException(); refCountedException->refCount = 1; - exception->typeInfo = const_cast(&typeid(Exception)); + exception->typeInfo = const_cast(&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 a373ef2..1f02d11 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 #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 ca984e0..34ab5df 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 7ef0b96..305efba 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 01c5245..3569247 100644 --- a/src/qml/jsruntime/qv4global_p.h +++ b/src/qml/jsruntime/qv4global_p.h @@ -43,7 +43,7 @@ #define QV4GLOBAL_H #include - +#include #include #if defined(Q_CC_MSVC) @@ -232,6 +232,14 @@ struct PropertyAttributes } }; +struct StackFrame { + QString source; + QString function; + int line; + int column; +}; +typedef QVector StackTrace; + } Q_DECLARE_TYPEINFO(QV4::PropertyAttributes, Q_PRIMITIVE_TYPE); diff --git a/src/qml/jsruntime/qv4globalobject.cpp b/src/qml/jsruntime/qv4globalobject.cpp index cbf6ddc..a465fdc 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 37db745..44ba059 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 8be1343..6e474ec 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 6002346..b8b62c1 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 0dddbe8..e320656 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 5c8f7db..8d3dd97 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 7d3214e..d38897c 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 623f9ae..3c9db5e 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 a3fc43b..e933376 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; diff --git a/src/qml/qml/qqmlcomponent.cpp b/src/qml/qml/qqmlcomponent.cpp index 2d3e900..c4bc242 100644 --- a/src/qml/qml/qqmlcomponent.cpp +++ b/src/qml/qml/qqmlcomponent.cpp @@ -1542,10 +1542,8 @@ void QmlIncubatorObject::statusChanged(Status s) callData->thisObject = this; callData->args[0] = QV4::Primitive::fromUInt32(s); f->call(callData); - } catch (QV4::Exception &e) { - e.accept(ctx); - QQmlError error; - QQmlJavaScriptExpression::exceptionToError(e, error); + } catch (...) { + QQmlError error = QQmlError::catchJavaScriptException(ctx); QQmlEnginePrivate::warning(QQmlEnginePrivate::get(v8->engine()), error); } } diff --git a/src/qml/qml/qqmlerror.cpp b/src/qml/qml/qqmlerror.cpp index 0c8e46b..3a41797 100644 --- a/src/qml/qml/qqmlerror.cpp +++ b/src/qml/qml/qqmlerror.cpp @@ -46,6 +46,8 @@ #include #include +#include + QT_BEGIN_NAMESPACE /*! @@ -136,6 +138,28 @@ QQmlError::~QQmlError() delete d; d = 0; } +QQmlError QQmlError::catchJavaScriptException(QV4::ExecutionContext *context) +{ + QV4::StackTrace trace; + QV4::Scope scope(context); + QV4::ScopedValue exception(scope, context->catchException(&trace)); + QQmlError error; + if (!trace.isEmpty()) { + QV4::StackFrame frame = trace.first(); + error.setUrl(QUrl(frame.source)); + error.setLine(frame.line); + error.setColumn(frame.column); + } + QV4::Scoped errorObj(scope, exception); + if (!!errorObj && errorObj->asSyntaxError()) { + QV4::ScopedString m(scope, errorObj->engine()->newString("message")); + QV4::ScopedValue v(scope, errorObj->get(m)); + error.setDescription(v->toQStringNoThrow()); + } else + error.setDescription(exception->toQStringNoThrow()); + return error; +} + /*! Returns true if this error is valid, otherwise false. */ diff --git a/src/qml/qml/qqmlerror.h b/src/qml/qml/qqmlerror.h index e69b3c1..50491b9 100644 --- a/src/qml/qml/qqmlerror.h +++ b/src/qml/qml/qqmlerror.h @@ -49,6 +49,10 @@ QT_BEGIN_NAMESPACE +namespace QV4 { +struct ExecutionContext; +} + class QDebug; class QQmlErrorPrivate; class Q_QML_EXPORT QQmlError @@ -59,6 +63,9 @@ public: QQmlError &operator=(const QQmlError &); ~QQmlError(); + // Use only inside catch(...) -- will re-throw if no JS exception + static QQmlError catchJavaScriptException(QV4::ExecutionContext *context); + bool isValid() const; QUrl url() const; diff --git a/src/qml/qml/qqmljavascriptexpression.cpp b/src/qml/qml/qqmljavascriptexpression.cpp index 938b14a..8751d9c 100644 --- a/src/qml/qml/qqmljavascriptexpression.cpp +++ b/src/qml/qml/qqmljavascriptexpression.cpp @@ -84,18 +84,9 @@ void QQmlDelayedError::setErrorObject(QObject *object) m_error.setObject(object); } -void QQmlDelayedError::setError(const QV4::Exception &e) +void QQmlDelayedError::catchJavaScriptException(QV4::ExecutionContext *context) { - m_error.setDescription(QV4::Value::fromReturnedValue(e.value()).toQStringNoThrow()); - QV4::ExecutionEngine::StackTrace trace = e.stackTrace(); - if (!trace.isEmpty()) { - QV4::ExecutionEngine::StackFrame frame = trace.first(); - m_error.setUrl(QUrl(frame.source)); - m_error.setLine(frame.line); - m_error.setColumn(frame.column); - } - - m_error.setColumn(-1); + m_error = QQmlError::catchJavaScriptException(context); } @@ -183,19 +174,13 @@ QV4::ReturnedValue QQmlJavaScriptExpression::evaluate(QQmlContextData *context, if (!watcher.wasDeleted() && hasDelayedError()) delayedError()->clearError(); - } catch (QV4::Exception &e) { - e.accept(ctx); - QV4::ScopedValue ex(scope, e.value()); + } catch (...) { + if (watcher.wasDeleted()) + ctx->catchException(); // ignore exception + else + delayedError()->catchJavaScriptException(ctx); if (isUndefined) *isUndefined = true; - if (!watcher.wasDeleted()) { - if (!ex->isUndefined()) { - delayedError()->setError(e); - } else { - if (hasDelayedError()) - delayedError()->clearError(); - } - } } if (capture.errorString) { @@ -302,27 +287,6 @@ QQmlDelayedError *QQmlJavaScriptExpression::delayedError() return &m_vtable.value(); } -void QQmlJavaScriptExpression::exceptionToError(const QV4::Exception &e, QQmlError &error) -{ - QV4::Scope scope(e.engine()); - QV4::ExecutionEngine::StackTrace trace = e.stackTrace(); - if (!trace.isEmpty()) { - QV4::ExecutionEngine::StackFrame frame = trace.first(); - error.setUrl(QUrl(frame.source)); - error.setLine(frame.line); - error.setColumn(frame.column); - } - QV4::Scoped errorObj(scope, e.value()); - if (!!errorObj && errorObj->asSyntaxError()) { - QV4::ScopedString m(scope, errorObj->engine()->newString("message")); - QV4::ScopedValue v(scope, errorObj->get(m)); - error.setDescription(v->toQStringNoThrow()); - } else { - QV4::ScopedValue v(scope, e.value()); - error.setDescription(v->toQStringNoThrow()); - } -} - QV4::ReturnedValue QQmlJavaScriptExpression::evalFunction(QQmlContextData *ctxt, QObject *scopeObject, const QString &code, const QString &filename, quint16 line, @@ -341,10 +305,8 @@ QQmlJavaScriptExpression::evalFunction(QQmlContextData *ctxt, QObject *scopeObje try { script.parse(); result = script.run(); - } 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(QLatin1String("Exception occurred during function evaluation")); if (error.line() == -1) @@ -377,10 +339,8 @@ QV4::ReturnedValue QQmlJavaScriptExpression::qmlBinding(QQmlContextData *ctxt, Q try { script.parse(); result = script.qmlBinding(); - } 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(QLatin1String("Exception occurred during function evaluation")); if (error.line() == -1) diff --git a/src/qml/qml/qqmljavascriptexpression_p.h b/src/qml/qml/qqmljavascriptexpression_p.h index 031cc2d..efea961 100644 --- a/src/qml/qml/qqmljavascriptexpression_p.h +++ b/src/qml/qml/qqmljavascriptexpression_p.h @@ -61,6 +61,10 @@ QT_BEGIN_NAMESPACE +namespace QV4 { +struct ExecutionContext; +} + class QQmlDelayedError { public: @@ -85,7 +89,8 @@ public: void setErrorDescription(const QString &description); void setErrorObject(QObject *object); - void setError(const QV4::Exception &e); + // Call only from catch(...) -- will re-throw if no JS exception + void catchJavaScriptException(QV4::ExecutionContext *context); private: @@ -142,7 +147,6 @@ public: void clearGuards(); QQmlDelayedError *delayedError(); - static void exceptionToError(const QV4::Exception &e, QQmlError &); static QV4::ReturnedValue evalFunction(QQmlContextData *ctxt, QObject *scope, const QString &code, const QString &filename, quint16 line, diff --git a/src/qml/qml/qqmltypeloader.cpp b/src/qml/qml/qqmltypeloader.cpp index 3209d5a..76cb0ce 100644 --- a/src/qml/qml/qqmltypeloader.cpp +++ b/src/qml/qml/qqmltypeloader.cpp @@ -2766,10 +2766,8 @@ QV4::PersistentValue QQmlScriptData::scriptValueForContext(QQmlContextData *pare try { m_program->qml = qmlglobal; m_program->run(); - } catch (QV4::Exception &e) { - e.accept(ctx); - QQmlError error; - QQmlExpressionPrivate::exceptionToError(e, error); + } catch (...) { + QQmlError error = QQmlError::catchJavaScriptException(ctx); if (error.isValid()) ep->warning(error); } diff --git a/src/qml/qml/qqmlvaluetypewrapper.cpp b/src/qml/qml/qqmlvaluetypewrapper.cpp index 656e9df..6477f63 100644 --- a/src/qml/qml/qqmlvaluetypewrapper.cpp +++ b/src/qml/qml/qqmlvaluetypewrapper.cpp @@ -372,7 +372,7 @@ void QmlValueTypeWrapper::put(Managed *m, const StringRef name, const ValueRef v cacheData.valueTypeCoreIndex = index; cacheData.valueTypePropType = p.userType(); - QV4::ExecutionEngine::StackFrame frame = v4->currentStackFrame(); + QV4::StackFrame frame = v4->currentStackFrame(); newBinding = new QQmlBinding(value, reference->object, context, frame.source, qmlSourceCoordinate(frame.line), qmlSourceCoordinate(frame.column)); diff --git a/src/qml/qml/qqmlvmemetaobject.cpp b/src/qml/qml/qqmlvmemetaobject.cpp index ecc6287..7c033ac 100644 --- a/src/qml/qml/qqmlvmemetaobject.cpp +++ b/src/qml/qml/qqmlvmemetaobject.cpp @@ -944,10 +944,8 @@ int QQmlVMEMetaObject::metaCall(QMetaObject::Call c, int _id, void **a) try { result = function->call(callData); if (a[0]) *(QVariant *)a[0] = ep->v8engine()->toVariant(result, 0); - } catch (QV4::Exception &e) { - e.accept(ctx); - QQmlError error; - QQmlExpressionPrivate::exceptionToError(e, error); + } catch (...) { + QQmlError error = QQmlError::catchJavaScriptException(ctx); if (error.isValid()) ep->warning(error); if (a[0]) *(QVariant *)a[0] = QVariant(); diff --git a/src/qml/qml/qqmlxmlhttprequest.cpp b/src/qml/qml/qqmlxmlhttprequest.cpp index 2b9bd61..6aeabf9 100644 --- a/src/qml/qml/qqmlxmlhttprequest.cpp +++ b/src/qml/qml/qqmlxmlhttprequest.cpp @@ -1105,7 +1105,6 @@ private: PersistentValue m_me; void dispatchCallback(const ValueRef me); - void printError(const Exception &e); int m_status; QString m_statusText; @@ -1568,20 +1567,12 @@ void QQmlXMLHttpRequest::dispatchCallback(const ValueRef me) // deleted explicitly (e.g., by a Loader deleting the itemContext when // the source is changed). We do nothing in this case, as the evaluation // cannot succeed. - } catch(Exception &e) { - e.accept(ctx); - printError(e); + } catch (...) { + QQmlError error = QQmlError::catchJavaScriptException(ctx); + QQmlEnginePrivate::warning(QQmlEnginePrivate::get(v4->v8Engine->engine()), error); } } -// Must have a handle scope -void QQmlXMLHttpRequest::printError(const Exception &e) -{ - QQmlError error; - QQmlExpressionPrivate::exceptionToError(e, error); - QQmlEnginePrivate::warning(QQmlEnginePrivate::get(v4->v8Engine->engine()), error); -} - void QQmlXMLHttpRequest::destroyNetwork() { if (m_network) { diff --git a/src/qml/qml/v8/qqmlbuiltinfunctions.cpp b/src/qml/qml/v8/qqmlbuiltinfunctions.cpp index a53a1ef..595c75d 100644 --- a/src/qml/qml/v8/qqmlbuiltinfunctions.cpp +++ b/src/qml/qml/v8/qqmlbuiltinfunctions.cpp @@ -1333,10 +1333,10 @@ enum ConsoleLogTypes { static QString jsStack(QV4::ExecutionEngine *engine) { QString stack; - QVector stackTrace = engine->stackTrace(10); + QVector stackTrace = engine->stackTrace(10); for (int i = 0; i < stackTrace.count(); i++) { - const QV4::ExecutionEngine::StackFrame &frame = stackTrace.at(i); + const QV4::StackFrame &frame = stackTrace.at(i); QString stackFrame; if (frame.column >= 0) @@ -1377,7 +1377,7 @@ static QV4::ReturnedValue writeToConsole(ConsoleLogTypes logType, SimpleCallCont result.append(jsStack(v4)); } - QV4::ExecutionEngine::StackFrame frame = v4->currentStackFrame(); + QV4::StackFrame frame = v4->currentStackFrame(); QMessageLogger logger(frame.source.toUtf8().constData(), frame.line, frame.function.toUtf8().constData()); switch (logType) { case Log: @@ -1418,7 +1418,7 @@ QV4::ReturnedValue ConsoleObject::method_profile(SimpleCallContext *ctx) QString title; QV4::ExecutionEngine *v4 = ctx->engine; - QV4::ExecutionEngine::StackFrame frame = v4->currentStackFrame(); + QV4::StackFrame frame = v4->currentStackFrame(); QMessageLogger logger(frame.source.toUtf8().constData(), frame.line, frame.function.toUtf8().constData()); if (QQmlProfilerService::startProfiling()) { QV8ProfilerService::instance()->startProfiling(title); @@ -1440,7 +1440,7 @@ QV4::ReturnedValue ConsoleObject::method_profileEnd(SimpleCallContext *ctx) QV4::ExecutionEngine *v4 = ctx->engine; - QV4::ExecutionEngine::StackFrame frame = v4->currentStackFrame(); + QV4::StackFrame frame = v4->currentStackFrame(); QMessageLogger logger(frame.source.toUtf8().constData(), frame.line, frame.function.toUtf8().constData()); if (QQmlProfilerService::stopProfiling()) { @@ -1495,7 +1495,7 @@ QV4::ReturnedValue ConsoleObject::method_count(SimpleCallContext *ctx) QV4::ExecutionEngine *v4 = ctx->engine; QV8Engine *v8engine = ctx->engine->v8Engine; - QV4::ExecutionEngine::StackFrame frame = v4->currentStackFrame(); + QV4::StackFrame frame = v4->currentStackFrame(); QString scriptName = frame.source; @@ -1517,7 +1517,7 @@ QV4::ReturnedValue ConsoleObject::method_trace(SimpleCallContext *ctx) QString stack = jsStack(v4); - QV4::ExecutionEngine::StackFrame frame = v4->currentStackFrame(); + QV4::StackFrame frame = v4->currentStackFrame(); QMessageLogger logger(frame.source.toUtf8().constData(), frame.line, frame.function.toUtf8().constData()); logger.debug("%s", qPrintable(stack)); @@ -1547,7 +1547,7 @@ QV4::ReturnedValue ConsoleObject::method_assert(SimpleCallContext *ctx) QString stack = jsStack(v4); - QV4::ExecutionEngine::StackFrame frame = v4->currentStackFrame(); + QV4::StackFrame frame = v4->currentStackFrame(); QMessageLogger logger(frame.source.toUtf8().constData(), frame.line, frame.function.toUtf8().constData()); logger.critical("%s\n%s", qPrintable(message), qPrintable(stack)); diff --git a/src/qml/types/qquickworkerscript.cpp b/src/qml/types/qquickworkerscript.cpp index f789f99..9b8616d 100644 --- a/src/qml/types/qquickworkerscript.cpp +++ b/src/qml/types/qquickworkerscript.cpp @@ -258,9 +258,8 @@ QV4::ReturnedValue QQuickWorkerScriptEnginePrivate::WorkerEngine::sendFunction(i callData->args[0] = QV4::Primitive::fromInt32(id); callData->thisObject = global(); v = f->call(callData); - } catch (QV4::Exception &e) { - e.accept(ctx); - v = e.value(); + } catch (...) { + v = ctx->catchException(); } return v.asReturnedValue(); } @@ -367,10 +366,8 @@ void QQuickWorkerScriptEnginePrivate::processMessage(int id, const QByteArray &d callData->args[0] = script->object.value(); callData->args[1] = value; f->call(callData); - } catch (QV4::Exception &e) { - e.accept(ctx); - QQmlError error; - QQmlExpressionPrivate::exceptionToError(e, error); + } catch (...) { + QQmlError error = QQmlError::catchJavaScriptException(ctx); reportScriptException(script, error); } } @@ -406,10 +403,8 @@ void QQuickWorkerScriptEnginePrivate::processLoad(int id, const QUrl &url) try { program.parse(); program.run(); - } catch (QV4::Exception &e) { - e.accept(ctx); - QQmlError error; - QQmlExpressionPrivate::exceptionToError(e, error); + } catch (...) { + QQmlError error = QQmlError::catchJavaScriptException(ctx); reportScriptException(script, error); } } else { diff --git a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp index 82ceea9..ea8a1fe 100644 --- a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp +++ b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp @@ -2280,8 +2280,8 @@ static inline bool evaluate_error(QV8Engine *engine, const QV4::ValueRef o, cons d->args[0] = o; d->thisObject = engine->global(); function->call(d); - } catch (QV4::Exception &e) { - e.accept(ctx); + } catch (...) { + ctx->catchException(); return true; } return false; @@ -2310,8 +2310,8 @@ static inline bool evaluate_value(QV8Engine *engine, const QV4::ValueRef o, d->thisObject = engine->global(); value = function->call(d); return __qmljs_strict_equal(value, result); - } catch (QV4::Exception &e) { - e.accept(ctx); + } catch (...) { + ctx->catchException(); } return false; } @@ -2335,8 +2335,8 @@ static inline QV4::ReturnedValue evaluate(QV8Engine *engine, const QV4::ValueRef d->args[0] = o; d->thisObject = engine->global(); return function->call(d); - } catch (QV4::Exception &e) { - e.accept(ctx); + } catch (...) { + ctx->catchException(); } return QV4::Encode::undefined(); } diff --git a/tools/v4/main.cpp b/tools/v4/main.cpp index 38329b8..3d79e89 100644 --- a/tools/v4/main.cpp +++ b/tools/v4/main.cpp @@ -113,10 +113,10 @@ DEFINE_MANAGED_VTABLE(GC); } // builtins -static void showException(QV4::ExecutionContext *ctx, const QV4::Exception &exception) +static void showException(QV4::ExecutionContext *ctx, const QV4::ValueRef exception, const QV4::StackTrace &trace) { QV4::Scope scope(ctx); - QV4::ScopedValue ex(scope, exception.value()); + QV4::ScopedValue ex(scope, *exception); QV4::ErrorObject *e = ex->asErrorObject(); if (!e) { std::cerr << "Uncaught exception: " << qPrintable(ex->toString(ctx)->toQString()) << std::endl; @@ -126,7 +126,7 @@ static void showException(QV4::ExecutionContext *ctx, const QV4::Exception &exce std::cerr << "Uncaught exception: " << qPrintable(message->toQStringNoThrow()) << std::endl; } - foreach (const QV4::ExecutionEngine::StackFrame &frame, exception.stackTrace()) { + foreach (const QV4::StackFrame &frame, trace) { std::cerr << " at " << qPrintable(frame.function) << " (" << qPrintable(frame.source); if (frame.line >= 0) std::cerr << ":" << frame.line; @@ -212,9 +212,10 @@ int main(int argc, char *argv[]) if (! qgetenv("SHOW_EXIT_VALUE").isEmpty()) std::cout << "exit value: " << qPrintable(result->toString(ctx)->toQString()) << std::endl; } - } catch (QV4::Exception& ex) { - ex.accept(ctx); - showException(ctx, ex); + } catch (...) { + QV4::StackTrace trace; + QV4::ScopedValue ex(scope, ctx->catchException(&trace)); + showException(ctx, ex, trace); return EXIT_FAILURE; } -- 2.7.4