diff options
author | Ulf Hermann <ulf.hermann@qt.io> | 2021-04-19 14:26:59 +0200 |
---|---|---|
committer | Ulf Hermann <ulf.hermann@qt.io> | 2021-04-19 20:24:20 +0200 |
commit | 092cf238916ae371dee31e5cc660a492fb58d0c4 (patch) | |
tree | 9dfcbeb9ea7cedff1cb056fbed72b3861618a84a | |
parent | 48b1c59b65332b773eb51d25c422b53dbd3d6762 (diff) |
Optimize property capture for known property caches
If we already know the property cache and data we don't have to look
them up again in captureProperty(). Such lookups can be expensive.
Change-Id: I94553260311912c5acee3105295f124721203e01
Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
-rw-r--r-- | src/qml/qml/qqml.cpp | 29 | ||||
-rw-r--r-- | src/qml/qml/qqmljavascriptexpression.cpp | 58 | ||||
-rw-r--r-- | src/qml/qml/qqmljavascriptexpression_p.h | 5 |
3 files changed, 61 insertions, 31 deletions
diff --git a/src/qml/qml/qqml.cpp b/src/qml/qml/qqml.cpp index 88fad02d1d..a0fbe507fd 100644 --- a/src/qml/qml/qqml.cpp +++ b/src/qml/qml/qqml.cpp @@ -726,10 +726,8 @@ bool QQmlPrivate::AOTCompiledContext::captureQmlContextPropertyLookup(uint index if (QQmlEngine *engine = qmlContext->engine()) { QQmlEnginePrivate *ep = QQmlEnginePrivate::get(engine); - if (!ep->propertyCapture) - return true; - ep->propertyCapture->captureProperty(qmlScopeObject, property->coreIndex(), - property->notifyIndex()); + if (QQmlPropertyCapture *capture = ep->propertyCapture) + capture->captureProperty(qmlScopeObject, l->qobjectLookup.propertyCache, property); } return true; @@ -746,8 +744,8 @@ QObject *QQmlPrivate::AOTCompiledContext::loadQmlContextPropertyIdLookup(uint in QQmlEnginePrivate *qmlEngine = QQmlEnginePrivate::get(qmlContext->engine()); const int objectId = l->qmlContextIdObjectLookup.objectId; - if (qmlEngine->propertyCapture) - qmlEngine->propertyCapture->captureProperty(qmlContext->idValueBindings(objectId)); + if (QQmlPropertyCapture *capture = qmlEngine->propertyCapture) + capture->captureProperty(qmlContext->idValueBindings(objectId)); return qmlContext->idValue(objectId); } @@ -765,19 +763,18 @@ bool QQmlPrivate::AOTCompiledContext::getObjectLookup( if (!object) return false; + const QQmlPropertyCache *propertyCache = l->qobjectLookup.propertyCache; if (l->getter == QV4::QObjectWrapper::lookupGetter && !QQmlData::wasDeleted(object) - && QQmlData::get(object)->propertyCache == l->qobjectLookup.propertyCache) { - QQmlPropertyData *property = l->qobjectLookup.propertyData; + && QQmlData::get(object)->propertyCache == propertyCache) { + const QQmlPropertyData *property = l->qobjectLookup.propertyData; if (property->propType() == type) { // We can directly read the property into the target, without conversion. if (!property->isConstant()) { if (QQmlEngine *engine = qmlContext->engine()) { QQmlEnginePrivate *ep = QQmlEnginePrivate::get(engine); - if (ep->propertyCapture) { - ep->propertyCapture->captureProperty(object, property->coreIndex(), - property->notifyIndex()); - } + if (QQmlPropertyCapture *capture = ep->propertyCapture) + capture->captureProperty(object, propertyCache, property); } } property->readProperty(object, target); @@ -832,17 +829,15 @@ bool QQmlPrivate::AOTCompiledContext::captureLookup(uint index, QObject *object) return false; } - const auto *property = l->qobjectLookup.propertyData; + const QQmlPropertyData *property = l->qobjectLookup.propertyData; Q_ASSERT(property); if (property->isConstant()) return true; if (QQmlEngine *engine = qmlContext->engine()) { QQmlEnginePrivate *ep = QQmlEnginePrivate::get(engine); - if (!ep->propertyCapture) - return true; - ep->propertyCapture->captureProperty(object, property->coreIndex(), - property->notifyIndex()); + if (QQmlPropertyCapture *capture = ep->propertyCapture) + capture->captureProperty(object, l->qobjectLookup.propertyCache, property); return true; } diff --git a/src/qml/qml/qqmljavascriptexpression.cpp b/src/qml/qml/qqmljavascriptexpression.cpp index 97ef260295..95d7d89c99 100644 --- a/src/qml/qml/qqmljavascriptexpression.cpp +++ b/src/qml/qml/qqmljavascriptexpression.cpp @@ -358,24 +358,54 @@ void QQmlPropertyCapture::captureProperty(QObject *o, int c, int n, bool doNotif metaObjectForBindable = m; } if (metaObjectForBindable) { - // if the property is a QPropery, and we're binding to a QProperty - // the automatic capturing process already takes care of everything - if (typeid(QQmlPropertyBindingJS) == typeid(*expression)) - return; - for (auto trigger = expression->qpropertyChangeTriggers; trigger; - trigger = trigger->next) { - if (trigger->target == o && trigger->propertyIndex == c) - return; // already installed - } - auto trigger = expression->allocatePropertyChangeTrigger(o, c); - QUntypedBindable bindable; - void *argv[] = { &bindable }; - metaObjectForBindable->metacall(o, QMetaObject::BindableProperty, c, argv); - bindable.observe(trigger); + captureBindableProperty(o, metaObjectForBindable, c); return; } } + captureNonBindableProperty(o, n, c, doNotify); +} + +void QQmlPropertyCapture::captureProperty( + QObject *o, const QQmlPropertyCache *propertyCache, const QQmlPropertyData *propertyData, + bool doNotify) +{ + if (watcher->wasDeleted()) + return; + + Q_ASSERT(expression); + + if (propertyData->isBindable()) { + if (const QMetaObject *metaObjectForBindable = propertyCache->metaObject()) { + captureBindableProperty(o, metaObjectForBindable, propertyData->coreIndex()); + return; + } + } + + captureNonBindableProperty(o, propertyData->notifyIndex(), propertyData->coreIndex(), doNotify); +} + +void QQmlPropertyCapture::captureBindableProperty( + QObject *o, const QMetaObject *metaObjectForBindable, int c) +{ + // if the property is a QPropery, and we're binding to a QProperty + // the automatic capturing process already takes care of everything + if (typeid(QQmlPropertyBindingJS) == typeid(*expression)) + return; + for (auto trigger = expression->qpropertyChangeTriggers; trigger; + trigger = trigger->next) { + if (trigger->target == o && trigger->propertyIndex == c) + return; // already installed + } + auto trigger = expression->allocatePropertyChangeTrigger(o, c); + QUntypedBindable bindable; + void *argv[] = { &bindable }; + metaObjectForBindable->metacall(o, QMetaObject::BindableProperty, c, argv); + bindable.observe(trigger); +} + +void QQmlPropertyCapture::captureNonBindableProperty(QObject *o, int n, int c, bool doNotify) +{ if (n == -1) { if (!errorString) { errorString = new QStringList; diff --git a/src/qml/qml/qqmljavascriptexpression_p.h b/src/qml/qml/qqmljavascriptexpression_p.h index 4f4d744928..7a741afb75 100644 --- a/src/qml/qml/qqmljavascriptexpression_p.h +++ b/src/qml/qml/qqmljavascriptexpression_p.h @@ -237,6 +237,7 @@ public: void captureProperty(QQmlNotifier *); void captureProperty(QObject *, int, int, bool doNotify = true); + void captureProperty(QObject *, const QQmlPropertyCache *, const QQmlPropertyData *, bool doNotify = true); void captureTranslation() { translationCaptured = true; } QQmlEngine *engine; @@ -245,6 +246,10 @@ public: QForwardFieldList<QQmlJavaScriptExpressionGuard, &QQmlJavaScriptExpressionGuard::next> guards; QStringList *errorString; bool translationCaptured = false; + +private: + void captureBindableProperty(QObject *o, const QMetaObject *metaObjectForBindable, int c); + void captureNonBindableProperty(QObject *o, int n, int c, bool doNotify); }; QQmlJavaScriptExpression::DeleteWatcher::DeleteWatcher(QQmlJavaScriptExpression *e) |