aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorUlf Hermann <ulf.hermann@qt.io>2021-04-19 14:26:59 +0200
committerUlf Hermann <ulf.hermann@qt.io>2021-04-19 20:24:20 +0200
commit092cf238916ae371dee31e5cc660a492fb58d0c4 (patch)
tree9dfcbeb9ea7cedff1cb056fbed72b3861618a84a
parent48b1c59b65332b773eb51d25c422b53dbd3d6762 (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.cpp29
-rw-r--r--src/qml/qml/qqmljavascriptexpression.cpp58
-rw-r--r--src/qml/qml/qqmljavascriptexpression_p.h5
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)