From 3efefcceba59d570a13b1a7de32a0e8caaf74aee Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Mon, 8 May 2023 10:41:49 -0700 Subject: [PATCH] QSlotObjectBase: move the m_ref after m_impl for Qt 7 This moves the padding that exists on 64-bit architectures from between the two fields to the end of the the structure. In turns, this allows certain ABIs to reuse the tail padding space of the base class to store some information. It can only be used if the functor has alignment of 4 or less, but the interesting case is when it's an empty but final functor. The pahole report goes from: struct CallableObject : QSlotObjectBase { /* class QSlotObjectBase ; */ /* 0 16 */ struct FinalFunctor func; /* 16 0 */ /* XXX last struct has 1 byte of padding */ /* size: 24, cachelines: 1, members: 2 */ /* padding: 8 */ /* paddings: 1, sum paddings: 1 */ } __attribute__((__aligned__(8))); to (pahole gets very confused by this trick): struct CallableObject : QSlotObjectBase { /* class QSlotObjectBase ; */ /* 0 16 */ /* XXX last struct has 4 bytes of padding */ /* XXX 65532 bytes hole, try to pack */ struct FinalFunctor func; /* 12 0 */ /* size: 16, cachelines: 1, members: 2 */ /* padding: 4 */ /* paddings: 2, sum paddings: 5 */ /* BRAIN FART ALERT! 16 bytes != 0 (member bytes) + 0 (member bits) + 65532 (byte holes) + 0 (bit holes), diff = -524160 bits */ } __attribute__((__aligned__(8))); Change-Id: I3e3bfef633af4130a03afffd175d3be98511bae5 Reviewed-by: Volker Hilsheimer --- src/corelib/kernel/qobjectdefs_impl.h | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/corelib/kernel/qobjectdefs_impl.h b/src/corelib/kernel/qobjectdefs_impl.h index 9d9e024ce6..8ae158b6b0 100644 --- a/src/corelib/kernel/qobjectdefs_impl.h +++ b/src/corelib/kernel/qobjectdefs_impl.h @@ -397,14 +397,21 @@ namespace QtPrivate { } // internal base class (interface) containing functions required to call a slot managed by a pointer to function. - class QSlotObjectBase { - QAtomicInt m_ref; + class QSlotObjectBase + { +#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0) + QAtomicInt m_ref = 1; +#endif // Don't use virtual functions here; we don't want the // compiler to create tons of per-polymorphic-class stuff that // we'll never need. We just use one function pointer, and the // Operations enum below to distinguish requests typedef void (*ImplFn)(int which, QSlotObjectBase* this_, QObject *receiver, void **args, bool *ret); const ImplFn m_impl; + +#if QT_VERSION >= QT_VERSION_CHECK(7, 0, 0) + QAtomicInt m_ref = 1; +#endif protected: // The operations that can be requested by calls to m_impl, // see the member functions that call m_impl below for details @@ -416,7 +423,7 @@ namespace QtPrivate { NumOperations }; public: - explicit QSlotObjectBase(ImplFn fn) : m_ref(1), m_impl(fn) {} + explicit QSlotObjectBase(ImplFn fn) : m_impl(fn) {} inline int ref() noexcept { return m_ref.ref(); } inline void destroyIfLastRef() noexcept