diff options
author | Marc Mutz <marc.mutz@kdab.com> | 2012-08-10 16:12:58 +0200 |
---|---|---|
committer | Qt by Nokia <qt-info@nokia.com> | 2012-08-15 23:40:57 +0200 |
commit | 04c286ceb60311d4d7e1ae589b99d1ed7120c9cf (patch) | |
tree | c8e2efa83cf8a286dc9717eea54c1f9a25ab8cfc /src/corelib/kernel/qobject.cpp | |
parent | 3ef51efbe75bfb9f1dfbe7df073e9eb745a72ad8 (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.cpp')
-rw-r--r-- | src/corelib/kernel/qobject.cpp | 32 |
1 files changed, 14 insertions, 18 deletions
diff --git a/src/corelib/kernel/qobject.cpp b/src/corelib/kernel/qobject.cpp index a00d528ec9..6ac29879b9 100644 --- a/src/corelib/kernel/qobject.cpp +++ b/src/corelib/kernel/qobject.cpp @@ -72,6 +72,11 @@ QT_BEGIN_NAMESPACE static int DIRECT_CONNECTION_ONLY = 0; +struct QSlotObjectBaseDeleter { // for use with QScopedPointer<QSlotObjectBase,...> + static void cleanup(QtPrivate::QSlotObjectBase *slot) { + if (slot && !slot->ref.deref() ) slot->destroy(); + } +}; static int *queuedConnectionTypes(const QList<QByteArray> &typeNames) { int *types = new int [typeNames.count() + 1]; @@ -432,7 +437,7 @@ QMetaCallEvent::QMetaCallEvent(ushort method_offset, ushort method_relative, QOb /*! \internal */ -QMetaCallEvent::QMetaCallEvent(QObject::QSlotObjectBase *slotO, const QObject *sender, int signalId, +QMetaCallEvent::QMetaCallEvent(QtPrivate::QSlotObjectBase *slotO, const QObject *sender, int signalId, int nargs, int *types, void **args, QSemaphore *semaphore) : QEvent(MetaCall), slotObj_(slotO), sender_(sender), signalId_(signalId), nargs_(nargs), types_(types), args_(args), semaphore_(semaphore), @@ -460,7 +465,7 @@ QMetaCallEvent::~QMetaCallEvent() semaphore_->release(); #endif if (slotObj_ && !slotObj_->ref.deref()) - delete slotObj_; + slotObj_->destroy(); } /*! @@ -864,7 +869,7 @@ QObjectPrivate::Connection::~Connection() delete [] v; } if (isSlotObject && !slotObj->ref.deref()) - delete slotObj; + slotObj->destroy(); } @@ -3412,7 +3417,8 @@ void QMetaObject::activate(QObject *sender, int signalOffset, int local_signal_i const QObjectPrivate::StaticMetaCallFunction callFunction = c->callFunction; const int method_relative = c->method_relative; if (c->isSlotObject) { - QExplicitlySharedDataPointer<QObject::QSlotObjectBase> obj(c->slotObj); + c->slotObj->ref.ref(); + const QScopedPointer<QtPrivate::QSlotObjectBase, QSlotObjectBaseDeleter> obj(c->slotObj); locker.unlock(); obj->call(receiver, argv ? argv : empty_argv); locker.relock(); @@ -4185,13 +4191,13 @@ void qDeleteInEventHandler(QObject *o) */ QMetaObject::Connection QObject::connectImpl(const QObject *sender, void **signal, const QObject *receiver, void **slot, - QObject::QSlotObjectBase *slotObj, Qt::ConnectionType type, + QtPrivate::QSlotObjectBase *slotObj, Qt::ConnectionType type, const int *types, const QMetaObject *senderMetaObject) { if (!sender || !signal || !slotObj || !senderMetaObject) { qWarning("QObject::connect: invalid null parametter"); if (slotObj && !slotObj->ref.deref()) - delete slotObj; + slotObj->destroy(); return QMetaObject::Connection(); } int signal_index = -1; @@ -4200,7 +4206,7 @@ QMetaObject::Connection QObject::connectImpl(const QObject *sender, void **signa if (signal_index < 0 || signal_index >= QMetaObjectPrivate::get(senderMetaObject)->signalCount) { qWarning("QObject::connect: signal not found in %s", senderMetaObject->className()); if (!slotObj->ref.deref()) - delete slotObj; + slotObj->destroy(); return QMetaObject::Connection(0); } signal_index += QMetaObjectPrivate::signalOffset(senderMetaObject); @@ -4220,7 +4226,7 @@ QMetaObject::Connection QObject::connectImpl(const QObject *sender, void **signa while (c2) { if (c2->receiver == receiver && c2->isSlotObject && c2->slotObj->compare(slot)) { if (!slotObj->ref.deref()) - delete slotObj; + slotObj->destroy(); return QMetaObject::Connection(); } c2 = c2->nextConnectionList; @@ -4412,16 +4418,6 @@ QMetaObject::Connection::~Connection() the signal or the slot, or if the arguments do not match. */ -QObject::QSlotObjectBase::~QSlotObjectBase() -{ -} - -bool QObject::QSlotObjectBase::compare(void** ) -{ - return false; -} - - QT_END_NAMESPACE #include "moc_qobject.cpp" |