aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml/jsruntime/qv4referenceobject.cpp
Commit message (Collapse)AuthorAgeFilesLines
* JSRuntime: Don't immediately connect reference objectsOlivier De Cannière2025-11-131-0/+70
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | The change in a7349e6433d092398d76cafa5408753f06892cd7 reduced the number of readbacks of reference objects by using connections to set the dirty state only when necessary. Establishing connections, however, comes at a cost and this introduced a regression in the delegates_item_childrenRect QmlBench benchmark. The mitigation introduced in this patch is to delay creating the connection. When a reference object is created, it does not read or create a connection but is simply marked as dirty. Only on a subsequent read from within a different statement than the reference object's creation's statement, does a connection get created. This keeps the benefit of reducing unnecessary reads on objects that are used multiple times while not spending too much on creating connections. This brings back the benchmark to its original level of performance. The referenceObjectChainReadsBackAsRequiredBasedOnParentSignals test was changed to expect 8 reads instead of 4. Since all the accesses are part of the same statement, no connection is ever created and more reads are required than before. The referenceObjectDoesNotFetchWithoutNotifyEventDateObject test is reformatted to separate the assignment from the reads. Otherwise no connection is ever created. The referenceObjectDoesNotLeakAConnectionToTheDestroyedSignalOnANotifyBindable test can be updated to expect 0 connections. With this change, we only connect if the reference object is read again from a different statement. Amends a7349e6433d092398d76cafa5408753f06892cd7 Fixes: QTBUG-140757 Pick-to: 6.10 Change-Id: I5d02ec6266c51fbbe5f2e01405081dd5a167a833 Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
* JSRuntime: Extract ReferenceObject::init lambdas into functionsOlivier De Cannière2025-11-131-0/+64
| | | | | | Pick-to: 6.10 Change-Id: I489b515388f9aba9250bfb05687331c92578ca57 Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
* Doc: Fix small typos in ReferenceObject's documentationOlivier De Cannière2025-11-131-5/+5
| | | | | Change-Id: I71ba63cdde7c8f3e18b89a1a4e35da30202fd8e4 Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
* CRA review qml/jsruntimeFabian Kosmale2025-09-161-0/+1
| | | | | | | | | | | | | | | | | | This relies heavily on the documented fact that we only support trusted QML/JS content, meaning most files are only significant, not critical. This also extends to the handling of qmlc files (as in compilationunitmapper), as we store them in a user owned, non-shared cache directory – so any vulnerability there would already mean that an attacker has write-priviledges on user data. An exception is ArrayBuffer, which can be used with arbitrary user data, and should create a valid QBA. Fixes: QTBUG-136970 Pick-to: 6.10 6.9 6.8 QUIP: 23 Change-Id: I22033fe6ab4acf8362a8183e25b92331d45cb32c Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
* Avoid a memory leak in ReferenceObject::initLuca Di Sera2025-02-261-0/+4
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | `ReferenceObject::init` currently allocates connections to certain signals to enable a reduction of the amount of reads the `ReferenceObject` needs to perform, by using the signal to identify when the data that is being represented was invalidated. In particular, when the `ReferenceObject` is part of a chain that traces back to a `Q_PROPERTY`, and that property either has a `NOTIFY` signal or is a `BINDABLE`, a connection to the signal or a subscription to the `BINDABLE` is activated. When one of those is done, we further construct a connection to the `destroyed` signal of the object that holds the property, to ensure that a read is performed and our data is invalidated if that object is destroyed. The code that performs this process, in `ReferenceObject::init`, was written with the incorrect assumption that a property either has a `NOTIFY` signal or is `BINDABLE`, but not both. In truth, a property might both have a `NOTIFY` signal and be a `BINDABLE`. When this is the case, the current code would allocate a connection to the `destroyed` signal on the same memory block twice, once when setting up a connection to the `NOTIFY` signal and once when subscribing to the `BINDABLE`, without ensuring that the previously allocated connection was disposed of. To avoid this issue, the code that takes care of setting up the connections is now exclusive between the two connections path, with a priority on the `BINDABLE` subscription, as this mirrors the already existing preference we have when dealing with bindings and is expected to be slightly more performant. The documentation for this connection process was modified to add a small mention of this priority of execution. Some defensive asserts were added to the relevant connection code, to ensure that we can catch the construction of multiple connections at once, which is to be considered a bug. The code that takes care of disposing of the `destroyed` signal connection was modified to ensure that we only take into account our allocation strategy and not our actual connection status, which, while they shouldn't generally be in discord, might incorrectly avoid a necessary disposal if they would. A comment that related to the condition for the disposal was modified to be more precise with regards to the new condition. Some test cases were added to `tst_qqmllanguage` to check the leak and `BINDABLE` preference behavior. Change-Id: Ibdc657fd857a8838797e47ff235f67cfaeec20de Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
* Avoid unnecessary read-backs on ReferenceObjectsLuca Di Sera2025-02-051-0/+157
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 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 <ulf.hermann@qt.io>
* Add some documentation for ReferenceObjectLuca Di Sera2024-11-071-0/+319
| | | | | | | | | | | | | | | ReferenceObject is currently the backbone of the the write-back mechanism. Add some basic documentation on its purpose and usages to try and reduce the complexity of approaching some of the dependent code that deals with write-backs (e.g Sequence, QQmlValueTypeWrapper, ...) and to simplify approaching a review or performing work related to write-backs, which currently still require some development. Change-Id: I56f346c29c79313ebc6181ab87b9f7369115ad83 Reviewed-by: Olivier De Cannière <olivier.decanniere@qt.io> Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
* V4: Refactor QQmlValueType{Wrapper|Reference} and QV4::SequenceUlf Hermann2022-10-131-0/+10
Every QQmlValueTypeWrapper is potentially a reference now. Since most were already before, the overhead of checking the vtables at every step was dubious at best. Extract a common base class that handles the reading and writing of object properties employed in both value type references and sequences. Task-number: QTBUG-99766 Change-Id: Idf72d9a20a52366e5c2d0dcd4b3a18072c0ccc41 Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>