Reduce code bloat, by cleaning up QMetaTypeFunctionHelper

Create and Delete wrappers are not necessary, because they can be
easily simulated with Construct and Destruct. This change removes
redundant function wrappers and a bit of over-optimized code. Gain is
quite big:

Before:
   text    data     bss     dec     hex filename
5366008   47460   14904 5428372  52d494 libQt5Core.so.5.5.0
 505578    7060    2124  514762   7daca libQt5DBus.so.5.5.0
5591079  134656    6728 5732463  57786f libQt5Gui.so.5.5.0
1398785   31676    2576 1433037  15ddcd libQt5Network.so.5.5.0
6642431  220952    2536 6865919  68c3ff libQt5Widgets.so.5.5.0

After:
   text    data     bss     dec     hex filename
5342559   47460   14904 5404923  5278fb libQt5Core.so.5.5.0
 496025    7068    2124  505217   7b581 libQt5DBus.so.5.5.0
5579291  134272    6728 5720291  5748e3 libQt5Gui.so.5.5.0
1389461   31676    2576 1423713  15b961 libQt5Network.so.5.5.0
6637139  220952    2536 6860627  68af53 libQt5Widgets.so.5.5.0

Cost of the change, is moved to CPU while calling QMetaType create()
and destroy(), these two functions became a bit slower. The cost should
not be visible, because they call operator new anyway.

Change-Id: I34fd410343377d9c29925675d7da8172bfda9ce6
Reviewed-by: Simon Hausmann <simon.hausmann@digia.com>
This commit is contained in:
Jędrzej Nowacki 2014-10-31 16:07:39 +01:00 committed by Jędrzej Nowacki
parent 78e0e72eb5
commit 3d575d4845
3 changed files with 64 additions and 155 deletions

View File

@ -882,24 +882,43 @@ int QMetaType::registerType(const char *typeName, Deleter deleter,
/*!
\internal
\since 5.0
\internal
\since 5.0
\overload
Don't use, kept for binary compatibility
Registers a user type for marshalling, with \a normalizedTypeName, a \a
deleter, a \a creator, a \a destructor, a \a constructor, and
a \a size. Returns the type's handle, or -1 if the type could
not be registered. Note that normalizedTypeName is not checked for
conformance with Qt's normalized format, so it must already
conform.
*/
### TODO Qt6: remove me
*/
int QMetaType::registerNormalizedType(const NS(QByteArray) &normalizedTypeName, Deleter deleter,
Creator creator,
Destructor destructor,
Constructor constructor,
int size, TypeFlags flags, const QMetaObject *metaObject)
{
Q_UNUSED(deleter);
Q_UNUSED(creator);
return registerNormalizedType(normalizedTypeName, destructor, constructor, size, flags, metaObject);
}
/*!
\internal
\since 5.5
Registers a user type for marshalling, with \a normalizedTypeName,
a \a destructor, a \a constructor, and a \a size. Returns the type's
handle, or -1 if the type could not be registered.
\note normalizedTypeName is not checked for conformance with
Qt's normalized format, so it must already conform.
*/
int QMetaType::registerNormalizedType(const NS(QByteArray) &normalizedTypeName,
Destructor destructor,
Constructor constructor,
int size, TypeFlags flags, const QMetaObject *metaObject)
{
QVector<QCustomTypeInfo> *ct = customTypes();
if (!ct || normalizedTypeName.isEmpty() || !deleter || !creator || !destructor || !constructor)
if (!ct || normalizedTypeName.isEmpty() || !destructor || !constructor)
return -1;
int idx = qMetaTypeStaticType(normalizedTypeName.constData(),
@ -914,8 +933,6 @@ int QMetaType::registerNormalizedType(const NS(QByteArray) &normalizedTypeName,
if (idx == UnknownType) {
QCustomTypeInfo inf;
inf.typeName = normalizedTypeName;
inf.creator = creator;
inf.deleter = deleter;
#ifndef QT_NO_DATASTREAM
inf.loadOp = 0;
inf.saveOp = 0;
@ -1016,8 +1033,6 @@ int QMetaType::registerNormalizedTypedef(const NS(QByteArray) &normalizedTypeNam
QCustomTypeInfo inf;
inf.typeName = normalizedTypeName;
inf.alias = aliasId;
inf.creator = 0;
inf.deleter = 0;
ct->append(inf);
return aliasId;
}
@ -1566,60 +1581,6 @@ bool QMetaType::load(QDataStream &stream, int type, void *data)
return true;
}
#endif // QT_NO_DATASTREAM
namespace {
class TypeCreator {
template<typename T, bool IsAcceptedType = DefinedTypesFilter::Acceptor<T>::IsAccepted>
struct CreatorImpl {
static void *Create(const int /* type */, const void *copy)
{
// Using QMetaTypeFunctionHelper<T>::Create adds function call cost, even if it is a template (gcc).
// This "copy" check is moved out from the switcher by compiler (at least by gcc)
return copy ? new T(*static_cast<const T*>(copy)) : new T();
}
};
template<typename T>
struct CreatorImpl<T, /* IsAcceptedType = */ false> {
static void *Create(const int type, const void *copy)
{
if (QModulesPrivate::QTypeModuleInfo<T>::IsGui) {
if (Q_LIKELY(qMetaTypeGuiHelper))
return qMetaTypeGuiHelper[type - QMetaType::FirstGuiType].creator(copy);
}
if (QModulesPrivate::QTypeModuleInfo<T>::IsWidget) {
if (Q_LIKELY(qMetaTypeWidgetsHelper))
return qMetaTypeWidgetsHelper[type - QMetaType::FirstWidgetsType].creator(copy);
}
// This point can be reached only for known types that definition is not available, for example
// in bootstrap mode. We have no other choice then ignore it.
return 0;
}
};
public:
TypeCreator(const int type)
: m_type(type)
{}
template<typename T>
void *delegate(const T *copy) { return CreatorImpl<T>::Create(m_type, copy); }
void *delegate(const void*) { return 0; }
void *delegate(const QMetaTypeSwitcher::UnknownType *) { return 0; }
void *delegate(const QMetaTypeSwitcher::NotBuiltinType *copy)
{
QMetaType::Creator creator;
const QVector<QCustomTypeInfo> * const ct = customTypes();
{
QReadLocker locker(customTypesLock());
if (Q_UNLIKELY(m_type < QMetaType::User || !ct || ct->count() <= m_type - QMetaType::User))
return 0;
creator = ct->at(m_type - QMetaType::User).creator;
}
Q_ASSERT_X(creator, "void *QMetaType::create(int type, const void *copy)", "The type was not properly registered");
return creator(copy);
}
private:
const int m_type;
};
} // namespace
/*!
Returns a copy of \a copy, assuming it is of type \a type. If \a
@ -1629,65 +1590,11 @@ private:
*/
void *QMetaType::create(int type, const void *copy)
{
TypeCreator typeCreator(type);
return QMetaTypeSwitcher::switcher<void*>(typeCreator, type, copy);
QMetaType info(type);
int size = info.sizeOf();
return info.construct(operator new(size), copy);
}
namespace {
class TypeDestroyer {
template<typename T, bool IsAcceptedType = DefinedTypesFilter::Acceptor<T>::IsAccepted>
struct DestroyerImpl {
static void Destroy(const int /* type */, void *where) { QtMetaTypePrivate::QMetaTypeFunctionHelper<T>::Delete(where); }
};
template<typename T>
struct DestroyerImpl<T, /* IsAcceptedType = */ false> {
static void Destroy(const int type, void *where)
{
if (QModulesPrivate::QTypeModuleInfo<T>::IsGui) {
if (Q_LIKELY(qMetaTypeGuiHelper))
qMetaTypeGuiHelper[type - QMetaType::FirstGuiType].deleter(where);
return;
}
if (QModulesPrivate::QTypeModuleInfo<T>::IsWidget) {
if (Q_LIKELY(qMetaTypeWidgetsHelper))
qMetaTypeWidgetsHelper[type - QMetaType::FirstWidgetsType].deleter(where);
return;
}
// This point can be reached only for known types that definition is not available, for example
// in bootstrap mode. We have no other choice then ignore it.
}
};
public:
TypeDestroyer(const int type)
: m_type(type)
{}
template<typename T>
void delegate(const T *where) { DestroyerImpl<T>::Destroy(m_type, const_cast<T*>(where)); }
void delegate(const void *) {}
void delegate(const QMetaTypeSwitcher::UnknownType*) {}
void delegate(const QMetaTypeSwitcher::NotBuiltinType *where) { customTypeDestroyer(m_type, (void*)where); }
private:
static void customTypeDestroyer(const int type, void *where)
{
QMetaType::Destructor deleter;
const QVector<QCustomTypeInfo> * const ct = customTypes();
{
QReadLocker locker(customTypesLock());
if (Q_UNLIKELY(type < QMetaType::User || !ct || ct->count() <= type - QMetaType::User))
return;
deleter = ct->at(type - QMetaType::User).deleter;
}
Q_ASSERT_X(deleter, "void QMetaType::destroy(int type, void *data)", "The type was not properly registered");
deleter(where);
}
const int m_type;
};
} // namespace
/*!
Destroys the \a data, assuming it is of the \a type given.
@ -1695,8 +1602,9 @@ private:
*/
void QMetaType::destroy(int type, void *data)
{
TypeDestroyer deleter(type);
QMetaTypeSwitcher::switcher<void>(deleter, type, data);
QMetaType info(type);
info.destruct(data);
operator delete(data);
}
namespace {
@ -2246,10 +2154,10 @@ QMetaType QMetaType::typeInfo(const int type)
{
TypeInfo typeInfo(type);
QMetaTypeSwitcher::switcher<void>(typeInfo, type, 0);
return typeInfo.info.creator ? QMetaType(QMetaType::NoExtensionFlags
return typeInfo.info.constructor ? QMetaType(static_cast<ExtensionFlag>(QMetaType::CreateEx | QMetaType::DestroyEx)
, static_cast<const QMetaTypeInterface *>(0) // typeInfo::info is a temporary variable, we can't return address of it.
, typeInfo.info.creator
, typeInfo.info.deleter
, 0 // unused
, 0 // unused
, typeInfo.info.saveOp
, typeInfo.info.loadOp
, typeInfo.info.constructor
@ -2291,8 +2199,8 @@ QMetaType::QMetaType(const int typeId)
Copy constructs a QMetaType object.
*/
QMetaType::QMetaType(const QMetaType &other)
: m_creator(other.m_creator)
, m_deleter(other.m_deleter)
: m_creator_unused(other.m_creator_unused)
, m_deleter_unused(other.m_deleter_unused)
, m_saveOp(other.m_saveOp)
, m_loadOp(other.m_loadOp)
, m_constructor(other.m_constructor)
@ -2307,8 +2215,8 @@ QMetaType::QMetaType(const QMetaType &other)
QMetaType &QMetaType::operator =(const QMetaType &other)
{
m_creator = other.m_creator;
m_deleter = other.m_deleter;
m_creator_unused = other.m_creator_unused;
m_deleter_unused = other.m_deleter_unused;
m_saveOp = other.m_saveOp;
m_loadOp = other.m_loadOp;
m_constructor = other.m_constructor;
@ -2357,11 +2265,14 @@ void QMetaType::dtor()
Method used for future binary compatible extensions. The function may be called
during QMetaType::create to force library call from inlined code.
### TODO Qt6 remove the extension
*/
void *QMetaType::createExtended(const void *copy) const
{
Q_UNUSED(copy);
return 0;
if (m_typeId == QMetaType::UnknownType)
return 0;
return m_constructor(operator new(m_size), copy);
}
/*!
@ -2370,10 +2281,13 @@ void *QMetaType::createExtended(const void *copy) const
Method used for future binary compatible extensions. The function may be called
during QMetaType::destroy to force library call from inlined code.
### TODO Qt6 remove the extension
*/
void QMetaType::destroyExtended(void *data) const
{
Q_UNUSED(data);
m_destructor(data);
operator delete(data);
}
/*!

View File

@ -471,6 +471,11 @@ public:
int size,
QMetaType::TypeFlags flags,
const QMetaObject *metaObject);
static int registerNormalizedType(const QT_PREPEND_NAMESPACE(QByteArray) &normalizedTypeName, Destructor destructor,
Constructor constructor,
int size,
QMetaType::TypeFlags flags,
const QMetaObject *metaObject);
static int registerTypedef(const char *typeName, int aliasId);
static int registerNormalizedTypedef(const QT_PREPEND_NAMESPACE(QByteArray) &normalizedTypeName, int aliasId);
static int type(const char *typeName);
@ -668,8 +673,8 @@ public:
static void unregisterConverterFunction(int from, int to);
private:
Creator m_creator;
Deleter m_deleter;
Creator m_creator_unused;
Deleter m_deleter_unused;
SaveOperator m_saveOp;
LoadOperator m_loadOp;
Constructor m_constructor;
@ -1618,8 +1623,6 @@ int qRegisterNormalizedMetaType(const QT_PREPEND_NAMESPACE(QByteArray) &normaliz
flags |= QMetaType::WasDeclaredAsMetaType;
const int id = QMetaType::registerNormalizedType(normalizedTypeName,
QtMetaTypePrivate::QMetaTypeFunctionHelper<T>::Delete,
QtMetaTypePrivate::QMetaTypeFunctionHelper<T>::Create,
QtMetaTypePrivate::QMetaTypeFunctionHelper<T>::Destruct,
QtMetaTypePrivate::QMetaTypeFunctionHelper<T>::Construct,
int(sizeof(T)),
@ -1988,8 +1991,8 @@ inline QMetaType::QMetaType(const ExtensionFlag extensionFlags, const QMetaTypeI
uint theTypeFlags,
int typeId,
const QMetaObject *_metaObject)
: m_creator(creator)
, m_deleter(deleter)
: m_creator_unused(creator)
, m_deleter_unused(deleter)
, m_saveOp(saveOp)
, m_loadOp(loadOp)
, m_constructor(constructor)
@ -2023,16 +2026,14 @@ inline bool QMetaType::isRegistered() const
inline void *QMetaType::create(const void *copy) const
{
if (Q_UNLIKELY(isExtended(CreateEx)))
return createExtended(copy);
return m_creator(copy);
// ### TODO Qt6 remove the extension
return createExtended(copy);
}
inline void QMetaType::destroy(void *data) const
{
if (Q_UNLIKELY(isExtended(DestroyEx)))
return destroyExtended(data);
m_deleter(data);
// ### TODO Qt6 remove the extension
destroyExtended(data);
}
inline void *QMetaType::construct(void *where, const void *copy) const

View File

@ -114,8 +114,6 @@ QT_FOR_EACH_STATIC_WIDGETS_CLASS(QT_DECLARE_WIDGETS_MODULE_TYPES_ITER)
class QMetaTypeInterface
{
public:
QMetaType::Creator creator;
QMetaType::Deleter deleter;
QMetaType::SaveOperator saveOp;
QMetaType::LoadOperator loadOp;
QMetaType::Constructor constructor;
@ -148,8 +146,6 @@ public:
#define QT_METATYPE_INTERFACE_INIT_IMPL(Type, DATASTREAM_DELEGATE) \
{ \
/*creator*/(QtMetaTypePrivate::QMetaTypeFunctionHelper<Type, QtMetaTypePrivate::TypeDefinition<Type>::IsAvailable>::Create), \
/*deleter*/(QtMetaTypePrivate::QMetaTypeFunctionHelper<Type, QtMetaTypePrivate::TypeDefinition<Type>::IsAvailable>::Delete), \
DATASTREAM_DELEGATE(Type) \
/*constructor*/(QtMetaTypePrivate::QMetaTypeFunctionHelper<Type, QtMetaTypePrivate::TypeDefinition<Type>::IsAvailable>::Construct), \
/*destructor*/(QtMetaTypePrivate::QMetaTypeFunctionHelper<Type, QtMetaTypePrivate::TypeDefinition<Type>::IsAvailable>::Destruct), \
@ -173,8 +169,6 @@ public:
#define QT_METATYPE_INTERFACE_INIT_NO_DATASTREAM(Type) QT_METATYPE_INTERFACE_INIT_IMPL(Type, QT_METATYPE_INTERFACE_INIT_EMPTY_DATASTREAM_IMPL)
#define QT_METATYPE_INTERFACE_INIT_EMPTY() \
{ \
/*creator*/ 0, \
/*deleter*/ 0, \
QT_METATYPE_INTERFACE_INIT_EMPTY_DATASTREAM_IMPL(void) \
/*constructor*/ 0, \
/*destructor*/ 0, \