summaryrefslogtreecommitdiffstats
path: root/src/corelib/kernel/qobject.h
diff options
context:
space:
mode:
authorMarc Mutz <marc.mutz@kdab.com>2012-08-10 16:12:58 +0200
committerQt by Nokia <qt-info@nokia.com>2012-08-15 23:40:57 +0200
commit04c286ceb60311d4d7e1ae589b99d1ed7120c9cf (patch)
treec8e2efa83cf8a286dc9717eea54c1f9a25ab8cfc /src/corelib/kernel/qobject.h
parent3ef51efbe75bfb9f1dfbe7df073e9eb745a72ad8 (diff)
QSlotObjectBase: combat virtual function "bloat"
In C++, the compiler creates extra functions and data for classes with virtual functions. This can lead to "virtual function bloat": http://www.boost.org/doc/libs/1_47_0/doc/html/function/misc.html#id1382504 This is especially true when the number of instances is of the same order of magnitute as the number of derived classes, such as is common with type erasure techniques. One such case is the QSlotObjectBase hierarchy, which this patch tackles. The mechanics of this optimisation are simple: re-implement the virtual function call mechanism by hand, with function pointers. But we go one step further and collapse the vtable into a single pointer to a function that implements all three currently-defined operations, swtching on an 'int which' argument. This even allows us to extend this in a BC way, should that become necessary later, by adding a new Operation and using the void** argument to transport arguments, if any. This approach was inspired by: Ulrich Drepper: How To Write Shared Libraries, Section 2.4.4 http://www.akkadia.org/drepper/dsohowto.pdf Also move the QSlotObjectBase hierarchy out of QObject so as not to export all the derived classes. This was pointed out in review by Thiago. Results (Linux amd64, GCC 4.8-pre -O2 -std=c++11, stripped): size tst_qobject* text data bss dec hex filename 523275 21192 48 544515 84f03 tst_qobject (old) 507343 13984 48 521375 7f49f tst_qobject (new) relinfo.pl tst_qobject* (old) tst_qobject: 473 relocations, 0 relative (0%), 240 PLT entries, 240 for local syms (100%), 0 users (new) tst_qobject: 323 relocations, 0 relative (0%), 238 PLT entries, 238 for local syms (100%), 0 users Change-Id: I40ad4744dde8c5c29ef62ed2d82d4b1ede178510 Reviewed-by: Olivier Goffart <ogoffart@woboq.com> Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
Diffstat (limited to 'src/corelib/kernel/qobject.h')
-rw-r--r--src/corelib/kernel/qobject.h56
1 files changed, 5 insertions, 51 deletions
diff --git a/src/corelib/kernel/qobject.h b/src/corelib/kernel/qobject.h
index 1d2d6a6794..ee157347ea 100644
--- a/src/corelib/kernel/qobject.h
+++ b/src/corelib/kernel/qobject.h
@@ -246,7 +246,7 @@ public:
return connectImpl(sender, reinterpret_cast<void **>(&signal),
receiver, reinterpret_cast<void **>(&slot),
- new QSlotObject<Func2, typename QtPrivate::List_Left<typename SignalType::Arguments, SlotType::ArgumentCount>::Value,
+ new QtPrivate::QSlotObject<Func2, typename QtPrivate::List_Left<typename SignalType::Arguments, SlotType::ArgumentCount>::Value,
typename SignalType::ReturnType>(slot),
type, types, &SignalType::Object::staticMetaObject);
}
@@ -268,7 +268,7 @@ public:
"Return type of the slot is not compatible with the return type of the signal.");
return connectImpl(sender, reinterpret_cast<void **>(&signal), sender, 0,
- new QStaticSlotObject<Func2,
+ new QtPrivate::QStaticSlotObject<Func2,
typename QtPrivate::List_Left<typename SignalType::Arguments, SlotType::ArgumentCount>::Value,
typename SignalType::ReturnType>(slot),
Qt::DirectConnection, 0, &SignalType::Object::staticMetaObject);
@@ -282,7 +282,7 @@ public:
typedef QtPrivate::FunctionPointer<Func1> SignalType;
return connectImpl(sender, reinterpret_cast<void **>(&signal), sender, 0,
- new QFunctorSlotObject<Func2, SignalType::ArgumentCount, typename SignalType::Arguments, typename SignalType::ReturnType>(slot),
+ new QtPrivate::QFunctorSlotObject<Func2, SignalType::ArgumentCount, typename SignalType::Arguments, typename SignalType::ReturnType>(slot),
Qt::DirectConnection, 0, &SignalType::Object::staticMetaObject);
}
#endif //Q_QDOC
@@ -394,56 +394,10 @@ private:
Q_DISABLE_COPY(QObject)
Q_PRIVATE_SLOT(d_func(), void _q_reregisterTimers(void *))
- private:
- // internal base class (interface) containing functions required to call a slot managed by a pointer to function.
- struct Q_CORE_EXPORT QSlotObjectBase {
- QAtomicInt ref;
- QSlotObjectBase() : ref(1) {}
- virtual ~QSlotObjectBase();
- virtual void call(QObject *receiver, void **a) = 0;
- virtual bool compare(void **);
- };
- // implementation of QSlotObjectBase for which the slot is a pointer to member function of a QObject
- // Args and R are the List of arguments and the returntype of the signal to which the slot is connected.
- template<typename Func, typename Args, typename R> struct QSlotObject : QSlotObjectBase
- {
- typedef QtPrivate::FunctionPointer<Func> FuncType;
- Func function;
- QSlotObject(Func f) : function(f) {}
- virtual void call(QObject *receiver, void **a) {
- FuncType::template call<Args, R>(function, static_cast<typename FuncType::Object *>(receiver), a);
- }
- virtual bool compare(void **f) {
- return *reinterpret_cast<Func *>(f) == function;
- }
- };
- // implementation of QSlotObjectBase for which the slot is a static function
- // Args and R are the List of arguments and the returntype of the signal to which the slot is connected.
- template<typename Func, typename Args, typename R> struct QStaticSlotObject : QSlotObjectBase
- {
- typedef QtPrivate::FunctionPointer<Func> FuncType;
- Func function;
- QStaticSlotObject(Func f) : function(f) {}
- virtual void call(QObject *receiver, void **a) {
- FuncType::template call<Args, R>(function, receiver, a);
- }
- };
- // implementation of QSlotObjectBase for which the slot is a functor (or lambda)
- // N is the number of arguments
- // Args and R are the List of arguments and the returntype of the signal to which the slot is connected.
- template<typename Func, int N, typename Args, typename R> struct QFunctorSlotObject : QSlotObjectBase
- {
- typedef QtPrivate::Functor<Func, N> FuncType;
- Func function;
- QFunctorSlotObject(const Func &f) : function(f) {}
- virtual void call(QObject *receiver, void **a) {
- FuncType::template call<Args, R>(function, receiver, a);
- }
- };
-
+private:
static QMetaObject::Connection connectImpl(const QObject *sender, void **signal,
const QObject *receiver, void **slotPtr,
- QSlotObjectBase *slot, Qt::ConnectionType type,
+ QtPrivate::QSlotObjectBase *slot, Qt::ConnectionType type,
const int *types, const QMetaObject *senderMetaObject);
static bool disconnectImpl(const QObject *sender, void **signal, const QObject *receiver, void **slot,