From 3410b1dc9c9d29cab84d471064d8ef1d26a0f98c Mon Sep 17 00:00:00 2001 From: Fabian Kosmale Date: Thu, 28 Jul 2022 12:51:11 +0200 Subject: [PATCH] QProperty: optimize non-recursive notification logic Previously, we were storing all binding-observers in a list, so that we can later revisit them during the notification loop. However, there is no point in doing that when the binding did not actually change. Pick-to: 6.4 Change-Id: I0b3343cc442eca2586c7c6a10c31d780f04730e6 Reviewed-by: Andrei Golubev Reviewed-by: Ulf Hermann --- src/corelib/kernel/qproperty.cpp | 7 ++++--- src/corelib/kernel/qproperty_p.h | 11 ++++++----- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/src/corelib/kernel/qproperty.cpp b/src/corelib/kernel/qproperty.cpp index bade48042d..f80c22c0d9 100644 --- a/src/corelib/kernel/qproperty.cpp +++ b/src/corelib/kernel/qproperty.cpp @@ -276,7 +276,7 @@ void QPropertyBindingPrivate::unlinkAndDeref() destroyAndFreeMemory(this); } -void QPropertyBindingPrivate::evaluateRecursive(PendingBindingObserverList &bindingObservers, QBindingStatus *status) +bool QPropertyBindingPrivate::evaluateRecursive(PendingBindingObserverList &bindingObservers, QBindingStatus *status) { if (!status) status = &bindingStatus; @@ -769,10 +769,11 @@ void QPropertyObserverPointer::evaluateBindings(PendingBindingObserverList &bind QPropertyObserver *next = observer->next.data(); if (QPropertyObserver::ObserverTag(observer->next.tag()) == QPropertyObserver::ObserverNotifiesBinding) { - bindingObservers.push_back(observer); auto bindingToEvaluate = observer->binding; QPropertyObserverNodeProtector protector(observer); - bindingToEvaluate->evaluateRecursive_inline(bindingObservers, status); + QBindingObserverPtr bindingObserver(observer); // binding must not be gone after evaluateRecursive_inline + if (bindingToEvaluate->evaluateRecursive_inline(bindingObservers, status)) + bindingObservers.push_back(std::move(bindingObserver)); next = protector.next(); } diff --git a/src/corelib/kernel/qproperty_p.h b/src/corelib/kernel/qproperty_p.h index 9c32a63fc3..50bdfb4abc 100644 --- a/src/corelib/kernel/qproperty_p.h +++ b/src/corelib/kernel/qproperty_p.h @@ -360,7 +360,7 @@ public: void unlinkAndDeref(); - void evaluateRecursive(PendingBindingObserverList &bindingObservers, QBindingStatus *status = nullptr); + bool evaluateRecursive(PendingBindingObserverList &bindingObservers, QBindingStatus *status = nullptr); // ### TODO: remove as soon as declarative no longer needs this overload void evaluateRecursive() @@ -369,7 +369,7 @@ public: evaluateRecursive(bindingObservers); } - void Q_ALWAYS_INLINE evaluateRecursive_inline(PendingBindingObserverList &bindingObservers, QBindingStatus *status); + bool Q_ALWAYS_INLINE evaluateRecursive_inline(PendingBindingObserverList &bindingObservers, QBindingStatus *status); void notifyRecursive(); void notifyNonRecursive(const PendingBindingObserverList &bindingObservers); @@ -780,13 +780,13 @@ struct QUntypedBindablePrivate } }; -inline void QPropertyBindingPrivate::evaluateRecursive_inline(PendingBindingObserverList &bindingObservers, QBindingStatus *status) +inline bool QPropertyBindingPrivate::evaluateRecursive_inline(PendingBindingObserverList &bindingObservers, QBindingStatus *status) { if (updating) { error = QPropertyBindingError(QPropertyBindingError::BindingLoop); if (isQQmlPropertyBinding) errorCallBack(this); - return; + return false; } /* @@ -816,10 +816,11 @@ inline void QPropertyBindingPrivate::evaluateRecursive_inline(PendingBindingObse // If there was not, we must not clear it, as that only should happen in notifyRecursive pendingNotify = pendingNotify || changed; if (!changed || !firstObserver) - return; + return changed; firstObserver.noSelfDependencies(this); firstObserver.evaluateBindings(bindingObservers, status); + return true; } template