summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFabian Kosmale <fabian.kosmale@qt.io>2021-06-28 15:27:43 +0200
committerFabian Kosmale <fabian.kosmale@qt.io>2021-08-08 21:59:46 +0200
commit226d0981cdf1da8ca8ee53d88b663eea14de41e5 (patch)
treee462ece91179629e9122f647249814a8b7632008
parent63e1cf916d5f8783634ac3c10c5be114d3711df5 (diff)
QProperty: more micro optimization
- Provide an inline version of evaluateRecursive which does not fetch the status. - Provide an unsafe variant of setBindingToNotify which does not set the tag. This can be used in allocateDependencyObserver, as newly allocated observers already have the correct tag (this is checked via an assert). Change-Id: I31aec6af4aef244efc6d0777e5bfaaa8f82f2046 Reviewed-by: Lars Knoll <lars.knoll@qt.io> (cherry picked from commit f7eed15588fc93af417b8969fe4e498936d81e04)
-rw-r--r--src/corelib/kernel/qproperty.cpp54
-rw-r--r--src/corelib/kernel/qproperty_p.h46
2 files changed, 60 insertions, 40 deletions
diff --git a/src/corelib/kernel/qproperty.cpp b/src/corelib/kernel/qproperty.cpp
index 97854f8ac3..0055e6a5ff 100644
--- a/src/corelib/kernel/qproperty.cpp
+++ b/src/corelib/kernel/qproperty.cpp
@@ -285,44 +285,7 @@ void QPropertyBindingPrivate::unlinkAndDeref()
void QPropertyBindingPrivate::evaluateRecursive(QBindingStatus *status)
{
- if (updating) {
- error = QPropertyBindingError(QPropertyBindingError::BindingLoop);
- if (isQQmlPropertyBinding)
- errorCallBack(this);
- return;
- }
-
- QScopedValueRollback<bool> updateGuard(updating, true);
-
- /*
- * Evaluating the binding might lead to the binding being broken. This can
- * cause ref to reach zero at the end of the function. However, the
- * updateGuard's destructor will then still trigger, trying to set the
- * updating bool to its old value
- * To prevent this, we create a QPropertyBindingPrivatePtr which ensures
- * that the object is still alive when updateGuard's dtor runs.
- */
- QPropertyBindingPrivatePtr keepAlive {this};
-
- BindingEvaluationState evaluationFrame(this, status);
-
- auto bindingFunctor = reinterpret_cast<std::byte *>(this) +
- QPropertyBindingPrivate::getSizeEnsuringAlignment();
- bool changed = false;
- if (hasBindingWrapper) {
- changed = staticBindingWrapper(metaType, propertyDataPtr,
- {vtable, bindingFunctor});
- } else {
- changed = vtable->call(metaType, propertyDataPtr, bindingFunctor);
- }
- // If there was a change, we must set pendingNotify.
- // If there was not, we must not clear it, as that only should happen in notifyRecursive
- pendingNotify = pendingNotify || changed;
- if (!changed || !firstObserver)
- return;
-
- firstObserver.noSelfDependencies(this);
- firstObserver.evaluateBindings(status);
+ return evaluateRecursive_inline(status);
}
void QPropertyBindingPrivate::notifyRecursive()
@@ -539,7 +502,8 @@ void QPropertyBindingData::registerWithCurrentlyEvaluatingBinding_helper(Binding
QPropertyBindingDataPointer d{this};
QPropertyObserverPointer dependencyObserver = currentState->binding->allocateDependencyObserver();
- dependencyObserver.setBindingToNotify(currentState->binding);
+ Q_ASSERT(QPropertyObserver::ObserverNotifiesBinding == 0);
+ dependencyObserver.setBindingToNotify_unsafe(currentState->binding);
d.addObserver(dependencyObserver.ptr);
}
@@ -664,6 +628,16 @@ void QPropertyObserverPointer::setBindingToNotify(QPropertyBindingPrivate *bindi
}
/*!
+ \internal
+ The same as as setBindingToNotify, but assumes that the tag is already correct.
+ */
+void QPropertyObserverPointer::setBindingToNotify_unsafe(QPropertyBindingPrivate *binding)
+{
+ Q_ASSERT(ptr->next.tag() == QPropertyObserver::ObserverNotifiesBinding);
+ ptr->binding = binding;
+}
+
+/*!
\internal
QPropertyObserverNodeProtector is a RAII wrapper which takes care of the internal switching logic
for QPropertyObserverPointer::notify (described ibidem)
@@ -775,7 +749,7 @@ void QPropertyObserverPointer::evaluateBindings(QBindingStatus *status)
if (QPropertyObserver::ObserverTag(observer->next.tag()) == QPropertyObserver::ObserverNotifiesBinding) {
auto bindingToEvaluate = observer->binding;
QPropertyObserverNodeProtector protector(observer);
- bindingToEvaluate->evaluateRecursive(status);
+ bindingToEvaluate->evaluateRecursive_inline(status);
next = protector.next();
}
diff --git a/src/corelib/kernel/qproperty_p.h b/src/corelib/kernel/qproperty_p.h
index 96e89926db..f1b6ef6aa2 100644
--- a/src/corelib/kernel/qproperty_p.h
+++ b/src/corelib/kernel/qproperty_p.h
@@ -55,6 +55,7 @@
#include <qproperty.h>
#include <qscopedpointer.h>
+#include <qscopedvaluerollback.h>
#include <vector>
QT_BEGIN_NAMESPACE
@@ -104,6 +105,7 @@ struct QPropertyObserverPointer
void unlink();
void setBindingToNotify(QPropertyBindingPrivate *binding);
+ void setBindingToNotify_unsafe(QPropertyBindingPrivate *binding);
void setChangeHandler(QPropertyObserver::ChangeHandler changeHandler);
void notify(QUntypedPropertyData *propertyDataPtr);
@@ -325,6 +327,8 @@ public:
void unlinkAndDeref();
void evaluateRecursive(QBindingStatus *status = nullptr);
+ void Q_ALWAYS_INLINE evaluateRecursive_inline(QBindingStatus *status = nullptr);
+
void notifyRecursive();
static QPropertyBindingPrivate *get(const QUntypedPropertyBinding &binding)
@@ -693,6 +697,48 @@ struct QUntypedBindablePrivate
}
};
+inline void QPropertyBindingPrivate::evaluateRecursive_inline(QBindingStatus *status)
+{
+ if (updating) {
+ error = QPropertyBindingError(QPropertyBindingError::BindingLoop);
+ if (isQQmlPropertyBinding)
+ errorCallBack(this);
+ return;
+ }
+
+ QScopedValueRollback<bool> updateGuard(updating, true);
+
+ /*
+ * Evaluating the binding might lead to the binding being broken. This can
+ * cause ref to reach zero at the end of the function. However, the
+ * updateGuard's destructor will then still trigger, trying to set the
+ * updating bool to its old value
+ * To prevent this, we create a QPropertyBindingPrivatePtr which ensures
+ * that the object is still alive when updateGuard's dtor runs.
+ */
+ QPropertyBindingPrivatePtr keepAlive {this};
+
+ QtPrivate::BindingEvaluationState evaluationFrame(this, status);
+
+ auto bindingFunctor = reinterpret_cast<std::byte *>(this) +
+ QPropertyBindingPrivate::getSizeEnsuringAlignment();
+ bool changed = false;
+ if (hasBindingWrapper) {
+ changed = staticBindingWrapper(metaType, propertyDataPtr,
+ {vtable, bindingFunctor});
+ } else {
+ changed = vtable->call(metaType, propertyDataPtr, bindingFunctor);
+ }
+ // If there was a change, we must set pendingNotify.
+ // If there was not, we must not clear it, as that only should happen in notifyRecursive
+ pendingNotify = pendingNotify || changed;
+ if (!changed || !firstObserver)
+ return;
+
+ firstObserver.noSelfDependencies(this);
+ firstObserver.evaluateBindings(status);
+}
+
QT_END_NAMESPACE
#endif // QPROPERTY_P_H