diff options
-rw-r--r-- | src/imports/localstorage/localstorage.pro | 1 | ||||
-rw-r--r-- | src/imports/localstorage/plugin.cpp | 62 | ||||
-rw-r--r-- | src/qml/qml/qqmlcomponent.cpp | 26 | ||||
-rw-r--r-- | src/qml/qml/qqmlvmemetaobject.cpp | 31 | ||||
-rw-r--r-- | src/qml/qml/qqmlxmlhttprequest.cpp | 97 | ||||
-rw-r--r-- | src/qml/qml/v8/qqmlbuiltinfunctions.cpp | 26 | ||||
-rw-r--r-- | src/qml/qml/v8/qv8include.cpp | 15 | ||||
-rw-r--r-- | src/qml/qml/v8/qv8qobjectwrapper.cpp | 19 |
8 files changed, 123 insertions, 154 deletions
diff --git a/src/imports/localstorage/localstorage.pro b/src/imports/localstorage/localstorage.pro index 15753263b8..d3e7182a3b 100644 --- a/src/imports/localstorage/localstorage.pro +++ b/src/imports/localstorage/localstorage.pro @@ -4,6 +4,7 @@ TARGETPATH = QtQuick/LocalStorage IMPORT_VERSION = 2.0 QT = sql qml-private core-private +CONFIG += exceptions SOURCES += plugin.cpp diff --git a/src/imports/localstorage/plugin.cpp b/src/imports/localstorage/plugin.cpp index f5627984d8..7ce4f43b9d 100644 --- a/src/imports/localstorage/plugin.cpp +++ b/src/imports/localstorage/plugin.cpp @@ -341,15 +341,17 @@ static QV4::Value qmlsqldatabase_changeVersion(const v8::Arguments& args) ok = false; db.transaction(); - v8::TryCatch tc; - v8::Handle<v8::Value> callbackArgs[] = { instance }; - v8::Handle<v8::Function>::Cast(callback)->Call(v8::Value::fromV4Value(engine->global()), 1, callbackArgs); - - if (tc.HasCaught()) { + QV4::Value callbackArgs[] = { instance->v4Value() }; + QV4::FunctionObject *f = callback->v4Value().asFunctionObject(); + QV4::ExecutionContext *ctx = f->engine()->current; + try { + f->call(engine->global(), callbackArgs, 1); + } catch (QV4::Exception &e) { + e.accept(ctx); db.rollback(); - tc.ReThrow(); - return QV4::Value::undefinedValue(); - } else if (!db.commit()) { + throw; + } + if (!db.commit()) { db.rollback(); V4THROW_SQL(SQLEXCEPTION_UNKNOWN_ERR,QQmlEngine::tr("SQL transaction failed")); } else { @@ -393,18 +395,23 @@ static QV4::Value qmlsqldatabase_transaction_shared(const v8::Arguments& args, b instance->SetExternalResource(q); db.transaction(); - v8::TryCatch tc; - v8::Handle<v8::Value> callbackArgs[] = { instance }; - callback->Call(v8::Value::fromV4Value(engine->global()), 1, callbackArgs); + QV4::FunctionObject *f = callback->v4Value().asFunctionObject(); + if (f) { + QV4::ExecutionContext *ctx = f->engine()->current; + QV4::Value callbackArgs[] = { instance->v4Value() }; + try { + f->call(engine->global(), callbackArgs, 1); + } catch (QV4::Exception &e) { + e.accept(ctx); + q->inTransaction = false; + db.rollback(); + throw; + } - q->inTransaction = false; + q->inTransaction = false; - if (tc.HasCaught()) { - db.rollback(); - tc.ReThrow(); - return QV4::Value::undefinedValue(); - } else if (!db.commit()) { - db.rollback(); + if (!db.commit()) + db.rollback(); } return QV4::Value::undefinedValue(); @@ -674,14 +681,17 @@ void QQuickLocalStorage::openDatabaseSync(QQmlV4Function *args) r->version = version; instance->SetExternalResource(r); - if (created && dbcreationCallback->IsFunction()) { - v8::TryCatch tc; - v8::Handle<v8::Function> callback = v8::Handle<v8::Function>::Cast(dbcreationCallback); - v8::Handle<v8::Value> args[] = { instance }; - callback->Call(v8::Value::fromV4Value(engine->global()), 1, args); - if (tc.HasCaught()) { - tc.ReThrow(); - return; + if (created) { + QV4::FunctionObject *f = dbcreationCallback->v4Value().asFunctionObject(); + if (f) { + QV4::ExecutionContext *ctx = f->engine()->current; + QV4::Value args[] = { instance->v4Value() }; + try { + f->call(engine->global(), args, 1); + } catch (QV4::Exception &e) { + e.accept(ctx); + throw; + } } } diff --git a/src/qml/qml/qqmlcomponent.cpp b/src/qml/qml/qqmlcomponent.cpp index 471d5fca8b..a3f85e243a 100644 --- a/src/qml/qml/qqmlcomponent.cpp +++ b/src/qml/qml/qqmlcomponent.cpp @@ -1475,20 +1475,18 @@ void QV8IncubatorResource::statusChanged(Status s) } if (!me.isEmpty()) { // Will be false in synchronous mode - v8::Handle<v8::Value> callback = v8::Handle<v8::Object>(me)->GetInternalField(0); - - if (!callback.IsEmpty() && !callback->IsUndefined()) { - - if (callback->IsFunction()) { - v8::Handle<v8::Function> f = v8::Handle<v8::Function>::Cast(callback); - v8::Handle<v8::Value> args[] = { v8::Integer::NewFromUnsigned(s) }; - v8::TryCatch tc; - f->Call(me.value(), 1, args); - if (tc.HasCaught()) { - QQmlError error; - QQmlJavaScriptExpression::exceptionToError(tc.Message(), error); - QQmlEnginePrivate::warning(QQmlEnginePrivate::get(engine->engine()), error); - } + QV4::Value callback = v8::Handle<v8::Object>(me)->GetInternalField(0)->v4Value(); + + if (QV4::FunctionObject *f = callback.asFunctionObject()) { + QV4::ExecutionContext *ctx = f->engine()->current; + QV4::Value args[] = { QV4::Value::fromUInt32(s) }; + try { + f->call(me.value(), args, 1); + } catch (QV4::Exception &e) { + e.accept(ctx); + QQmlError error; + QQmlJavaScriptExpression::exceptionToError(e, error); + QQmlEnginePrivate::warning(QQmlEnginePrivate::get(engine->engine()), error); } } } diff --git a/src/qml/qml/qqmlvmemetaobject.cpp b/src/qml/qml/qqmlvmemetaobject.cpp index d1b12eeaec..838950cbdd 100644 --- a/src/qml/qml/qqmlvmemetaobject.cpp +++ b/src/qml/qml/qqmlvmemetaobject.cpp @@ -54,6 +54,7 @@ #include <private/qv4object_p.h> #include <private/qv4variantobject_p.h> +#include <private/qv4functionobject_p.h> QT_BEGIN_NAMESPACE @@ -911,8 +912,8 @@ int QQmlVMEMetaObject::metaCall(QMetaObject::Call c, int _id, void **a) QQmlEnginePrivate *ep = QQmlEnginePrivate::get(ctxt->engine); ep->referenceScarceResources(); // "hold" scarce resources in memory during evaluation. - v8::Handle<v8::Function> function = method(id); - if (function.IsEmpty()) { + QV4::FunctionObject *function = method(id)->v4Value().asFunctionObject(); + if (!function) { // The function was not compiled. There are some exceptional cases which the // expression rewriter does not rewrite properly (e.g., \r-terminated lines // are not rewritten correctly but this bug is deemed out-of-scope to fix for @@ -926,27 +927,23 @@ int QQmlVMEMetaObject::metaCall(QMetaObject::Call c, int _id, void **a) QQmlVMEMetaData::MethodData *data = metaData->methodData() + id; - v8::Handle<v8::Value> *args = 0; + QVarLengthArray<QV4::Value, 9> args; - if (data->parameterCount) { - args = new v8::Handle<v8::Value>[data->parameterCount]; - for (int ii = 0; ii < data->parameterCount; ++ii) - args[ii] = ep->v8engine()->fromVariant(*(QVariant *)a[ii + 1]); - } - - v8::TryCatch try_catch; + for (int ii = 0; ii < data->parameterCount; ++ii) + args[ii] = ep->v8engine()->fromVariant(*(QVariant *)a[ii + 1]); - v8::Handle<v8::Value> result = function->Call(v8::Value::fromV4Value(ep->v8engine()->global()), data->parameterCount, args); - - QVariant rv; - if (try_catch.HasCaught()) { + QV4::Value result = QV4::Value::undefinedValue(); + QV4::ExecutionContext *ctx = function->engine()->current; + try { + result = function->call(ep->v8engine()->global(), args.data(), data->parameterCount); + if (a[0]) *(QVariant *)a[0] = ep->v8engine()->toVariant(result, 0); + } catch (QV4::Exception &e) { + e.accept(ctx); QQmlError error; - QQmlExpressionPrivate::exceptionToError(try_catch.Message(), error); + QQmlExpressionPrivate::exceptionToError(e, error); if (error.isValid()) ep->warning(error); if (a[0]) *(QVariant *)a[0] = QVariant(); - } else { - if (a[0]) *(QVariant *)a[0] = ep->v8engine()->toVariant(result->v4Value(), 0); } ep->dereferenceScarceResources(); // "release" scarce resources if top-level expression evaluation is complete. diff --git a/src/qml/qml/qqmlxmlhttprequest.cpp b/src/qml/qml/qqmlxmlhttprequest.cpp index 8ebda6f189..938a7e5a8f 100644 --- a/src/qml/qml/qqmlxmlhttprequest.cpp +++ b/src/qml/qml/qqmlxmlhttprequest.cpp @@ -999,6 +999,7 @@ private slots: private: void requestFromUrl(const QUrl &url); + QV4::ExecutionEngine *v4; State m_state; bool m_errorFlag; bool m_sendFlag; @@ -1027,7 +1028,7 @@ private: QV4::PersistentValue m_me; void dispatchCallback(const QV4::Value &me); - void printError(v8::Handle<v8::Message>); + void printError(const QV4::Exception &e); int m_status; QString m_statusText; @@ -1040,8 +1041,9 @@ private: }; QQmlXMLHttpRequest::QQmlXMLHttpRequest(QV8Engine *engine, QNetworkAccessManager *manager) -: QV8ObjectResource(engine), m_state(Unsent), m_errorFlag(false), m_sendFlag(false), - m_redirectCount(0), m_gotXml(false), m_textCodec(0), m_network(0), m_nam(manager) + : QV8ObjectResource(engine), v4(QV8Engine::getV4(engine)) + , m_state(Unsent), m_errorFlag(false), m_sendFlag(false) + , m_redirectCount(0), m_gotXml(false), m_textCodec(0), m_network(0), m_nam(manager) { } @@ -1085,9 +1087,7 @@ QV4::Value QQmlXMLHttpRequest::open(v8::Handle<v8::Object> me, const QString &me m_method = method; m_url = url; m_state = Opened; - v8::TryCatch tc; dispatchCallback(me->v4Value()); - if (tc.HasCaught()) printError(tc.Message()); return QV4::Value::undefinedValue(); } @@ -1228,9 +1228,7 @@ QV4::Value QQmlXMLHttpRequest::abort(v8::Handle<v8::Object> me) m_state = Done; m_sendFlag = false; - v8::TryCatch tc; dispatchCallback(me->v4Value()); - if (tc.HasCaught()) printError(tc.Message()); } m_state = Unsent; @@ -1259,18 +1257,14 @@ void QQmlXMLHttpRequest::readyRead() if (m_state < HeadersReceived) { m_state = HeadersReceived; fillHeadersList (); - v8::TryCatch tc; dispatchCallback(m_me.value()); - if (tc.HasCaught()) printError(tc.Message()); } bool wasEmpty = m_responseEntityBody.isEmpty(); m_responseEntityBody.append(m_network->readAll()); if (wasEmpty && !m_responseEntityBody.isEmpty()) m_state = Loading; - v8::TryCatch tc; dispatchCallback(m_me.value()); - if (tc.HasCaught()) printError(tc.Message()); } static const char *errorToString(QNetworkReply::NetworkError error) @@ -1308,9 +1302,7 @@ void QQmlXMLHttpRequest::error(QNetworkReply::NetworkError error) error == QNetworkReply::ContentReSendError || error == QNetworkReply::UnknownContentError) { m_state = Loading; - v8::TryCatch tc; dispatchCallback(m_me.value()); - if (tc.HasCaught()) printError(tc.Message()); } else { m_errorFlag = true; m_responseEntityBody = QByteArray(); @@ -1318,9 +1310,7 @@ void QQmlXMLHttpRequest::error(QNetworkReply::NetworkError error) m_state = Done; - v8::TryCatch tc; dispatchCallback(m_me.value()); - if (tc.HasCaught()) printError(tc.Message()); } #define XMLHTTPREQUEST_MAXIMUM_REDIRECT_RECURSION 15 @@ -1347,9 +1337,7 @@ void QQmlXMLHttpRequest::finished() if (m_state < HeadersReceived) { m_state = HeadersReceived; fillHeadersList (); - v8::TryCatch tc; dispatchCallback(m_me); - if (tc.HasCaught()) printError(tc.Message()); } m_responseEntityBody.append(m_network->readAll()); readEncoding(); @@ -1366,15 +1354,11 @@ void QQmlXMLHttpRequest::finished() destroyNetwork(); if (m_state < Loading) { m_state = Loading; - v8::TryCatch tc; dispatchCallback(m_me); - if (tc.HasCaught()) printError(tc.Message()); } m_state = Done; - v8::TryCatch tc; dispatchCallback(m_me); - if (tc.HasCaught()) printError(tc.Message()); setMe(v8::Handle<v8::Object>()); } @@ -1454,52 +1438,51 @@ const QByteArray &QQmlXMLHttpRequest::rawResponseBody() const return m_responseEntityBody; } -// Requires a TryCatch scope void QQmlXMLHttpRequest::dispatchCallback(const QV4::Value &me) { - if (me.isEmpty() || me.isUndefined() || me.isNull()) { - v8::ThrowException(v8::Exception::Error(v8::String::New("Unable to dispatch QQmlXmlHttpRequest callback: invalid object"))); - return; - } - - QV4::Object *o = me.asObject(); - if (!o) - v8::ThrowException(v8::Exception::Error(v8::String::New("QQmlXMLHttpRequest: internal error: empty ThisObject"))); - - QV4::ExecutionEngine *v4 = o->engine(); - QV4::Object *thisObj = o->get(v4->newString(QStringLiteral("ThisObject"))).asObject(); - if (!thisObj) { - v8::ThrowException(v8::Exception::Error(v8::String::New("QQmlXMLHttpRequest: internal error: empty ThisObject"))); - return; - } + QV4::ExecutionContext *ctx = v4->current; + try { + QV4::Object *o = me.asObject(); + if (!o) + __qmljs_throw(ctx, QV4::Value::fromObject( + v4->newErrorObject(QV4::Value::fromString(ctx, QStringLiteral("QQmlXMLHttpRequest: internal error: empty ThisObject")))), -1); + + QV4::Object *thisObj = o->get(v4->newString(QStringLiteral("ThisObject"))).asObject(); + if (!thisObj) + __qmljs_throw(ctx, QV4::Value::fromObject( + v4->newErrorObject(QV4::Value::fromString(ctx, QStringLiteral("QQmlXMLHttpRequest: internal error: empty ThisObject")))), -1); + + QV4::FunctionObject *callback = thisObj->get(v4->newString(QStringLiteral("onreadystatechange"))).asFunctionObject(); + if (!callback) { + // not an error, but no onreadystatechange function to call. + return; + } - QV4::FunctionObject *callback = thisObj->get(v4->newString(QStringLiteral("onreadystatechange"))).asFunctionObject(); - if (!callback) { - // not an error, but no onreadystatechange function to call. - return; - } + QV4::Value activationObject = o->get(v4->newString(QStringLiteral("ActivationObject"))); + if (!activationObject.asObject()) { + v8::ThrowException(v8::Exception::Error(v8::String::New("QQmlXMLHttpRequest: internal error: empty ActivationObject"))); + return; + } - QV4::Value activationObject = o->get(v4->newString(QStringLiteral("ActivationObject"))); - if (!activationObject.asObject()) { - v8::ThrowException(v8::Exception::Error(v8::String::New("QQmlXMLHttpRequest: internal error: empty ActivationObject"))); - return; + QQmlContextData *callingContext = engine->contextWrapper()->context(activationObject); + if (callingContext) + callback->call(v4->current, activationObject, 0, 0); + + // if the callingContext object is no longer valid, then it has been + // 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(QV4::Exception &e) { + e.accept(ctx); + printError(e); } - - QQmlContextData *callingContext = engine->contextWrapper()->context(activationObject); - if (callingContext) - callback->call(v4->current, activationObject, 0, 0); - - // if the callingContext object is no longer valid, then it has been - // 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. } // Must have a handle scope -void QQmlXMLHttpRequest::printError(v8::Handle<v8::Message> message) +void QQmlXMLHttpRequest::printError(const QV4::Exception &e) { QQmlError error; - QQmlExpressionPrivate::exceptionToError(message, error); + QQmlExpressionPrivate::exceptionToError(e, error); QQmlEnginePrivate::warning(QQmlEnginePrivate::get(engine->engine()), error); } diff --git a/src/qml/qml/v8/qqmlbuiltinfunctions.cpp b/src/qml/qml/v8/qqmlbuiltinfunctions.cpp index 4e8fad369c..bac0c231e2 100644 --- a/src/qml/qml/v8/qqmlbuiltinfunctions.cpp +++ b/src/qml/qml/v8/qqmlbuiltinfunctions.cpp @@ -118,30 +118,8 @@ QV4::Value console(ConsoleLogTypes logType, const v8::Arguments &args, if (i != 0) result.append(QLatin1Char(' ')); - v8::Handle<v8::Value> value = args[i]; - - v8::TryCatch tryCatch; - v8::Handle<v8::String> toString = value->ToString(); - if (tryCatch.HasCaught()) { - // toString() threw Exception - // Is it possible for value to be anything other than Object? - QString str; - if (value->IsObject()) { - str = QStringLiteral("[object Object]"); - } else { - toString = tryCatch.Exception()->ToString(); - str = QStringLiteral("toString() threw exception: %1") - .arg(toString->v4Value().toQString()); - } - result.append(str); - continue; - } - - QString tmp = toString->v4Value().toQString(); - if (value->IsArray()) - result.append(QStringLiteral("[%1]").arg(tmp)); - else - result.append(tmp); + QV4::Value value = args[i]->v4Value(); + result.append(value.toQString()); } if (printStack) { diff --git a/src/qml/qml/v8/qv8include.cpp b/src/qml/qml/v8/qv8include.cpp index f3880ec9a2..5c24a96847 100644 --- a/src/qml/qml/v8/qv8include.cpp +++ b/src/qml/qml/v8/qv8include.cpp @@ -49,6 +49,7 @@ #include <private/qqmlengine_p.h> #include <private/qv4engine_p.h> +#include <private/qv4functionobject_p.h> QT_BEGIN_NAMESPACE @@ -92,10 +93,16 @@ v8::Handle<v8::Object> QV8Include::resultValue(Status status) void QV8Include::callback(QV8Engine *engine, v8::Handle<v8::Function> callback, v8::Handle<v8::Object> status) { - if (!callback.IsEmpty()) { - v8::Handle<v8::Value> args[] = { status }; - v8::TryCatch tc; - callback->Call(v8::Value::fromV4Value(engine->global()), 1, args); + QV4::FunctionObject *f = callback->v4Value().asFunctionObject(); + if (!f) + return; + + QV4::Value args[] = { status->v4Value() }; + QV4::ExecutionContext *ctx = f->engine()->current; + try { + f->call(engine->global(), args, 1); + } catch (QV4::Exception &e) { + e.accept(ctx); } } diff --git a/src/qml/qml/v8/qv8qobjectwrapper.cpp b/src/qml/qml/v8/qv8qobjectwrapper.cpp index b10b17f955..2030bf775c 100644 --- a/src/qml/qml/v8/qv8qobjectwrapper.cpp +++ b/src/qml/qml/v8/qv8qobjectwrapper.cpp @@ -1323,21 +1323,16 @@ int QV8QObjectConnectionList::qt_metacall(QMetaObject::Call method, int index, v if (connection.needsDestroy) continue; - v8::TryCatch try_catch; QV4::FunctionObject *f = connection.function.value().asFunctionObject(); QV4::ExecutionEngine *v4 = f->internalClass->engine; - if (connection.thisObject.isEmpty()) { - f->call(v4->current, engine->global(), args.data(), argCount); - } else { - f->call(v4->current, connection.thisObject, args.data(), argCount); - } - - if (try_catch.HasCaught()) { + QV4::ExecutionContext *ctx = v4->current; + try { + f->call(v4->current, connection.thisObject.isEmpty() ? engine->global() : connection.thisObject.value(), args.data(), argCount); + } catch (QV4::Exception &e) { QQmlError error; - error.setDescription(QString(QLatin1String("Unknown exception occurred during evaluation of connected function: %1")).arg(f->name->toQString())); - v8::Handle<v8::Message> message = try_catch.Message(); - if (!message.IsEmpty()) - QQmlExpressionPrivate::exceptionToError(message, error); + QQmlExpressionPrivate::exceptionToError(e, error); + if (error.description().isEmpty()) + error.setDescription(QString(QLatin1String("Unknown exception occurred during evaluation of connected function: %1")).arg(f->name->toQString())); QQmlEnginePrivate::get(engine->engine())->warning(error); } } |