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     <ancestor>; */      /*     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     <ancestor>; */      /*     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 <volker.hilsheimer@qt.io>
bb10
Thiago Macieira 2023-05-08 10:41:49 -07:00
parent ccd3b28aab
commit 3efefcceba
1 changed files with 10 additions and 3 deletions

View File

@ -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