aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSimon Hausmann <simon.hausmann@digia.com>2013-09-11 13:23:21 +0200
committerThe Qt Project <gerrit-noreply@qt-project.org>2013-10-02 16:07:33 +0200
commitc860d1399b4ff5f3a5b1b2630bc33112c88c13e8 (patch)
tree3e6cdd7b209cc343dd791827d07bb69a700e7043
parentc1d66eec1dbaf9034e03e3efa0403a774c764373 (diff)
Change exception handling API
This patch changes the exception handling API in the engine slightly, encapsulating any use of direct throw statements and catch blocks with concrete types. In the future we need to be able to change the way these are implemented, in order to ensure that the correct stack unwinding code is triggered for throw and re-throw. This patch separates the C++ exception object thrown from the V4 exception (that includes value, throwing context pointer) and stores the latter inside the engine. In order for that to compile, ExecutionEngine::StackTrace and StackFrame had to move into the QV4 namespace directly. In addition the syntax for catching exceptions changes from try { ... } catch (QV4::Exception &ex) { ex.accept(context); QV4::ScopedValue exceptionValue(scope, ex.value()); } to try { ... } catch (...) { QV4::ScopedValue exception(scope, context->catchException()); } Context::catchException() checks if there's a "current" exception in the engine, and if not assumes that we caught an unrelated exception and consequently re-throws. partiallyUnwind() is also gone and replaced with rethrowException(), in order to encapsulate the re-throw. Lastly, in the future nesting try/catch blocks isn't going to be possible due to limitations in the common C++ ABI with regards to foreign exceptions. Change-Id: Ic81c75b057a2147e3176d8e0b4d326c14278b47d Reviewed-by: Lars Knoll <lars.knoll@digia.com>
-rw-r--r--src/imports/localstorage/plugin.cpp8
-rw-r--r--src/imports/testlib/main.cpp4
-rw-r--r--src/qml/compiler/qv4isel_masm.cpp20
-rw-r--r--src/qml/jsapi/qjsengine.cpp5
-rw-r--r--src/qml/jsapi/qjsvalue.cpp49
-rw-r--r--src/qml/jsapi/qjsvalueiterator.cpp4
-rw-r--r--src/qml/jsruntime/qv4context.cpp27
-rw-r--r--src/qml/jsruntime/qv4context_p.h4
-rw-r--r--src/qml/jsruntime/qv4engine.cpp8
-rw-r--r--src/qml/jsruntime/qv4engine_p.h10
-rw-r--r--src/qml/jsruntime/qv4errorobject.cpp4
-rw-r--r--src/qml/jsruntime/qv4errorobject_p.h2
-rw-r--r--src/qml/jsruntime/qv4exception.cpp55
-rw-r--r--src/qml/jsruntime/qv4exception_gcc.cpp13
-rw-r--r--src/qml/jsruntime/qv4exception_p.h27
-rw-r--r--src/qml/jsruntime/qv4function_p.h2
-rw-r--r--src/qml/jsruntime/qv4functionobject.cpp30
-rw-r--r--src/qml/jsruntime/qv4global_p.h10
-rw-r--r--src/qml/jsruntime/qv4globalobject.cpp6
-rw-r--r--src/qml/jsruntime/qv4include.cpp14
-rw-r--r--src/qml/jsruntime/qv4qobjectwrapper.cpp8
-rw-r--r--src/qml/jsruntime/qv4runtime.cpp3
-rw-r--r--src/qml/jsruntime/qv4script.cpp8
-rw-r--r--src/qml/jsruntime/qv4sequenceobject.cpp2
-rw-r--r--src/qml/jsruntime/qv4serialize.cpp4
-rw-r--r--src/qml/jsruntime/qv4value.cpp15
-rw-r--r--src/qml/jsruntime/qv4vme_moth.cpp14
-rw-r--r--src/qml/qml/qqmlcomponent.cpp6
-rw-r--r--src/qml/qml/qqmlerror.cpp24
-rw-r--r--src/qml/qml/qqmlerror.h7
-rw-r--r--src/qml/qml/qqmljavascriptexpression.cpp62
-rw-r--r--src/qml/qml/qqmljavascriptexpression_p.h8
-rw-r--r--src/qml/qml/qqmltypeloader.cpp6
-rw-r--r--src/qml/qml/qqmlvaluetypewrapper.cpp2
-rw-r--r--src/qml/qml/qqmlvmemetaobject.cpp6
-rw-r--r--src/qml/qml/qqmlxmlhttprequest.cpp15
-rw-r--r--src/qml/qml/v8/qqmlbuiltinfunctions.cpp16
-rw-r--r--src/qml/types/qquickworkerscript.cpp17
-rw-r--r--tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp12
-rw-r--r--tools/v4/main.cpp13
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;
}