QMetaType: move the built-in QMetaTypeInterfaces to read-only segments

The presence of the mutable causes the const object to lose its
constness, so declaring as const wasn't helpful. But we can't drop the
const wholesale for MSVC right now because it mangles the variable's
type in the external name.

For all other compilers, we drop it for user-defined types, which is a
no-op but is semantically correct because QMetaType needs to modify
those objects. Aside from a few const_cast (marked with comments),
nothing else changes.

For types with built-in type IDs, however, the QMetaTypeInterface is now
fully const... or would be if it weren't full of relocations. It does
move the lot from the .data section to the .data.rel.ro section. After
this change, QtCore and QtGui have:

                QtCore  QtGui
.data.rel.ro       57     23
.data, exported    17     39
.data, private     94    193

sizeof(QtPrivate::QMetaTypeInterface) = 112 on 64-bit platforms
(but GCC issues ".align 32", so they effectively occupy 128 bytes)

Change-Id: Id0fb9ab0089845ee8843fffd16f9a35bfafebf77
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
This commit is contained in:
Thiago Macieira 2022-06-17 23:32:33 -07:00
parent dbf58407cb
commit c474825945
2 changed files with 31 additions and 5 deletions

View File

@ -75,8 +75,11 @@ struct QMetaTypeCustomRegistry
// index of first empty (unregistered) type in registry, if any.
int firstEmpty = 0;
int registerCustomType(const QtPrivate::QMetaTypeInterface *ti)
int registerCustomType(const QtPrivate::QMetaTypeInterface *cti)
{
// we got here because cti->typeId is 0, so this is a custom meta type
// (not read-only)
auto ti = const_cast<QtPrivate::QMetaTypeInterface *>(cti);
{
QWriteLocker l(&lock);
if (int id = ti->typeId.loadRelaxed())
@ -789,9 +792,11 @@ bool QMetaType::isOrdered() const
void QMetaType::unregisterMetaType(QMetaType type)
{
if (type.d_ptr && type.d_ptr->typeId.loadRelaxed() >= QMetaType::User) {
// this is a custom meta type (not read-only)
auto d = const_cast<QtPrivate::QMetaTypeInterface *>(type.d_ptr);
if (auto reg = customTypeRegistry())
reg->unregisterDynamicType(type.d_ptr->typeId.loadRelaxed());
type.d_ptr->typeId.storeRelease(0);
reg->unregisterDynamicType(d->typeId.loadRelaxed());
d->typeId.storeRelease(0);
}
}

View File

@ -225,6 +225,20 @@ struct QMetaObject;
namespace QtPrivate
{
class QMetaTypeInterface;
// MSVC is the only supported compiler that includes the type of a variable in
// its mangled form, so it's not binary-compatible to drop the const in
// QMetaTypeInterfaceWrapper::metaType for it, which means we must keep the
// mutable field until Qt 7.
#if QT_VERSION >= QT_VERSION_CHECK(7, 0, 0) || defined(QT_BOOTSTRAPPED) || !defined(Q_CC_MSVC)
# define QMTI_MUTABLE
using NonConstMetaTypeInterface = QMetaTypeInterface;
#else
# define QMTI_MUTABLE mutable
using NonConstMetaTypeInterface = const QMetaTypeInterface;
#endif
class QMetaTypeInterface
{
public:
@ -232,7 +246,7 @@ public:
ushort alignment;
uint size;
uint flags;
mutable QBasicAtomicInt typeId;
QMTI_MUTABLE QBasicAtomicInt typeId;
using MetaObjectFn = const QMetaObject *(*)(const QMetaTypeInterface *);
MetaObjectFn metaObjectFn;
@ -261,6 +275,7 @@ public:
using LegacyRegisterOp = void (*)();
LegacyRegisterOp legacyRegisterOp;
};
#undef QMTI_MUTABLE
/*!
This template is used for implicit conversion from type From to type To.
@ -2326,7 +2341,13 @@ public:
template<typename T>
struct QMetaTypeInterfaceWrapper
{
static inline constexpr const QMetaTypeInterface metaType = {
// if the type ID for T is known at compile-time, then we can declare
// the QMetaTypeInterface object const; otherwise, we declare it as
// non-const and the .typeId is updated by QMetaType::idHelper().
static constexpr bool IsConstMetaTypeInterface = !!BuiltinMetaType<T>::value;
using InterfaceType = std::conditional_t<IsConstMetaTypeInterface, const QMetaTypeInterface, NonConstMetaTypeInterface>;
static inline InterfaceType metaType = {
/*.revision=*/ 0,
/*.alignment=*/ alignof(T),
/*.size=*/ sizeof(T),