From: Simon Hausmann Date: Thu, 6 Jun 2013 12:18:11 +0000 (+0200) Subject: Remove signal & slot related code from QV8QObjectWrapper X-Git-Tag: upstream/5.2.1~669^2~312 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=e058cc234c7bb3065b092bed304b7da9f3f98bed;p=platform%2Fupstream%2Fqtdeclarative.git Remove signal & slot related code from QV8QObjectWrapper The code isn't needed anymore. Also moved ExtractQtSignal/QtMethod out, too. Change-Id: I8d7a0ef89ad5ea1ca102a416b70e27597c0279b7 Reviewed-by: Lars Knoll --- diff --git a/src/qml/qml/v8/qv8engine.cpp b/src/qml/qml/v8/qv8engine.cpp index f37006b..4a25ddb 100644 --- a/src/qml/qml/v8/qv8engine.cpp +++ b/src/qml/qml/v8/qv8engine.cpp @@ -100,6 +100,7 @@ QV8Engine::QV8Engine(QJSEngine* qq) v8::Isolate::SetEngine(m_v4Engine); m_v4Engine->v8Engine = this; + QV4::QObjectWrapper::initializeBindings(m_v4Engine); m_qobjectWrapper.init(this); } diff --git a/src/qml/qml/v8/qv8qobjectwrapper.cpp b/src/qml/qml/v8/qv8qobjectwrapper.cpp index 4a48ef2..32d08c3 100644 --- a/src/qml/qml/v8/qv8qobjectwrapper.cpp +++ b/src/qml/qml/v8/qv8qobjectwrapper.cpp @@ -84,6 +84,27 @@ QT_BEGIN_NAMESPACE using namespace QV4; +static QPair extractQtMethod(QV4::FunctionObject *function) +{ + if (function && function->subtype == QV4::FunctionObject::WrappedQtMethod) { + QObjectMethod *method = static_cast(function); + return qMakePair(method->object(), method->methodIndex()); + } + + return qMakePair((QObject *)0, -1); +} + +static QPair extractQtSignal(const Value &value) +{ + if (QV4::FunctionObject *function = value.asFunctionObject()) + return extractQtMethod(function); + + if (QV4::QmlSignalHandler *handler = value.as()) + return qMakePair(handler->object(), handler->signalIndex()); + + return qMakePair((QObject *)0, -1); +} + QObjectWrapper::QObjectWrapper(ExecutionEngine *engine, QObject *object) : Object(engine) , m_object(object) @@ -100,6 +121,12 @@ QObjectWrapper::~QObjectWrapper() deleteQObject(); } +void QObjectWrapper::initializeBindings(ExecutionEngine *engine) +{ + engine->functionPrototype->defineDefaultProperty(engine, QStringLiteral("connect"), method_connect); + engine->functionPrototype->defineDefaultProperty(engine, QStringLiteral("disconnect"), method_disconnect); +} + void QObjectWrapper::deleteQObject(bool deleteInstantly) { if (!m_object) @@ -303,6 +330,201 @@ QV4::Value QObjectWrapper::enumerateProperties(Object *object) return QV4::Value::fromObject(that->engine()->newArrayObject(result)); } +namespace QV4 { + +struct QObjectSlotDispatcher : public QtPrivate::QSlotObjectBase +{ + QV4::PersistentValue function; + QV4::PersistentValue thisObject; + int signalIndex; + + QObjectSlotDispatcher() + : QtPrivate::QSlotObjectBase(&impl) + , signalIndex(-1) + {} + + static void impl(int which, QSlotObjectBase *this_, QObject *r, void **metaArgs, bool *ret) + { + switch (which) { + case Destroy: { + delete static_cast(this_); + } + break; + case Call: { + QObjectSlotDispatcher *This = static_cast(this_); + QVarLengthArray dummy; + int *argsTypes = QQmlPropertyCache::methodParameterTypes(r, This->signalIndex, dummy, 0); + + int argCount = argsTypes ? argsTypes[0]:0; + + QV4::FunctionObject *f = This->function.value().asFunctionObject(); + QV4::ExecutionEngine *v4 = f->internalClass->engine; + QV4::ExecutionContext *ctx = v4->current; + + QVarLengthArray args(argCount); + for (int ii = 0; ii < argCount; ++ii) { + int type = argsTypes[ii + 1]; + if (type == qMetaTypeId()) { + args[ii] = v4->v8Engine->fromVariant(*((QVariant *)metaArgs[ii + 1])); + } else { + args[ii] = v4->v8Engine->fromVariant(QVariant(type, metaArgs[ii + 1])); + } + } + + try { + f->call(v4->current, This->thisObject.isEmpty() ? Value::fromObject(v4->globalObject) : This->thisObject.value(), args.data(), argCount); + } catch (QV4::Exception &e) { + e.accept(ctx); + QQmlError 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(v4->v8Engine->engine())->warning(error); + } + } + break; + case Compare: { + QObjectSlotDispatcher *connection = static_cast(this_); + if (connection->function.isEmpty()) { + *ret = false; + return; + } + + // This is tricky. Normally the metaArgs[0] pointer is a pointer to the _function_ + // for the new-style QObject::connect. Here we use the engine pointer as sentinel + // to distinguish those type of QSlotObjectBase connections from our QML connections. + QV4::ExecutionEngine *v4 = reinterpret_cast(metaArgs[0]); + if (v4 != connection->function.engine()) { + *ret = false; + return; + } + + QV4::Value function = *reinterpret_cast(metaArgs[1]); + QV4::Value thisObject = *reinterpret_cast(metaArgs[2]); + QObject *receiverToDisconnect = reinterpret_cast(metaArgs[3]); + int slotIndexToDisconnect = *reinterpret_cast(metaArgs[4]); + + if (slotIndexToDisconnect != -1) { + // This is a QObject function wrapper + if (connection->thisObject.isEmpty() == thisObject.isEmpty() && + (connection->thisObject.isEmpty() || __qmljs_strict_equal(connection->thisObject, thisObject))) { + + QPair connectedFunctionData = extractQtMethod(connection->function.value().asFunctionObject()); + if (connectedFunctionData.first == receiverToDisconnect && + connectedFunctionData.second == slotIndexToDisconnect) { + *ret = true; + return; + } + } + } else { + // This is a normal JS function + if (__qmljs_strict_equal(connection->function, function) && + connection->thisObject.isEmpty() == thisObject.isEmpty() && + (connection->thisObject.isEmpty() || __qmljs_strict_equal(connection->thisObject, thisObject))) { + *ret = true; + return; + } + } + + *ret = false; + } + break; + case NumOperations: + break; + } + }; +}; + +} // namespace QV4 + +Value QObjectWrapper::method_connect(SimpleCallContext *ctx) +{ + if (ctx->argumentCount == 0) + V4THROW_ERROR("Function.prototype.connect: no arguments given"); + + QPair signalInfo = extractQtSignal(ctx->thisObject); + QObject *signalObject = signalInfo.first; + int signalIndex = signalInfo.second; + + if (signalIndex < 0) + V4THROW_ERROR("Function.prototype.connect: this object is not a signal"); + + if (!signalObject) + V4THROW_ERROR("Function.prototype.connect: cannot connect to deleted QObject"); + + if (signalObject->metaObject()->method(signalIndex).methodType() != QMetaMethod::Signal) + V4THROW_ERROR("Function.prototype.connect: this object is not a signal"); + + QV4::QObjectSlotDispatcher *slot = new QV4::QObjectSlotDispatcher; + slot->signalIndex = signalIndex; + + if (ctx->argumentCount == 1) { + slot->function = ctx->arguments[0]; + } else if (ctx->argumentCount >= 2) { + slot->thisObject = ctx->arguments[0]; + slot->function = ctx->arguments[1]; + } + + if (!slot->function.value().asFunctionObject()) + V4THROW_ERROR("Function.prototype.connect: target is not a function"); + + if (!slot->thisObject.isEmpty() && !slot->thisObject.value().isObject()) + V4THROW_ERROR("Function.prototype.connect: target this is not an object"); + + QObjectPrivate::connect(signalObject, signalIndex, slot, Qt::AutoConnection); + + return QV4::Value::undefinedValue(); +} + +Value QObjectWrapper::method_disconnect(SimpleCallContext *ctx) +{ + if (ctx->argumentCount == 0) + V4THROW_ERROR("Function.prototype.disconnect: no arguments given"); + + QPair signalInfo = extractQtSignal(ctx->thisObject); + QObject *signalObject = signalInfo.first; + int signalIndex = signalInfo.second; + + if (signalIndex == -1) + V4THROW_ERROR("Function.prototype.disconnect: this object is not a signal"); + + if (!signalObject) + V4THROW_ERROR("Function.prototype.disconnect: cannot disconnect from deleted QObject"); + + if (signalIndex < 0 || signalObject->metaObject()->method(signalIndex).methodType() != QMetaMethod::Signal) + V4THROW_ERROR("Function.prototype.disconnect: this object is not a signal"); + + QV4::Value functionValue = QV4::Value::emptyValue(); + QV4::Value functionThisValue = QV4::Value::emptyValue(); + + if (ctx->argumentCount == 1) { + functionValue = ctx->arguments[0]; + } else if (ctx->argumentCount >= 2) { + functionThisValue = ctx->arguments[0]; + functionValue = ctx->arguments[1]; + } + + if (!functionValue.asFunctionObject()) + V4THROW_ERROR("Function.prototype.disconnect: target is not a function"); + + if (!functionThisValue.isEmpty() && !functionThisValue.isObject()) + V4THROW_ERROR("Function.prototype.disconnect: target this is not an object"); + + QPair functionData = extractQtMethod(functionValue.asFunctionObject()); + + void *a[] = { + ctx->engine, + &functionValue, + &functionThisValue, + functionData.first, + &functionData.second + }; + + QObjectPrivate::disconnect(signalObject, signalIndex, reinterpret_cast(&a)); + + return QV4::Value::undefinedValue(); +} + void QObjectWrapper::markObjects(Managed *that) { QObjectWrapper *This = static_cast(that); @@ -442,11 +664,6 @@ static inline QV4::Value valueToHandle(QV8Engine *e, QObject *v) void QV8QObjectWrapper::init(QV8Engine *engine) { m_engine = engine; - - QV4::ExecutionEngine *v4 = QV8Engine::getV4(engine); - - v4->functionPrototype->defineDefaultProperty(v4, QStringLiteral("connect"), Connect); - v4->functionPrototype->defineDefaultProperty(v4, QStringLiteral("disconnect"), Disconnect); } // Load value properties @@ -812,226 +1029,6 @@ static void FastValueSetterReadOnly(v8::Handle property, v8::Handle< v8::ThrowException(v8::Exception::Error(v8engine->toString(error))); } -QPair QV8QObjectWrapper::ExtractQtSignal(QV8Engine *engine, const Value &value) -{ - if (QV4::FunctionObject *function = value.asFunctionObject()) - return ExtractQtMethod(engine, function); - - if (QV4::QmlSignalHandler *handler = value.as()) - return qMakePair(handler->object(), handler->signalIndex()); - - return qMakePair((QObject *)0, -1); -} - -QPair QV8QObjectWrapper::ExtractQtMethod(QV8Engine *engine, QV4::FunctionObject *function) -{ - if (function && function->subtype == QV4::FunctionObject::WrappedQtMethod) { - QObjectMethod *method = static_cast(function); - return qMakePair(method->object(), method->methodIndex()); - } - - return qMakePair((QObject *)0, -1); -} - -namespace QV4 { - -struct QObjectSlotDispatcher : public QtPrivate::QSlotObjectBase -{ - QV4::PersistentValue function; - QV4::PersistentValue thisObject; - int signalIndex; - - QObjectSlotDispatcher() - : QtPrivate::QSlotObjectBase(&impl) - , signalIndex(-1) - {} - - static void impl(int which, QSlotObjectBase *this_, QObject *r, void **metaArgs, bool *ret) - { - switch (which) { - case Destroy: { - delete static_cast(this_); - } - break; - case Call: { - QObjectSlotDispatcher *This = static_cast(this_); - QVarLengthArray dummy; - int *argsTypes = QQmlPropertyCache::methodParameterTypes(r, This->signalIndex, dummy, 0); - - int argCount = argsTypes ? argsTypes[0]:0; - - QV4::FunctionObject *f = This->function.value().asFunctionObject(); - QV4::ExecutionEngine *v4 = f->internalClass->engine; - QV4::ExecutionContext *ctx = v4->current; - - QVarLengthArray args(argCount); - for (int ii = 0; ii < argCount; ++ii) { - int type = argsTypes[ii + 1]; - if (type == qMetaTypeId()) { - args[ii] = v4->v8Engine->fromVariant(*((QVariant *)metaArgs[ii + 1])); - } else { - args[ii] = v4->v8Engine->fromVariant(QVariant(type, metaArgs[ii + 1])); - } - } - - try { - f->call(v4->current, This->thisObject.isEmpty() ? Value::fromObject(v4->globalObject) : This->thisObject.value(), args.data(), argCount); - } catch (QV4::Exception &e) { - e.accept(ctx); - QQmlError 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(v4->v8Engine->engine())->warning(error); - } - } - break; - case Compare: { - QObjectSlotDispatcher *connection = static_cast(this_); - if (connection->function.isEmpty()) { - *ret = false; - return; - } - - // This is tricky. Normally the metaArgs[0] pointer is a pointer to the _function_ - // for the new-style QObject::connect. Here we use the engine pointer as sentinel - // to distinguish those type of QSlotObjectBase connections from our QML connections. - QV4::ExecutionEngine *v4 = reinterpret_cast(metaArgs[0]); - if (v4 != connection->function.engine()) { - *ret = false; - return; - } - - QV4::Value function = *reinterpret_cast(metaArgs[1]); - QV4::Value thisObject = *reinterpret_cast(metaArgs[2]); - QObject *receiverToDisconnect = reinterpret_cast(metaArgs[3]); - int slotIndexToDisconnect = *reinterpret_cast(metaArgs[4]); - - if (slotIndexToDisconnect != -1) { - // This is a QObject function wrapper - if (connection->thisObject.isEmpty() == thisObject.isEmpty() && - (connection->thisObject.isEmpty() || __qmljs_strict_equal(connection->thisObject, thisObject))) { - - QPair connectedFunctionData = QV8QObjectWrapper::ExtractQtMethod(v4->v8Engine, connection->function.value().asFunctionObject()); - if (connectedFunctionData.first == receiverToDisconnect && - connectedFunctionData.second == slotIndexToDisconnect) { - *ret = true; - return; - } - } - } else { - // This is a normal JS function - if (__qmljs_strict_equal(connection->function, function) && - connection->thisObject.isEmpty() == thisObject.isEmpty() && - (connection->thisObject.isEmpty() || __qmljs_strict_equal(connection->thisObject, thisObject))) { - *ret = true; - return; - } - } - - *ret = false; - } - break; - case NumOperations: - break; - } - }; -}; - -} - -QV4::Value QV8QObjectWrapper::Connect(SimpleCallContext *ctx) -{ - if (ctx->argumentCount == 0) - V4THROW_ERROR("Function.prototype.connect: no arguments given"); - - QV8Engine *engine = ctx->engine->v8Engine; - - QPair signalInfo = ExtractQtSignal(engine, ctx->thisObject); - QObject *signalObject = signalInfo.first; - int signalIndex = signalInfo.second; - - if (signalIndex < 0) - V4THROW_ERROR("Function.prototype.connect: this object is not a signal"); - - if (!signalObject) - V4THROW_ERROR("Function.prototype.connect: cannot connect to deleted QObject"); - - if (signalObject->metaObject()->method(signalIndex).methodType() != QMetaMethod::Signal) - V4THROW_ERROR("Function.prototype.connect: this object is not a signal"); - - QV4::QObjectSlotDispatcher *slot = new QV4::QObjectSlotDispatcher; - slot->signalIndex = signalIndex; - - if (ctx->argumentCount == 1) { - slot->function = ctx->arguments[0]; - } else if (ctx->argumentCount >= 2) { - slot->thisObject = ctx->arguments[0]; - slot->function = ctx->arguments[1]; - } - - if (!slot->function.value().asFunctionObject()) - V4THROW_ERROR("Function.prototype.connect: target is not a function"); - - if (!slot->thisObject.isEmpty() && !slot->thisObject.value().isObject()) - V4THROW_ERROR("Function.prototype.connect: target this is not an object"); - - QObjectPrivate::connect(signalObject, signalIndex, slot, Qt::AutoConnection); - - return QV4::Value::undefinedValue(); -} - -QV4::Value QV8QObjectWrapper::Disconnect(SimpleCallContext *ctx) -{ - if (ctx->argumentCount == 0) - V4THROW_ERROR("Function.prototype.disconnect: no arguments given"); - - QV8Engine *engine = ctx->engine->v8Engine; - - QPair signalInfo = ExtractQtSignal(engine, ctx->thisObject); - QObject *signalObject = signalInfo.first; - int signalIndex = signalInfo.second; - - if (signalIndex == -1) - V4THROW_ERROR("Function.prototype.disconnect: this object is not a signal"); - - if (!signalObject) - V4THROW_ERROR("Function.prototype.disconnect: cannot disconnect from deleted QObject"); - - if (signalIndex < 0 || signalObject->metaObject()->method(signalIndex).methodType() != QMetaMethod::Signal) - V4THROW_ERROR("Function.prototype.disconnect: this object is not a signal"); - - QV4::Value functionValue = QV4::Value::emptyValue(); - QV4::Value functionThisValue = QV4::Value::emptyValue(); - - if (ctx->argumentCount == 1) { - functionValue = ctx->arguments[0]; - } else if (ctx->argumentCount >= 2) { - functionThisValue = ctx->arguments[0]; - functionValue = ctx->arguments[1]; - } - - if (!functionValue.asFunctionObject()) - V4THROW_ERROR("Function.prototype.disconnect: target is not a function"); - - if (!functionThisValue.isEmpty() && !functionThisValue.isObject()) - V4THROW_ERROR("Function.prototype.disconnect: target this is not an object"); - - QPair functionData = ExtractQtMethod(engine, functionValue.asFunctionObject()); - - void *a[] = { - ctx->engine, - &functionValue, - &functionThisValue, - functionData.first, - &functionData.second - }; - - QObjectPrivate::disconnect(signalObject, signalIndex, reinterpret_cast(&a)); - - return QV4::Value::undefinedValue(); -} - /*! \fn v8::Handle QV8QObjectWrapper::getProperty(QObject *object, const QHashedV8String &property, QV8QObjectWrapper::RevisionMode revisionMode) diff --git a/src/qml/qml/v8/qv8qobjectwrapper_p.h b/src/qml/qml/v8/qv8qobjectwrapper_p.h index 18c0c26..e06ce49 100644 --- a/src/qml/qml/v8/qv8qobjectwrapper_p.h +++ b/src/qml/qml/v8/qv8qobjectwrapper_p.h @@ -73,7 +73,6 @@ class QObject; class QV8Engine; class QQmlData; class QV8ObjectResource; -class QV8QObjectConnectionList; class QQmlPropertyCache; namespace QV4 { @@ -87,6 +86,8 @@ struct Q_QML_EXPORT QObjectWrapper : public QV4::Object ~QObjectWrapper(); + static void initializeBindings(ExecutionEngine *engine); + QObject *object() const { return m_object.data(); } void deleteQObject(bool deleteInstantly = false); @@ -114,6 +115,9 @@ private: { static_cast(that)->~QObjectWrapper(); } + + static Value method_connect(SimpleCallContext *ctx); + static Value method_disconnect(SimpleCallContext *ctx); }; struct QObjectMethod : public QV4::FunctionObject @@ -204,7 +208,6 @@ public: private: friend class QQmlPropertyCache; - friend class QV8QObjectConnectionList; friend struct QV4::QObjectWrapper; friend struct QV4::QObjectSlotDispatcher; @@ -212,13 +215,8 @@ private: const QHashedV4String &, QQmlContextData *, QV4::QObjectWrapper::RevisionMode); static bool SetProperty(QV8Engine *, QObject *, const QHashedV4String &, QQmlContextData *, v8::Handle, QV4::QObjectWrapper::RevisionMode); - static QV4::Value Connect(QV4::SimpleCallContext *ctx); - static QV4::Value Disconnect(QV4::SimpleCallContext *ctx); - static QPair ExtractQtMethod(QV8Engine *, QV4::FunctionObject *); - static QPair ExtractQtSignal(QV8Engine *, const QV4::Value &value); QV8Engine *m_engine; - QHash m_connections; }; v8::Handle QV8QObjectWrapper::getProperty(QObject *object, const QHashedV4String &string,