Remove signal & slot related code from QV8QObjectWrapper
authorSimon Hausmann <simon.hausmann@digia.com>
Thu, 6 Jun 2013 12:18:11 +0000 (14:18 +0200)
committerLars Knoll <lars.knoll@digia.com>
Fri, 7 Jun 2013 16:32:50 +0000 (18:32 +0200)
The code isn't needed anymore. Also moved ExtractQtSignal/QtMethod
out, too.

Change-Id: I8d7a0ef89ad5ea1ca102a416b70e27597c0279b7
Reviewed-by: Lars Knoll <lars.knoll@digia.com>
src/qml/qml/v8/qv8engine.cpp
src/qml/qml/v8/qv8qobjectwrapper.cpp
src/qml/qml/v8/qv8qobjectwrapper_p.h

index f37006b..4a25ddb 100644 (file)
@@ -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);
 }
 
index 4a48ef2..32d08c3 100644 (file)
@@ -84,6 +84,27 @@ QT_BEGIN_NAMESPACE
 
 using namespace QV4;
 
+static QPair<QObject *, int> extractQtMethod(QV4::FunctionObject *function)
+{
+    if (function && function->subtype == QV4::FunctionObject::WrappedQtMethod) {
+        QObjectMethod *method = static_cast<QObjectMethod*>(function);
+        return qMakePair(method->object(), method->methodIndex());
+    }
+
+    return qMakePair((QObject *)0, -1);
+}
+
+static QPair<QObject *, int> extractQtSignal(const Value &value)
+{
+    if (QV4::FunctionObject *function = value.asFunctionObject())
+        return extractQtMethod(function);
+
+    if (QV4::QmlSignalHandler *handler = value.as<QV4::QmlSignalHandler>())
+        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<QObjectSlotDispatcher*>(this_);
+        }
+        break;
+        case Call: {
+            QObjectSlotDispatcher *This = static_cast<QObjectSlotDispatcher*>(this_);
+            QVarLengthArray<int, 9> 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<QV4::Value, 9> args(argCount);
+            for (int ii = 0; ii < argCount; ++ii) {
+                int type = argsTypes[ii + 1];
+                if (type == qMetaTypeId<QVariant>()) {
+                    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<QObjectSlotDispatcher*>(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<QV4::ExecutionEngine*>(metaArgs[0]);
+            if (v4 != connection->function.engine()) {
+                *ret = false;
+                return;
+            }
+
+            QV4::Value function = *reinterpret_cast<QV4::Value*>(metaArgs[1]);
+            QV4::Value thisObject = *reinterpret_cast<QV4::Value*>(metaArgs[2]);
+            QObject *receiverToDisconnect = reinterpret_cast<QObject*>(metaArgs[3]);
+            int slotIndexToDisconnect = *reinterpret_cast<int*>(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<QObject *, int> 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<QObject *, int> 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<QObject *, int> 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<QObject *, int> functionData = extractQtMethod(functionValue.asFunctionObject());
+
+    void *a[] = {
+        ctx->engine,
+        &functionValue,
+        &functionThisValue,
+        functionData.first,
+        &functionData.second
+    };
+
+    QObjectPrivate::disconnect(signalObject, signalIndex, reinterpret_cast<void**>(&a));
+
+    return QV4::Value::undefinedValue();
+}
+
 void QObjectWrapper::markObjects(Managed *that)
 {
     QObjectWrapper *This = static_cast<QObjectWrapper*>(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<v8::String> property, v8::Handle<
     v8::ThrowException(v8::Exception::Error(v8engine->toString(error)));
 }
 
-QPair<QObject *, int> QV8QObjectWrapper::ExtractQtSignal(QV8Engine *engine, const Value &value)
-{
-    if (QV4::FunctionObject *function = value.asFunctionObject())
-        return ExtractQtMethod(engine, function);
-
-    if (QV4::QmlSignalHandler *handler = value.as<QV4::QmlSignalHandler>())
-        return qMakePair(handler->object(), handler->signalIndex());
-
-    return qMakePair((QObject *)0, -1);
-}
-
-QPair<QObject *, int> QV8QObjectWrapper::ExtractQtMethod(QV8Engine *engine, QV4::FunctionObject *function)
-{
-    if (function && function->subtype == QV4::FunctionObject::WrappedQtMethod) {
-        QObjectMethod *method = static_cast<QObjectMethod*>(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<QObjectSlotDispatcher*>(this_);
-        }
-        break;
-        case Call: {
-            QObjectSlotDispatcher *This = static_cast<QObjectSlotDispatcher*>(this_);
-            QVarLengthArray<int, 9> 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<QV4::Value, 9> args(argCount);
-            for (int ii = 0; ii < argCount; ++ii) {
-                int type = argsTypes[ii + 1];
-                if (type == qMetaTypeId<QVariant>()) {
-                    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<QObjectSlotDispatcher*>(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<QV4::ExecutionEngine*>(metaArgs[0]);
-            if (v4 != connection->function.engine()) {
-                *ret = false;
-                return;
-            }
-
-            QV4::Value function = *reinterpret_cast<QV4::Value*>(metaArgs[1]);
-            QV4::Value thisObject = *reinterpret_cast<QV4::Value*>(metaArgs[2]);
-            QObject *receiverToDisconnect = reinterpret_cast<QObject*>(metaArgs[3]);
-            int slotIndexToDisconnect = *reinterpret_cast<int*>(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<QObject *, int> 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<QObject *, int> 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<QObject *, int> 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<QObject *, int> functionData = ExtractQtMethod(engine, functionValue.asFunctionObject());
-
-    void *a[] = {
-        ctx->engine,
-        &functionValue,
-        &functionThisValue,
-        functionData.first,
-        &functionData.second
-    };
-
-    QObjectPrivate::disconnect(signalObject, signalIndex, reinterpret_cast<void**>(&a));
-
-    return QV4::Value::undefinedValue();
-}
-
 /*!
     \fn v8::Handle<v8::Value> QV8QObjectWrapper::getProperty(QObject *object, const QHashedV8String &property, QV8QObjectWrapper::RevisionMode revisionMode)
 
index 18c0c26..e06ce49 100644 (file)
@@ -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<QObjectWrapper *>(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<v8::Value>, QV4::QObjectWrapper::RevisionMode);
-    static QV4::Value Connect(QV4::SimpleCallContext *ctx);
-    static QV4::Value Disconnect(QV4::SimpleCallContext *ctx);
-    static QPair<QObject *, int> ExtractQtMethod(QV8Engine *, QV4::FunctionObject *);
-    static QPair<QObject *, int> ExtractQtSignal(QV8Engine *, const QV4::Value &value);
 
     QV8Engine *m_engine;
-    QHash<QObject *, QV8QObjectConnectionList *> m_connections;
 };
 
 v8::Handle<v8::Value> QV8QObjectWrapper::getProperty(QObject *object, const QHashedV4String &string,