diff options
40 files changed, 258 insertions, 292 deletions
diff --git a/src/imports/localstorage/plugin.cpp b/src/imports/localstorage/plugin.cpp index c4e3d51d49..4cfc6a04b3 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 3d0954768a..f73674fd38 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<QV4::ExecutionEngine::StackFrame> stack = v4->stackTrace(frameIndex + 2); + QVector<QV4::StackFrame> 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<QV4::ExecutionEngine::StackFrame> stack = v4->stackTrace(frameIndex + 2); + QVector<QV4::StackFrame> 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 6afbee2400..850dc64b99 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 57647a49d3..d42cabd81c 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 8bcdccc507..ba94afadc6 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 e1786f06cd..fd5f709e14 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 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; diff --git a/src/qml/qml/qqmlcomponent.cpp b/src/qml/qml/qqmlcomponent.cpp index 2d3e9006b2..c4bc242bd9 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 0c8e46bd8d..3a4179717a 100644 --- a/src/qml/qml/qqmlerror.cpp +++ b/src/qml/qml/qqmlerror.cpp @@ -46,6 +46,8 @@ #include <QtCore/qfile.h> #include <QtCore/qstringlist.h> +#include <private/qv4errorobject_p.h> + 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<QV4::ErrorObject> 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 e69b3c15ba..50491b911c 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 938b14a15f..8751d9c500 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<QV4::ErrorObject> 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 031cc2d2c1..efea961bd2 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 3209d5a454..76cb0ce38f 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 656e9dfe3a..6477f63daf 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 ecc6287823..7c033acf47 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 2b9bd6196f..6aeabf9221 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 a53a1ef1ec..595c75da45 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<QV4::ExecutionEngine::StackFrame> stackTrace = engine->stackTrace(10); + QVector<QV4::StackFrame> 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 f789f999a4..9b8616d5e7 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 82ceea9c46..ea8a1fe6c7 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 38329b8289..3d79e8990f 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; } |