diff options
author | Luca Di Sera <[email protected]> | 2024-12-16 13:35:13 +0100 |
---|---|---|
committer | Luca Di Sera <[email protected]> | 2025-02-05 18:39:26 +0100 |
commit | a7349e6433d092398d76cafa5408753f06892cd7 (patch) | |
tree | a364aba708ab4d7c657a17dd6e0589d4c59bb53b /src/qml/jsruntime/qv4sequenceobject.cpp | |
parent | 063ab57c0d20da54a3fb7ecbeac103bac9aee7da (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.cpp | 2 |
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) |