From ee709e32366135fb7507b74b8e75d637772b166e Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Tue, 30 Apr 2019 09:55:13 +0200 Subject: QMetaMethod: clean up offset handling Centralize the offset handling in one place and avoid lots of magic numbers in various places. Expose the number of ints per method in QMetaObjectPrivate as a constant, so that code in other places can access it via private API. Change-Id: I59790287a17ea47e6160ec65d9c8d0aaee748947 Reviewed-by: Simon Hausmann Reviewed-by: Ulf Hermann Reviewed-by: Lars Knoll --- src/corelib/kernel/qmetaobject.cpp | 99 +++++++++++++++++++++++--------------- src/corelib/kernel/qmetaobject.h | 23 +++++++-- src/corelib/kernel/qmetaobject_p.h | 3 +- src/corelib/kernel/qobject.cpp | 6 +-- src/corelib/kernel/qobjectdefs.h | 2 +- 5 files changed, 86 insertions(+), 47 deletions(-) diff --git a/src/corelib/kernel/qmetaobject.cpp b/src/corelib/kernel/qmetaobject.cpp index 3e05cc71d2..ef8cf1857c 100644 --- a/src/corelib/kernel/qmetaobject.cpp +++ b/src/corelib/kernel/qmetaobject.cpp @@ -884,20 +884,19 @@ int QMetaObjectPrivate::signalIndex(const QMetaMethod &m) */ QMetaMethod QMetaObjectPrivate::signal(const QMetaObject *m, int signal_index) { - QMetaMethod result; if (signal_index < 0) - return result; + return QMetaMethod(); + Q_ASSERT(m != nullptr); int i = signal_index; i -= signalOffset(m); if (i < 0 && m->d.superdata) return signal(m->d.superdata, signal_index); - if (i >= 0 && i < priv(m->d.data)->signalCount) { - result.mobj = m; - result.handle = priv(m->d.data)->methodData + QMetaObjectPrivate::IntsPerMethod*i; - } - return result; + + if (i >= 0 && i < priv(m->d.data)->signalCount) + return QMetaMethod::fromRelativeMethodIndex(m, i); + return QMetaMethod(); } /*! @@ -1074,13 +1073,9 @@ int QMetaObject::indexOfClassInfo(const char *name) const QMetaMethod QMetaObject::constructor(int index) const { int i = index; - QMetaMethod result; - Q_ASSERT(priv(d.data)->revision >= 2); - if (i >= 0 && i < priv(d.data)->constructorCount) { - result.mobj = this; - result.handle = priv(d.data)->constructorData + QMetaObjectPrivate::IntsPerMethod*i; - } - return result; + if (i >= 0 && i < priv(d.data)->constructorCount) + return QMetaMethod::fromRelativeConstructorIndex(this, i); + return QMetaMethod(); } /*! @@ -1095,12 +1090,9 @@ QMetaMethod QMetaObject::method(int index) const if (i < 0 && d.superdata) return d.superdata->method(index); - QMetaMethod result; - if (i >= 0 && i < priv(d.data)->methodCount) { - result.mobj = this; - result.handle = priv(d.data)->methodData + QMetaObjectPrivate::IntsPerMethod*i; - } - return result; + if (i >= 0 && i < priv(d.data)->methodCount) + return QMetaMethod::fromRelativeMethodIndex(this, i); + return QMetaMethod(); } /*! @@ -1724,6 +1716,27 @@ bool QMetaObject::invokeMethodImpl(QObject *object, QtPrivate::QSlotObjectBase * \internal */ +/*! + \internal +*/ +QMetaMethod QMetaMethod::fromRelativeMethodIndex(const QMetaObject *mobj, int index) +{ + Q_ASSERT(index >= 0 && index < priv(mobj->d.data)->methodCount); + QMetaMethod m; + m.mobj = mobj; + m.data = { mobj->d.data + priv(mobj->d.data)->methodData + index * Data::Size }; + return m; +} + +QMetaMethod QMetaMethod::fromRelativeConstructorIndex(const QMetaObject *mobj, int index) +{ + Q_ASSERT(index >= 0 && index < priv(mobj->d.data)->constructorCount); + QMetaMethod m; + m.mobj = mobj; + m.data = { mobj->d.data + priv(mobj->d.data)->constructorData + index * Data::Size }; + return m; +} + /*! \macro Q_METAMETHOD_INVOKE_MAX_ARGS \relates QMetaMethod @@ -1752,13 +1765,13 @@ QByteArray QMetaMethodPrivate::signature() const QByteArray QMetaMethodPrivate::name() const { Q_ASSERT(priv(mobj->d.data)->revision >= 7); - return stringData(mobj, mobj->d.data[handle]); + return stringData(mobj, data.name()); } int QMetaMethodPrivate::typesDataIndex() const { Q_ASSERT(priv(mobj->d.data)->revision >= 7); - return mobj->d.data[handle + 2]; + return data.parameters(); } const char *QMetaMethodPrivate::rawReturnTypeName() const @@ -1779,7 +1792,7 @@ int QMetaMethodPrivate::returnType() const int QMetaMethodPrivate::parameterCount() const { Q_ASSERT(priv(mobj->d.data)->revision >= 7); - return mobj->d.data[handle + 1]; + return data.argc(); } int QMetaMethodPrivate::parametersDataIndex() const @@ -1838,13 +1851,13 @@ QList QMetaMethodPrivate::parameterNames() const QByteArray QMetaMethodPrivate::tag() const { Q_ASSERT(priv(mobj->d.data)->revision >= 7); - return stringData(mobj, mobj->d.data[handle + 3]); + return stringData(mobj, data.tag()); } int QMetaMethodPrivate::ownMethodIndex() const { // recompute the methodIndex by reversing the arithmetic in QMetaObject::property() - return (handle - priv(mobj->d.data)->methodData) / QMetaObjectPrivate::IntsPerMethod; + return ( data.d - mobj->d.data - priv(mobj->d.data)->methodData)/Data::Size; } /*! @@ -1903,7 +1916,7 @@ QMetaType QMetaMethod::returnMetaType() const { if (!mobj || methodType() == QMetaMethod::Constructor) return QMetaType{}; - auto mt = QMetaType(mobj->d.metaTypes[mobj->d.data[handle + 5]]); + auto mt = QMetaType(mobj->d.metaTypes[data.metaTypeOffset()]); if (mt.id() == QMetaType::UnknownType) return QMetaType(QMetaMethodPrivate::get(this)->returnType()); else @@ -1958,7 +1971,7 @@ QMetaType QMetaMethod::parameterMetaType(int index) const return {}; // + 1 if there exists a return type auto parameterOffset = index + (methodType() == QMetaMethod::Constructor ? 0 : 1); - auto mt = QMetaType(mobj->d.metaTypes[mobj->d.data[handle + 5] + parameterOffset]); + auto mt = QMetaType(mobj->d.metaTypes[data.metaTypeOffset() + parameterOffset]); if (mt.id() == QMetaType::UnknownType) return QMetaType(QMetaMethodPrivate::get(this)->parameterType(index)); else @@ -2058,7 +2071,7 @@ int QMetaMethod::attributes() const { if (!mobj) return false; - return ((mobj->d.data[handle + 4])>>4); + return data.flags() >> 4; } /*! @@ -2073,6 +2086,18 @@ int QMetaMethod::methodIndex() const return QMetaMethodPrivate::get(this)->ownMethodIndex() + mobj->methodOffset(); } +/*! + \since 6.0 + + Returns this method's local index inside. +*/ +int QMetaMethod::relativeMethodIndex() const +{ + if (!mobj) + return -1; + return QMetaMethodPrivate::get(this)->ownMethodIndex(); +} + // This method has been around for a while, but the documentation was marked \internal until 5.1 /*! \since 5.1 @@ -2083,9 +2108,9 @@ int QMetaMethod::revision() const { if (!mobj) return 0; - if ((QMetaMethod::Access)(mobj->d.data[handle + 4] & MethodRevisioned)) { + if (data.flags() & MethodRevisioned) { int offset = priv(mobj->d.data)->methodData - + priv(mobj->d.data)->methodCount * QMetaObjectPrivate::IntsPerMethod + + priv(mobj->d.data)->methodCount * Data::Size + QMetaMethodPrivate::get(this)->ownMethodIndex(); return mobj->d.data[offset]; } @@ -2106,7 +2131,7 @@ QMetaMethod::Access QMetaMethod::access() const { if (!mobj) return Private; - return (QMetaMethod::Access)(mobj->d.data[handle + 4] & AccessMask); + return (QMetaMethod::Access)(data.flags() & AccessMask); } /*! @@ -2118,7 +2143,7 @@ QMetaMethod::MethodType QMetaMethod::methodType() const { if (!mobj) return QMetaMethod::Method; - return (QMetaMethod::MethodType)((mobj->d.data[handle + 4] & MethodTypeMask)>>2); + return (QMetaMethod::MethodType)((data.flags() & MethodTypeMask)>>2); } /*! @@ -2145,16 +2170,12 @@ QMetaMethod QMetaMethod::fromSignalImpl(const QMetaObject *metaObject, void **si { int i = -1; void *args[] = { &i, signal }; - QMetaMethod result; for (const QMetaObject *m = metaObject; m; m = m->d.superdata) { m->static_metacall(QMetaObject::IndexOfMethod, 0, args); - if (i >= 0) { - result.mobj = m; - result.handle = priv(m->d.data)->methodData + QMetaObjectPrivate::IntsPerMethod*i; - break; - } + if (i >= 0) + return QMetaMethod::fromRelativeMethodIndex(m, i); } - return result; + return QMetaMethod(); } /*! diff --git a/src/corelib/kernel/qmetaobject.h b/src/corelib/kernel/qmetaobject.h index 67f5efe6f6..801cf8f6eb 100644 --- a/src/corelib/kernel/qmetaobject.h +++ b/src/corelib/kernel/qmetaobject.h @@ -51,7 +51,7 @@ QT_BEGIN_NAMESPACE class Q_CORE_EXPORT QMetaMethod { public: - Q_DECL_CONSTEXPR inline QMetaMethod() : mobj(nullptr), handle(0) {} + Q_DECL_CONSTEXPR inline QMetaMethod() : mobj(nullptr), data({ nullptr }) {} QByteArray methodSignature() const; QByteArray name() const; @@ -72,6 +72,7 @@ public: enum Attributes { Compatibility = 0x1, Cloned = 0x2, Scriptable = 0x4 }; int attributes() const; int methodIndex() const; + int relativeMethodIndex() const; int revision() const; inline const QMetaObject *enclosingMetaObject() const { return mobj; } @@ -184,9 +185,25 @@ private: char *signature(struct renamedInQt5_warning_checkTheLifeTime * = nullptr) = delete; #endif static QMetaMethod fromSignalImpl(const QMetaObject *, void **); + static QMetaMethod fromRelativeMethodIndex(const QMetaObject *mobj, int index); + static QMetaMethod fromRelativeConstructorIndex(const QMetaObject *mobj, int index); + + struct Data { + enum { Size = 6 }; + + uint name() const { return d[0]; } + uint argc() const { return d[1]; } + uint parameters() const { return d[2]; } + uint tag() const { return d[3]; } + uint flags() const { return d[4]; } + uint metaTypeOffset() const { return d[5]; } + bool operator==(const Data &other) const { return d == other.d; } + + const uint *d; + }; const QMetaObject *mobj; - uint handle; + Data data; friend class QMetaMethodPrivate; friend struct QMetaObject; friend struct QMetaObjectPrivate; @@ -197,7 +214,7 @@ private: Q_DECLARE_TYPEINFO(QMetaMethod, Q_MOVABLE_TYPE); inline bool operator==(const QMetaMethod &m1, const QMetaMethod &m2) -{ return m1.mobj == m2.mobj && m1.handle == m2.handle; } +{ return m1.data == m2.data; } inline bool operator!=(const QMetaMethod &m1, const QMetaMethod &m2) { return !(m1 == m2); } diff --git a/src/corelib/kernel/qmetaobject_p.h b/src/corelib/kernel/qmetaobject_p.h index b825c983f9..1e5bc06ffe 100644 --- a/src/corelib/kernel/qmetaobject_p.h +++ b/src/corelib/kernel/qmetaobject_p.h @@ -55,6 +55,7 @@ #include #include #include +#include #ifndef QT_NO_QOBJECT #include // For QObjectPrivate::Connection #endif @@ -178,7 +179,7 @@ struct QMetaObjectPrivate // revision 8 is Qt 5.12: It adds the enum name to QMetaEnum // revision 9 is Qt 6.0: It adds the metatype of properties and methods enum { OutputRevision = 9 }; // Used by moc, qmetaobjectbuilder and qdbus - enum { IntsPerMethod = 6}; + enum { IntsPerMethod = QMetaMethod::Data::Size}; int revision; int className; diff --git a/src/corelib/kernel/qobject.cpp b/src/corelib/kernel/qobject.cpp index 11ec534434..615bc63f1d 100644 --- a/src/corelib/kernel/qobject.cpp +++ b/src/corelib/kernel/qobject.cpp @@ -2562,9 +2562,9 @@ bool QObject::isSignalConnected(const QMetaMethod &signal) const Q_ASSERT_X(signal.mobj->cast(this) && signal.methodType() == QMetaMethod::Signal, "QObject::isSignalConnected" , "the parameter must be a signal member of the object"); - uint signalIndex = (signal.handle - QMetaObjectPrivate::get(signal.mobj)->methodData)/QMetaObjectPrivate::IntsPerMethod; + uint signalIndex = signal.relativeMethodIndex(); - if (signal.mobj->d.data[signal.handle + 4] & MethodCloned) + if (signal.data.flags() & MethodCloned) signalIndex = QMetaObjectPrivate::originalClone(signal.mobj, signalIndex); signalIndex += QMetaObjectPrivate::signalOffset(signal.mobj); @@ -2610,7 +2610,7 @@ void QMetaObjectPrivate::memberIndexes(const QObject *obj, m = m->d.superdata; if (!m) return; - *signalIndex = *methodIndex = (member.handle - get(member.mobj)->methodData)/QMetaObjectPrivate::IntsPerMethod; + *signalIndex = *methodIndex = member.relativeMethodIndex(); int signalOffset; int methodOffset; diff --git a/src/corelib/kernel/qobjectdefs.h b/src/corelib/kernel/qobjectdefs.h index 5ae4c47259..ae1abf61b9 100644 --- a/src/corelib/kernel/qobjectdefs.h +++ b/src/corelib/kernel/qobjectdefs.h @@ -427,7 +427,7 @@ struct Q_CORE_EXPORT QMetaObject #endif }; - struct { // private data + struct Data { // private data SuperData superdata; const uint *stringdata; const uint *data; -- cgit v1.2.3