diff options
author | Friedemann Kleint <Friedemann.Kleint@qt.io> | 2024-05-17 14:43:13 +0200 |
---|---|---|
committer | Friedemann Kleint <Friedemann.Kleint@qt.io> | 2024-05-21 09:57:01 +0200 |
commit | 985d9e01a2d52cecfb5083941e819969033d1061 (patch) | |
tree | b8665c87fcc188eeaa4bb06a5ffc4db4c27f15a3 /sources/pyside6/libpyside/pyside.cpp | |
parent | 84939474074974b080474a224e5e2900cad25d8a (diff) |
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 <tismer@stackless.com>
Diffstat (limited to 'sources/pyside6/libpyside/pyside.cpp')
-rw-r--r-- | sources/pyside6/libpyside/pyside.cpp | 44 |
1 files changed, 43 insertions, 1 deletions
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 <QtCore/QMutex> #include <QtCore/QStack> #include <QtCore/QThread> +#include <QtCore/private/qobject_p.h> #include <algorithm> #include <cstring> @@ -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<const FriendlyQObject *>(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; |