aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml/jsruntime/qv4sequenceobject.cpp
diff options
context:
space:
mode:
authorLuca Di Sera <[email protected]>2024-12-16 13:35:13 +0100
committerLuca Di Sera <[email protected]>2025-02-05 18:39:26 +0100
commita7349e6433d092398d76cafa5408753f06892cd7 (patch)
treea364aba708ab4d7c657a17dd6e0589d4c59bb53b /src/qml/jsruntime/qv4sequenceobject.cpp
parent063ab57c0d20da54a3fb7ecbeac103bac9aee7da (diff)
Avoid unnecessary read-backs on ReferenceObjects
When certain types are passed over from C++ to QML, QML converts them to a QML usable representation that keeps track of the original data. To do so, the QML representation of the object performs read/write-backs when required to ensure that the representation is kept in sync with the original data, by reading the latest data from the source or writing back changes that are performed on the QML side. Generally, the representation on the QML side cannot know when the original data was modified, so that it has to read the data again each time it accesses the representation to ensure that the latest data is available. The reads can be very expensive. For example, the following snippet: ``` JSON.stringify(foo) ``` Where `foo` is, for example, a `QStringList`, might need to read the data multiple times for each element in the list. For representations that provene from a QObject's property that has a NOTIFY signal, it is possible to cut down on the number of reads by reading only when the data was effectively changed since the last read, that is, the NOTIFY signal of the property was emitted. Similarly, if the property is a BINDABLE, we can subscribe to the BINDABLE itself to track whether a change was performed or not. Thus, to reduce the number of reads when possible, `ReferenceObject`, the base representation for objects that perform read/write-backs, was modified to take into account the NOTIFY signal or BINDABLE status of a property when referencing data that originally provenes from a `QObject`'s property on the C++ side. `QObjectWrapper`, `QQmlTypeWrapper`, `ReferenceObject` and `QMLValueTYpeWrapper` were modified with the usual `Q_MANAGED_TYPE` macro, to allow identifying instances of those objects, which is used to enable the new implementation. The intializer for `ReferenceObject` was modified to behave differently when the referenced data comes from a `QObjectWrapper`, which wraps a `QObject` provening from C++, or a `QQmlTypeWrapper`, which can wrap a `QObject` that is a singleton or an attached property. When it is so, and the part of the wrapped `QObject` that is referenced is a property that has a NOTIFY signal or is a BINDABLE, the `ReferenceObject` instance will now connect to the signal or subscribe to the BINDABLE. A newly added flag, `isDirty`, will be set when the signal is emitted and is used to track whether the data has changed since our last read. `QV4::ReferenceObject::readReference`, the base implementation for read-backs, was modified to take into account the new "isDirty" flag. When the flag is not set, we expect to already have the latest data, and thus do not actually perform the read anymore. Furthermore, the same implementation was modified to take care of setting the `isDirty` flag to a correct state after a read is performed. The connection to the NOTIFY signal is performed through the existing `QQmlNotifier/Endpoint` infrastructure, which allows, between others, to connect to signal emitted by a `QObject`, and should be more performant than a naked connection. Similarly, a BINDABLE is subscribed to by using its usual interface. A new callback was added to be used by `ReferenceObject` to allow setting the `isDirty` flag on the signal emission. `ReferenceObject` will now store a `QQmlNotifierEndpoint` or a `QPropertyNotifier`, that will take care of listening to upstream changes and set the dirty flag as required. A few bug-provening test cases where added to `tst_qqmllanguage` to test that the number of unnecessary reads was indeed reduced. Additional test cases were added to inspect certain aspects of the new implementation to ensure that it works in certain common or edge cases. The internal documentation for `ReferenceObject` was modified to mention this new behavior. Fixes: QTBUG-118847 Fixes: QTBUG-127322 Change-Id: Id62979ae4e03910e1165c293837e5d884727dddc Reviewed-by: Ulf Hermann <[email protected]>
Diffstat (limited to 'src/qml/jsruntime/qv4sequenceobject.cpp')
-rw-r--r--src/qml/jsruntime/qv4sequenceobject.cpp2
1 files changed, 1 insertions, 1 deletions
diff --git a/src/qml/jsruntime/qv4sequenceobject.cpp b/src/qml/jsruntime/qv4sequenceobject.cpp
index 416ed959cc..e487b17b25 100644
--- a/src/qml/jsruntime/qv4sequenceobject.cpp
+++ b/src/qml/jsruntime/qv4sequenceobject.cpp
@@ -111,7 +111,7 @@ void Heap::Sequence::init(
QMetaType listType, QMetaSequence metaSequence, const void *container,
Heap::Object *object, int propertyIndex, Heap::ReferenceObject::Flags flags)
{
- ReferenceObject::init(object, propertyIndex, flags);
+ ReferenceObject::init(object, propertyIndex, flags | IsDirty);
initTypes(listType, metaSequence);
if (CppStackFrame *frame = internalClass->engine->currentStackFrame)