From 985d9e01a2d52cecfb5083941e819969033d1061 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Fri, 17 May 2024 14:43:13 +0200 Subject: LazyInit: Speed up QObject conversion Lazy loading introduced a performance regression for applications using for example an event filter on QApplication, where all internal QObject-derived types from QML occur. This triggered the lazy loading mechanism for each of those classes that have no binding. To fix this, introduce checks to typeName(const QObject *) that skip the internal classes by checking for presence of a dynamic meta object and internal type names. This should also help skipping over QObject-derived classes written in Python which also have a dynamic meta object. Fixes: PYSIDE-2749 Task-number: PYSIDE-2404 Pick-to: 6.7 Change-Id: I029d104e59820fbf3dab52a3ac65b45d97b3c2e7 Reviewed-by: Christian Tismer --- sources/pyside6/libpyside/pyside.cpp | 44 +++++++++++++++++++++++++++++++++++- 1 file changed, 43 insertions(+), 1 deletion(-) (limited to 'sources/pyside6/libpyside/pyside.cpp') diff --git a/sources/pyside6/libpyside/pyside.cpp b/sources/pyside6/libpyside/pyside.cpp index 1a4050bf8..9e12e3cd7 100644 --- a/sources/pyside6/libpyside/pyside.cpp +++ b/sources/pyside6/libpyside/pyside.cpp @@ -43,6 +43,7 @@ #include #include #include +#include #include #include @@ -63,6 +64,20 @@ QT_END_NAMESPACE Q_LOGGING_CATEGORY(lcPySide, "qt.pyside.libpyside", QtCriticalMsg) +static QObjectData *qt_object_private(const QObject *o) +{ + class FriendlyQObject : public QObject { + public: + using QObject::d_ptr; + }; + return static_cast(o)->d_ptr.data(); +} + +static bool hasDynamicMetaObject(const QObject *o) +{ + return qt_object_private(o)->metaObject != nullptr; +} + namespace PySide { @@ -675,6 +690,32 @@ static void invalidatePtr(any_t *object) static const char invalidatePropertyName[] = "_PySideInvalidatePtr"; +// PYSIDE-2749: Skip over internal QML classes and classes +// with dynamic meta objects when looking for the best matching +// type to avoid unnessarily triggering the lazy load mechanism +// for classes that do not have a binding from things like eventFilter(). +static inline bool isInternalObject(const char *name) +{ + return std::strstr(name, "QMLTYPE") != nullptr || std::strstr(name, "QQmlPrivate") != nullptr; +} + +static const QMetaObject *metaObjectCandidate(const QObject *o) +{ + auto *metaObject = o->metaObject(); + // Skip QML helper types and Python objects + if (hasDynamicMetaObject(o)) { + if (auto *super = metaObject->superClass()) + metaObject = super; + } + for (auto *candidate = metaObject; candidate != nullptr; candidate = candidate->superClass()) { + if (!isInternalObject(candidate->className())) { + metaObject = candidate; + break; + } + } + return metaObject; +} + // PYSIDE-1214, when creating new wrappers for classes inheriting QObject but // not exposed to Python, try to find the best-matching (most-derived) Qt // class by walking up the meta objects. @@ -682,7 +723,8 @@ static const char *typeName(const QObject *cppSelf) { const char *typeName = typeid(*cppSelf).name(); if (!Shiboken::Conversions::getConverter(typeName)) { - for (auto metaObject = cppSelf->metaObject(); metaObject; metaObject = metaObject->superClass()) { + auto *metaObject = metaObjectCandidate(cppSelf); + for (; metaObject != nullptr; metaObject = metaObject->superClass()) { const char *name = metaObject->className(); if (Shiboken::Conversions::getConverter(name)) { typeName = name; -- cgit v1.2.3