From bc3491c1b85ca36486c9472ecf7ba82f46699e8a Mon Sep 17 00:00:00 2001
From: Olivier Goffart <olivier.goffart@nokia.com>
Date: Wed, 5 May 2010 09:44:58 +0200
Subject: Speedup activation of signals

The virtual QObject::qt_metacall will recurse to the whole object hierarchy
to find from which class a function should be called.
But it is possible to know, at connection time, from which exact
QMetaObject a function belongs, and the relative offset into it.
So we make the slot calls from the qt_static_metacall function.
So activation of signals is faster.

 - We must not call a slot from a class that has been destroyed.
   To avoid this, there is a check on the methodOffset. If it is
   smaller, that means we might be called (indirectly) from
   the destructor. We fallback to the virtual call to qt_metacall
   that does the right thing.

 - The signature of the static method is void (*) (QObject*,MetaCall,int,void**)
   It returns void, so the compiler is allowed to do tail recusive
   optimization.  Having the QObject* as first parameter make it ready
   on the stack for the call to the member function.

 - The new static method has to be a member function in order to
   be able to access the private slots.

Reviewed-by: brad
---
 src/corelib/kernel/qmetaobject.cpp |  35 ++++++---
 src/corelib/kernel/qmetaobject_p.h |   6 +-
 src/corelib/kernel/qobject.cpp     | 128 +++++++++++++++++++-----------
 src/corelib/kernel/qobject_p.h     |  10 ++-
 src/corelib/kernel/qobjectdefs.h   |   7 +-
 src/tools/moc/generator.cpp        | 157 ++++++++++++++++++++++---------------
 src/tools/moc/generator.h          |   2 +-
 src/tools/moc/moc.cpp              |   6 +-
 src/tools/moc/moc.h                |   3 +-
 src/tools/moc/outputrevision.h     |   2 +-
 10 files changed, 221 insertions(+), 135 deletions(-)

diff --git a/src/corelib/kernel/qmetaobject.cpp b/src/corelib/kernel/qmetaobject.cpp
index c5775f6..4bf4290 100644
--- a/src/corelib/kernel/qmetaobject.cpp
+++ b/src/corelib/kernel/qmetaobject.cpp
@@ -218,12 +218,20 @@ QObject *QMetaObject::newInstance(QGenericArgument val0,
 */
 int QMetaObject::static_metacall(Call cl, int idx, void **argv) const
 {
-    if (priv(d.data)->revision < 2)
-        return 0;
-    const QMetaObjectExtraData *extra = (const QMetaObjectExtraData*)(d.extradata);
-    if (!extra || !extra->static_metacall)
-        return 0;
-    return extra->static_metacall(cl, idx, argv);
+    const QMetaObjectExtraData *extra = reinterpret_cast<const QMetaObjectExtraData *>(d.extradata);
+    if (priv(d.data)->revision >= 6) {
+        if (!extra || !extra->static_metacall)
+            return 0;
+        extra->static_metacall(0, cl, idx, argv);
+        return -1;
+    } else if (priv(d.data)->revision >= 2) {
+        if (!extra || !extra->static_metacall)
+            return 0;
+        typedef int (*OldMetacall)(QMetaObject::Call, int, void **);
+        OldMetacall o = reinterpret_cast<OldMetacall>(extra->static_metacall);
+        return o(cl, idx, argv);
+    }
+    return 0;
 }
 
 /*!
@@ -639,20 +647,21 @@ int QMetaObjectPrivate::indexOfSignalRelative(const QMetaObject **baseObject,
 */
 int QMetaObject::indexOfSlot(const char *slot) const
 {
-    int i = QMetaObjectPrivate::indexOfSlot(this, slot, false);
+    const QMetaObject *m = this;
+    int i = QMetaObjectPrivate::indexOfSlotRelative(&m, slot, false);
     if (i < 0)
-        i = QMetaObjectPrivate::indexOfSlot(this, slot, true);
+        i = QMetaObjectPrivate::indexOfSlotRelative(&m, slot, true);
+    if (i >= 0)
+        i += methodOffset();
     return i;
 }
 
-int QMetaObjectPrivate::indexOfSlot(const QMetaObject *m,
+// same as indexOfSignalRelative but for slots.
+int QMetaObjectPrivate::indexOfSlotRelative(const QMetaObject **m,
                                     const char *slot,
                                     bool normalizeStringData)
 {
-    int i = indexOfMethodRelative<MethodSlot>(&m, slot, normalizeStringData);
-    if (i >= 0)
-        i += m->methodOffset();
-    return i;
+    return indexOfMethodRelative<MethodSlot>(m, slot, normalizeStringData);
 }
 
 static const QMetaObject *QMetaObject_findMetaObject(const QMetaObject *self, const char *name)
diff --git a/src/corelib/kernel/qmetaobject_p.h b/src/corelib/kernel/qmetaobject_p.h
index 210b32c..fdadf4a 100644
--- a/src/corelib/kernel/qmetaobject_p.h
+++ b/src/corelib/kernel/qmetaobject_p.h
@@ -118,6 +118,7 @@ struct QMetaObjectPrivate
     int flags; //since revision 3
     int signalCount; //since revision 4
     // revision 5 introduces changes in normalized signatures, no new members
+    // revision 6 added qt_static_metacall as a member of each Q_OBJECT and inside QMetaObject itself
 
     static inline const QMetaObjectPrivate *get(const QMetaObject *metaobject)
     { return reinterpret_cast<const QMetaObjectPrivate*>(metaobject->d.data); }
@@ -125,7 +126,7 @@ struct QMetaObjectPrivate
     static int indexOfSignalRelative(const QMetaObject **baseObject,
                                      const char* name,
                                      bool normalizeStringData);
-    static int indexOfSlot(const QMetaObject *m,
+    static int indexOfSlotRelative(const QMetaObject **m,
                            const char *slot,
                            bool normalizeStringData);
     static int originalClone(const QMetaObject *obj, int local_method_index);
@@ -136,7 +137,8 @@ struct QMetaObjectPrivate
     static void memberIndexes(const QObject *obj, const QMetaMethod &member,
                               int *signalIndex, int *methodIndex);
     static bool connect(const QObject *sender, int signal_index,
-                        const QObject *receiver, int method_index,
+                        const QObject *receiver, int method_index_relative,
+                        const QMetaObject *rmeta = 0,
                         int type = 0, int *types = 0);
     static bool disconnect(const QObject *sender, int signal_index,
                            const QObject *receiver, int method_index,
diff --git a/src/corelib/kernel/qobject.cpp b/src/corelib/kernel/qobject.cpp
index c6f2456..4cbeee2 100644
--- a/src/corelib/kernel/qobject.cpp
+++ b/src/corelib/kernel/qobject.cpp
@@ -2607,18 +2607,17 @@ bool QObject::connect(const QObject *sender, const char *signal,
     ++method; // skip code
 
     const QMetaObject *rmeta = receiver->metaObject();
-    int method_index = -1;
+    int method_index_relative = -1;
     switch (membcode) {
     case QSLOT_CODE:
-        method_index = QMetaObjectPrivate::indexOfSlot(rmeta, method, false);
+        method_index_relative = QMetaObjectPrivate::indexOfSlotRelative(&rmeta, method, false);
         break;
     case QSIGNAL_CODE:
-        method_index = QMetaObjectPrivate::indexOfSignalRelative(&rmeta, method, false);
-        if (method_index >= 0)
-            method_index += rmeta->methodOffset();
+        method_index_relative = QMetaObjectPrivate::indexOfSignalRelative(&rmeta, method, false);
         break;
     }
-    if (method_index < 0) {
+
+    if (method_index_relative < 0) {
         // check for normalized methods
         tmp_method_name = QMetaObject::normalizedSignature(method);
         method = tmp_method_name.constData();
@@ -2627,19 +2626,24 @@ bool QObject::connect(const QObject *sender, const char *signal,
         rmeta = receiver->metaObject();
         switch (membcode) {
         case QSLOT_CODE:
-            method_index = rmeta->indexOfSlot(method);
+            method_index_relative = QMetaObjectPrivate::indexOfSlotRelative(&rmeta, method, false);
+            if (method_index_relative < 0)
+                method_index_relative = QMetaObjectPrivate::indexOfSlotRelative(&rmeta, method, true);
             break;
         case QSIGNAL_CODE:
-            method_index = rmeta->indexOfSignal(method);
+            method_index_relative = QMetaObjectPrivate::indexOfSignalRelative(&rmeta, method, false);
+            if (method_index_relative < 0)
+                method_index_relative = QMetaObjectPrivate::indexOfSignalRelative(&rmeta, method, true);
             break;
         }
     }
 
-    if (method_index < 0) {
+    if (method_index_relative < 0) {
         err_method_notfound(receiver, method_arg, "connect");
         err_info_about_objects("connect", sender, receiver);
         return false;
     }
+
     if (!QMetaObject::checkConnectArgs(signal, method)) {
         qWarning("QObject::connect: Incompatible sender/receiver arguments"
                  "\n        %s::%s --> %s::%s",
@@ -2654,14 +2658,13 @@ bool QObject::connect(const QObject *sender, const char *signal,
         return false;
 
 #ifndef QT_NO_DEBUG
-    {
+    if (warnCompat) {
         QMetaMethod smethod = smeta->method(signal_absolute_index);
-        QMetaMethod rmethod = rmeta->method(method_index);
-        if (warnCompat)
-            check_and_warn_compat(smeta, smethod, rmeta, rmethod);
+        QMetaMethod rmethod = rmeta->method(method_index_relative + rmeta->methodOffset());
+        check_and_warn_compat(smeta, smethod, rmeta, rmethod);
     }
 #endif
-    if (!QMetaObjectPrivate::connect(sender, signal_index, receiver, method_index, type, types))
+    if (!QMetaObjectPrivate::connect(sender, signal_index, receiver, method_index_relative, rmeta ,type, types))
         return false;
     const_cast<QObject*>(sender)->connectNotify(signal - 1);
     return true;
@@ -2766,7 +2769,7 @@ bool QObject::connect(const QObject *sender, const QMetaMethod &signal,
     if (warnCompat)
         check_and_warn_compat(smeta, signal, rmeta, method);
 #endif
-    if (!QMetaObjectPrivate::connect(sender, signal_index, receiver, method_index, type, types))
+    if (!QMetaObjectPrivate::connect(sender, signal_index, receiver, method_index, 0, type, types))
         return false;
 
     const_cast<QObject*>(sender)->connectNotify(signalSignature.constData());
@@ -3157,18 +3160,28 @@ bool QMetaObject::connect(const QObject *sender, int signal_index,
 {
     signal_index = methodIndexToSignalIndex(sender->metaObject(), signal_index);
     return QMetaObjectPrivate::connect(sender, signal_index,
-                                       receiver, method_index, type, types);
+                                       receiver, method_index,
+                                       0, //FIXME, we could speed this connection up by computing the relative index
+                                       type, types);
 }
 
 /*! \internal
    Same as the QMetaObject::connect, but \a signal_index must be the result of QObjectPrivate::signalIndex
+
+    method_index is relative to the rmeta metaobject, if rmeta is null, then it is absolute index
  */
 bool QMetaObjectPrivate::connect(const QObject *sender, int signal_index,
-                                 const QObject *receiver, int method_index, int type, int *types)
+                                 const QObject *receiver, int method_index,
+                                 const QMetaObject *rmeta, int type, int *types)
 {
     QObject *s = const_cast<QObject *>(sender);
     QObject *r = const_cast<QObject *>(receiver);
 
+    int method_offset = rmeta ? rmeta->methodOffset() : 0;
+    QObjectPrivate::StaticMetaCallFunction callFunction =
+        (rmeta && QMetaObjectPrivate::get(rmeta)->revision >= 6 && rmeta->d.extradata)
+        ? reinterpret_cast<const QMetaObjectExtraData *>(rmeta->d.extradata)->static_metacall : 0;
+
     QOrderedMutexLocker locker(signalSlotLock(sender),
                                signalSlotLock(receiver));
 
@@ -3178,8 +3191,10 @@ bool QMetaObjectPrivate::connect(const QObject *sender, int signal_index,
             const QObjectPrivate::Connection *c2 =
                 (*connectionLists)[signal_index].first;
 
+            int method_index_absolute = method_index + method_offset;
+
             while (c2) {
-                if (c2->receiver == receiver && c2->method == method_index)
+                if (c2->receiver == receiver && c2->method() == method_index_absolute)
                     return false;
                 c2 = c2->nextConnectionList;
             }
@@ -3190,10 +3205,12 @@ bool QMetaObjectPrivate::connect(const QObject *sender, int signal_index,
     QObjectPrivate::Connection *c = new QObjectPrivate::Connection;
     c->sender = s;
     c->receiver = r;
-    c->method = method_index;
+    c->method_relative = method_index;
+    c->method_offset = method_offset;
     c->connectionType = type;
     c->argumentTypes = types;
     c->nextConnectionList = 0;
+    c->callFunction = callFunction;
 
     QT_TRY {
         QObjectPrivate::get(s)->addConnection(signal_index, c);
@@ -3254,7 +3271,7 @@ bool QMetaObjectPrivate::disconnectHelper(QObjectPrivate::Connection *c,
     while (c) {
         if (c->receiver
             && (receiver == 0 || (c->receiver == receiver
-                           && (method_index < 0 || c->method == method_index)))) {
+                           && (method_index < 0 || c->method() == method_index)))) {
             bool needToUnlock = false;
             QMutex *receiverMutex = 0;
             if (!receiver) {
@@ -3428,7 +3445,7 @@ static void queued_activate(QObject *sender, int signal, QObjectPrivate::Connect
     args[0] = 0; // return value
     for (int n = 1; n < nargs; ++n)
         args[n] = QMetaType::construct((types[n] = c->argumentTypes[n-1]), argv[n]);
-    QCoreApplication::postEvent(c->receiver, new QMetaCallEvent(c->method,
+    QCoreApplication::postEvent(c->receiver, new QMetaCallEvent(c->method(),
                                                                sender,
                                                                signal,
                                                                nargs,
@@ -3503,7 +3520,6 @@ void QMetaObject::activate(QObject *sender, const QMetaObject *m, int local_sign
                 continue;
 
             QObject * const receiver = c->receiver;
-            const int method = c->method;
             const bool receiverInSameThread = currentThreadId == receiver->d_func()->threadData->threadId;
 
             // determine if this connection should be sent immediately or
@@ -3514,6 +3530,7 @@ void QMetaObject::activate(QObject *sender, const QMetaObject *m, int local_sign
                 continue;
 #ifndef QT_NO_THREAD
             } else if (c->connectionType == Qt::BlockingQueuedConnection) {
+                const int method = c->method();
                 locker.unlock();
                 if (receiverInSameThread) {
                     qWarning("Qt: Dead lock detected while activating a BlockingQueuedConnection: "
@@ -3532,6 +3549,7 @@ void QMetaObject::activate(QObject *sender, const QMetaObject *m, int local_sign
                 continue;
 #endif
             }
+
             QObjectPrivate::Sender currentSender;
             QObjectPrivate::Sender *previousSender = 0;
             if (receiverInSameThread) {
@@ -3540,36 +3558,52 @@ void QMetaObject::activate(QObject *sender, const QMetaObject *m, int local_sign
                 currentSender.ref = 1;
                 previousSender = QObjectPrivate::setCurrentSender(receiver, &currentSender);
             }
-            locker.unlock();
+            const QObjectPrivate::StaticMetaCallFunction callFunction = c->callFunction;
+            const int method_relative = c->method_relative;
+            if (callFunction && c->method_offset <= receiver->metaObject()->methodOffset()) {
+                //we compare the vtable to make sure we are not in the destructor of the object.
+                locker.unlock();
+                if (qt_signal_spy_callback_set.slot_begin_callback != 0)
+                    qt_signal_spy_callback_set.slot_begin_callback(receiver, c->method(), argv ? argv : empty_argv);
 
-            if (qt_signal_spy_callback_set.slot_begin_callback != 0) {
-                qt_signal_spy_callback_set.slot_begin_callback(receiver,
-                                                               method,
-                                                               argv ? argv : empty_argv);
-            }
+                callFunction(receiver, QMetaObject::InvokeMetaMethod, method_relative, argv ? argv : empty_argv);
 
-#if defined(QT_NO_EXCEPTIONS)
-            metacall(receiver, QMetaObject::InvokeMetaMethod, method, argv ? argv : empty_argv);
-#else
-            QT_TRY {
-                metacall(receiver, QMetaObject::InvokeMetaMethod, method, argv ? argv : empty_argv);
-            } QT_CATCH(...) {
+                if (qt_signal_spy_callback_set.slot_end_callback != 0)
+                    qt_signal_spy_callback_set.slot_end_callback(receiver, c->method());
                 locker.relock();
-                if (receiverInSameThread)
-                    QObjectPrivate::resetCurrentSender(receiver, &currentSender, previousSender);
+            } else {
+                const int method = method_relative + c->method_offset;
+                locker.unlock();
 
-                --connectionLists->inUse;
-                Q_ASSERT(connectionLists->inUse >= 0);
-                if (connectionLists->orphaned && !connectionLists->inUse)
-                    delete connectionLists;
-                QT_RETHROW;
-            }
+                if (qt_signal_spy_callback_set.slot_begin_callback != 0) {
+                    qt_signal_spy_callback_set.slot_begin_callback(receiver,
+                                                                method,
+                                                                argv ? argv : empty_argv);
+                }
+
+#if defined(QT_NO_EXCEPTIONS)
+                metacall(receiver, QMetaObject::InvokeMetaMethod, method, argv ? argv : empty_argv);
+#else
+                QT_TRY {
+                    metacall(receiver, QMetaObject::InvokeMetaMethod, method, argv ? argv : empty_argv);
+                } QT_CATCH(...) {
+                    locker.relock();
+                    if (receiverInSameThread)
+                        QObjectPrivate::resetCurrentSender(receiver, &currentSender, previousSender);
+
+                    --connectionLists->inUse;
+                    Q_ASSERT(connectionLists->inUse >= 0);
+                    if (connectionLists->orphaned && !connectionLists->inUse)
+                        delete connectionLists;
+                    QT_RETHROW;
+                }
 #endif
 
-            if (qt_signal_spy_callback_set.slot_end_callback != 0)
-                qt_signal_spy_callback_set.slot_end_callback(receiver, method);
+                if (qt_signal_spy_callback_set.slot_end_callback != 0)
+                    qt_signal_spy_callback_set.slot_end_callback(receiver, method);
 
-            locker.relock();
+                locker.relock();
+            }
 
             if (receiverInSameThread)
                 QObjectPrivate::resetCurrentSender(receiver, &currentSender, previousSender);
@@ -3870,7 +3904,7 @@ void QObject::dumpObjectInfo()
                     continue;
                 }
                 const QMetaObject *receiverMetaObject = c->receiver->metaObject();
-                const QMetaMethod method = receiverMetaObject->method(c->method);
+                const QMetaMethod method = receiverMetaObject->method(c->method());
                 qDebug("          --> %s::%s %s",
                        receiverMetaObject->className(),
                        c->receiver->objectName().isEmpty() ? "unnamed" : qPrintable(c->receiver->objectName()),
@@ -3887,7 +3921,7 @@ void QObject::dumpObjectInfo()
 
     if (d->senders) {
         for (QObjectPrivate::Connection *s = d->senders; s; s = s->next) {
-            const QMetaMethod slot = metaObject()->method(s->method);
+            const QMetaMethod slot = metaObject()->method(s->method());
             qDebug("          <-- %s::%s  %s",
                    s->sender->metaObject()->className(),
                    s->sender->objectName().isEmpty() ? "unnamed" : qPrintable(s->sender->objectName()),
diff --git a/src/corelib/kernel/qobject_p.h b/src/corelib/kernel/qobject_p.h
index c7555be..71b5bee 100644
--- a/src/corelib/kernel/qobject_p.h
+++ b/src/corelib/kernel/qobject_p.h
@@ -108,19 +108,23 @@ public:
         QList<QVariant> propertyValues;
     };
 
+    typedef void (*StaticMetaCallFunction)(QObject *, QMetaObject::Call, int, void **);
     struct Connection
     {
         QObject *sender;
         QObject *receiver;
-        int method;
-        uint connectionType : 3; // 0 == auto, 1 == direct, 2 == queued, 4 == blocking
-        QBasicAtomicPointer<int> argumentTypes;
+        StaticMetaCallFunction callFunction;
         // The next pointer for the singly-linked ConnectionList
         Connection *nextConnectionList;
         //senders linked list
         Connection *next;
         Connection **prev;
+        QBasicAtomicPointer<int> argumentTypes;
+        ushort method_offset;
+        ushort method_relative;
+        ushort connectionType : 3; // 0 == auto, 1 == direct, 2 == queued, 4 == blocking
         ~Connection();
+        int method() const { return method_offset + method_relative; }
     };
     // ConnectionList is a singly-linked list
     struct ConnectionList {
diff --git a/src/corelib/kernel/qobjectdefs.h b/src/corelib/kernel/qobjectdefs.h
index 54b5ab2..6bf40f7 100644
--- a/src/corelib/kernel/qobjectdefs.h
+++ b/src/corelib/kernel/qobjectdefs.h
@@ -55,7 +55,7 @@ class QByteArray;
 class QString;
 
 #ifndef Q_MOC_OUTPUT_REVISION
-#define Q_MOC_OUTPUT_REVISION 62
+#define Q_MOC_OUTPUT_REVISION 63
 #endif
 
 // The following macros are our "extensions" to C++
@@ -163,6 +163,7 @@ public: \
     virtual void *qt_metacast(const char *); \
     QT_TR_FUNCTIONS \
     virtual int qt_metacall(QMetaObject::Call, int, void **); \
+    static void qt_static_metacall(QObject *, QMetaObject::Call, int, void **); \
 private:
 /* tmake ignore Q_OBJECT */
 #define Q_OBJECT_FAKE Q_OBJECT
@@ -468,7 +469,6 @@ struct Q_CORE_EXPORT QMetaObject
         const uint *data;
         const void *extradata;
     } d;
-
 };
 
 typedef const QMetaObject& (*QMetaObjectAccessor)();
@@ -480,7 +480,8 @@ struct QMetaObjectExtraData
 #else
     const QMetaObject **objects;
 #endif
-    int (*static_metacall)(QMetaObject::Call, int, void **);
+    void (*static_metacall)(QObject *, QMetaObject::Call, int, void **); //from revision 6
+    //int (*static_metacall)(QMetaObject::Call, int, void **); //used from revison 2 until revison 5
 };
 
 inline const char *QMetaObject::className() const
diff --git a/src/tools/moc/generator.cpp b/src/tools/moc/generator.cpp
index 4df7ae5..ac769d7 100644
--- a/src/tools/moc/generator.cpp
+++ b/src/tools/moc/generator.cpp
@@ -173,7 +173,7 @@ void Generator::generateCode()
     int index = 14;
     fprintf(out, "static const uint qt_meta_data_%s[] = {\n", qualifiedClassNameIdentifier.constData());
     fprintf(out, "\n // content:\n");
-    fprintf(out, "    %4d,       // revision\n", 5);
+    fprintf(out, "    %4d,       // revision\n", 6);
     fprintf(out, "    %4d,       // classname\n", strreg(cdef->qualified));
     fprintf(out, "    %4d, %4d, // classinfo\n", cdef->classInfoList.count(), cdef->classInfoList.count() ? index : 0);
     index += cdef->classInfoList.count() * 2;
@@ -291,12 +291,11 @@ void Generator::generateCode()
     }
     fprintf(out, "\"\n};\n\n");
 
-
 //
 // Generate internal qt_static_metacall() function
 //
-    if (isConstructible)
-        generateStaticMetacall(qualifiedClassNameIdentifier);
+    if (cdef->hasQObject && !isQt)
+        generateStaticMetacall();
 
 //
 // Build extra array
@@ -329,17 +328,19 @@ void Generator::generateCode()
         fprintf(out, "    0\n};\n\n");
     }
 
-    if (isConstructible || !extraList.isEmpty()) {
+    bool hasExtraData = (cdef->hasQObject && !isQt) || !extraList.isEmpty();
+    if (hasExtraData) {
         fprintf(out, "static const QMetaObjectExtraData qt_meta_extradata2_%s = {\n    ",
                 qualifiedClassNameIdentifier.constData());
         if (extraList.isEmpty())
             fprintf(out, "0, ");
         else
             fprintf(out, "qt_meta_extradata_%s, ", qualifiedClassNameIdentifier.constData());
-        if (!isConstructible)
-            fprintf(out, "0");
+
+        if (cdef->hasQObject && !isQt)
+            fprintf(out, " %s::qt_static_metacall", cdef->qualified.constData());
         else
-            fprintf(out, "%s_qt_static_metacall", qualifiedClassNameIdentifier.constData());
+            fprintf(out, " 0");
         fprintf(out, " \n};\n\n");
     }
 
@@ -359,7 +360,7 @@ void Generator::generateCode()
         fprintf(out, "    { 0, ");
     fprintf(out, "qt_meta_stringdata_%s,\n      qt_meta_data_%s, ",
              qualifiedClassNameIdentifier.constData(), qualifiedClassNameIdentifier.constData());
-    if (!isConstructible && extraList.isEmpty())
+    if (!hasExtraData)
         fprintf(out, "0 }\n");
     else
         fprintf(out, "&qt_meta_extradata2_%s }\n", qualifiedClassNameIdentifier.constData());
@@ -657,34 +658,11 @@ void Generator::generateMetacall()
 
     if (methodList.size()) {
         needElse = true;
-        fprintf(out, "if (_c == QMetaObject::InvokeMetaMethod) {\n        ");
-        fprintf(out, "switch (_id) {\n");
-        for (int methodindex = 0; methodindex < methodList.size(); ++methodindex) {
-            const FunctionDef &f = methodList.at(methodindex);
-            fprintf(out, "        case %d: ", methodindex);
-            if (f.normalizedType.size())
-                fprintf(out, "{ %s _r = ", noRef(f.normalizedType).constData());
-            if (f.inPrivateClass.size())
-                fprintf(out, "%s->", f.inPrivateClass.constData());
-            fprintf(out, "%s(", f.name.constData());
-            int offset = 1;
-            for (int j = 0; j < f.arguments.count(); ++j) {
-                const ArgumentDef &a = f.arguments.at(j);
-                if (j)
-                    fprintf(out, ",");
-                fprintf(out, "(*reinterpret_cast< %s>(_a[%d]))",a.typeNameForCast.constData(), offset++);
-            }
-            fprintf(out, ");");
-            if (f.normalizedType.size())
-                fprintf(out, "\n            if (_a[0]) *reinterpret_cast< %s*>(_a[0]) = _r; } ",
-                        noRef(f.normalizedType).constData());
-            fprintf(out, " break;\n");
-        }
-        fprintf(out, "        default: ;\n");
-        fprintf(out, "        }\n");
-    }
-    if (methodList.size())
+        fprintf(out, "if (_c == QMetaObject::InvokeMetaMethod) {\n");
+        fprintf(out, "        if (_id < %d)\n", methodList.size());
+        fprintf(out, "            qt_static_metacall(this, _c, _id, _a);\n");
         fprintf(out, "        _id -= %d;\n    }", methodList.size());
+    }
 
     if (cdef->propertyList.size()) {
         bool needGet = false;
@@ -900,40 +878,95 @@ void Generator::generateMetacall()
     fprintf(out,"return _id;\n}\n");
 }
 
-void Generator::generateStaticMetacall(const QByteArray &prefix)
+void Generator::generateStaticMetacall()
 {
-    bool isQObject = (cdef->classname == "QObject");
+    fprintf(out, "void %s::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a)\n{\n",
+            cdef->qualified.constData());
 
-    fprintf(out, "static int %s_qt_static_metacall(QMetaObject::Call _c, int _id, void **_a)\n{\n",
-            prefix.constData());
+    bool needElse = false;
+    bool isUsed_a = false;
+
+    if (!cdef->constructorList.isEmpty()) {
+        fprintf(out, "    if (_c == QMetaObject::CreateInstance) {\n");
+        fprintf(out, "        switch (_id) {\n");
+        for (int ctorindex = 0; ctorindex < cdef->constructorList.count(); ++ctorindex) {
+            fprintf(out, "        case %d: { %s *_r = new %s(", ctorindex,
+                    cdef->classname.constData(), cdef->classname.constData());
+            const FunctionDef &f = cdef->constructorList.at(ctorindex);
+            int offset = 1;
+            for (int j = 0; j < f.arguments.count(); ++j) {
+                const ArgumentDef &a = f.arguments.at(j);
+                if (j)
+                    fprintf(out, ",");
+                fprintf(out, "(*reinterpret_cast< %s>(_a[%d]))", a.typeNameForCast.constData(), offset++);
+            }
+            fprintf(out, ");\n");
+            fprintf(out, "            if (_a[0]) *reinterpret_cast<QObject**>(_a[0]) = _r; } break;\n");
+        }
+        fprintf(out, "        }\n");
+        fprintf(out, "    }");
+        needElse = true;
+        isUsed_a = true;
+    }
 
-    fprintf(out, "    if (_c == QMetaObject::CreateInstance) {\n");
-    fprintf(out, "        switch (_id) {\n");
-    for (int ctorindex = 0; ctorindex < cdef->constructorList.count(); ++ctorindex) {
-        fprintf(out, "        case %d: { %s *_r = new %s(", ctorindex,
-                cdef->qualified.constData(), cdef->qualified.constData());
-        const FunctionDef &f = cdef->constructorList.at(ctorindex);
-        int offset = 1;
-        for (int j = 0; j < f.arguments.count(); ++j) {
-            const ArgumentDef &a = f.arguments.at(j);
-            if (j)
-                fprintf(out, ",");
-            fprintf(out, "(*reinterpret_cast< %s>(_a[%d]))", a.typeNameForCast.constData(), offset++);
+    QList<FunctionDef> methodList;
+    methodList += cdef->signalList;
+    methodList += cdef->slotList;
+    methodList += cdef->methodList;
+
+    if (!methodList.isEmpty()) {
+        if (needElse)
+            fprintf(out, " else ");
+        else
+            fprintf(out, "    ");
+        fprintf(out, "if (_c == QMetaObject::InvokeMetaMethod) {\n");
+        fprintf(out, "        Q_ASSERT(qobject_cast<%s *>(_o));\n", cdef->classname.constData());
+        fprintf(out, "        %s *_t = static_cast<%s *>(_o);\n", cdef->classname.constData(), cdef->classname.constData());
+        fprintf(out, "        switch (_id) {\n");
+        for (int methodindex = 0; methodindex < methodList.size(); ++methodindex) {
+            const FunctionDef &f = methodList.at(methodindex);
+            fprintf(out, "        case %d: ", methodindex);
+            if (f.normalizedType.size())
+                fprintf(out, "{ %s _r = ", noRef(f.normalizedType).constData());
+            fprintf(out, "_t->");
+            if (f.inPrivateClass.size())
+                fprintf(out, "%s->", f.inPrivateClass.constData());
+            fprintf(out, "%s(", f.name.constData());
+            int offset = 1;
+            for (int j = 0; j < f.arguments.count(); ++j) {
+                const ArgumentDef &a = f.arguments.at(j);
+                if (j)
+                    fprintf(out, ",");
+                fprintf(out, "(*reinterpret_cast< %s>(_a[%d]))",a.typeNameForCast.constData(), offset++);
+                isUsed_a = true;
+            }
+            fprintf(out, ");");
+            if (f.normalizedType.size()) {
+                fprintf(out, "\n            if (_a[0]) *reinterpret_cast< %s*>(_a[0]) = _r; } ",
+                        noRef(f.normalizedType).constData());
+                isUsed_a = true;
+            }
+            fprintf(out, " break;\n");
         }
-        fprintf(out, ");\n");
-        fprintf(out, "            if (_a[0]) *reinterpret_cast<QObject**>(_a[0]) = _r; } break;\n");
+        fprintf(out, "        default: ;\n");
+        fprintf(out, "        }\n");
+        fprintf(out, "    }");
+        needElse = true;
     }
-    fprintf(out, "        }\n");
-    fprintf(out, "        _id -= %d;\n", cdef->constructorList.count());
-    fprintf(out, "        return _id;\n");
-    fprintf(out, "    }\n");
 
-    if (!isQObject)
-        fprintf(out, "    _id = %s::staticMetaObject.superClass()->static_metacall(_c, _id, _a);\n", cdef->qualified.constData());
+    if (needElse)
+        fprintf(out, "\n");
 
-    fprintf(out, "    if (_id < 0)\n        return _id;\n");
+    if (methodList.isEmpty()) {
+        fprintf(out, "    Q_UNUSED(_o);\n");
+        if (cdef->constructorList.isEmpty()) {
+            fprintf(out, "    Q_UNUSED(_id);\n");
+            fprintf(out, "    Q_UNUSED(_c);\n");
+        }
+    }
+    if (!isUsed_a)
+        fprintf(out, "    Q_UNUSED(_a);\n");
 
-    fprintf(out, "    return _id;\n");
     fprintf(out, "}\n\n");
 }
 
diff --git a/src/tools/moc/generator.h b/src/tools/moc/generator.h
index ed0980e..fa5885f 100644
--- a/src/tools/moc/generator.h
+++ b/src/tools/moc/generator.h
@@ -62,7 +62,7 @@ private:
     void generateEnums(int index);
     void generateProperties();
     void generateMetacall();
-    void generateStaticMetacall(const QByteArray &prefix);
+    void generateStaticMetacall();
     void generateSignal(FunctionDef *def, int index);
 
     // used by binary QMetaObject generator
diff --git a/src/tools/moc/moc.cpp b/src/tools/moc/moc.cpp
index 74b1ace..5078b28 100644
--- a/src/tools/moc/moc.cpp
+++ b/src/tools/moc/moc.cpp
@@ -356,8 +356,9 @@ bool Moc::testFunctionRevision(FunctionDef *def)
 bool Moc::parseFunction(FunctionDef *def, bool inMacro)
 {
     def->isVirtual = false;
+    def->isStatic = false;
     //skip modifiers and attributes
-    while (test(INLINE) || test(STATIC) ||
+    while (test(INLINE) || (test(STATIC) && (def->isStatic = true)) ||
         (test(VIRTUAL) && (def->isVirtual = true)) //mark as virtual
         || testFunctionAttribute(def) || testFunctionRevision(def)) {}
     bool templateFunction = (lookup() == TEMPLATE);
@@ -447,8 +448,9 @@ bool Moc::parseFunction(FunctionDef *def, bool inMacro)
 bool Moc::parseMaybeFunction(const ClassDef *cdef, FunctionDef *def)
 {
     def->isVirtual = false;
+    def->isStatic = false;
     //skip modifiers and attributes
-    while (test(EXPLICIT) || test(INLINE) || test(STATIC) ||
+    while (test(EXPLICIT) || test(INLINE) || (test(STATIC) && (def->isStatic = true)) ||
         (test(VIRTUAL) && (def->isVirtual = true)) //mark as virtual
         || testFunctionAttribute(def) || testFunctionRevision(def)) {}
     bool tilde = test(TILDE);
diff --git a/src/tools/moc/moc.h b/src/tools/moc/moc.h
index 38c3917..4049534 100644
--- a/src/tools/moc/moc.h
+++ b/src/tools/moc/moc.h
@@ -83,7 +83,7 @@ struct ArgumentDef
 
 struct FunctionDef
 {
-    FunctionDef(): returnTypeIsVolatile(false), access(Private), isConst(false), isVirtual(false),
+    FunctionDef(): returnTypeIsVolatile(false), access(Private), isConst(false), isVirtual(false), isStatic(false),
                    inlineCode(false), wasCloned(false), isCompat(false), isInvokable(false),
                    isScriptable(false), isSlot(false), isSignal(false),
                    isConstructor(false), isDestructor(false), isAbstract(false), revision(0) {}
@@ -99,6 +99,7 @@ struct FunctionDef
     Access access;
     bool isConst;
     bool isVirtual;
+    bool isStatic;
     bool inlineCode;
     bool wasCloned;
 
diff --git a/src/tools/moc/outputrevision.h b/src/tools/moc/outputrevision.h
index 7e2ca8b..104a373 100644
--- a/src/tools/moc/outputrevision.h
+++ b/src/tools/moc/outputrevision.h
@@ -43,6 +43,6 @@
 #define OUTPUTREVISION_H
 
 // if the output revision changes, you MUST change it in qobjectdefs.h too
-enum { mocOutputRevision = 62 };          // moc format output revision
+enum { mocOutputRevision = 63 };          // moc format output revision
 
 #endif // OUTPUTREVISION_H
-- 
cgit v0.12