aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml/jsruntime
Commit message (Collapse)AuthorAgeFilesLines
...
* QtQml: Properly null-check module exports when iteratingUlf Hermann2025-08-121-2/+2
| | | | | | | | | | | | | We construct the iterator from the exports of the module in all current code paths. Therefore, this case can't happen in the current code. Still, the fact that we have a branch that throws a reference error there tells us that it's intended to work on other collections of names, too. Let's complete the check and also check for nullptr since resolveExport can indeed return that. Coverity-Id: 486706 Change-Id: Ieaf3996e76265e9e6ef59c2168699e47e41e8ff5 Reviewed-by: Olivier De Cannière <olivier.decanniere@qt.io>
* JSRuntime: Add const correctnessOlivier De Cannière2025-08-122-5/+5
| | | | | | Change-Id: I2fc82de562909ab2e0eecfbbe1e2e53953a33756 Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io> Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
* QtQml: Optimize retrieval of string from ValueUlf Hermann2025-08-121-2/+2
| | | | | | | | stringValue() already checks isString(). We don't have to do it twice. Coverity-Id: 486710 Change-Id: I074228f9a120c3bbfe6d4a65f05fe11322fbd07b Reviewed-by: Olivier De Cannière <olivier.decanniere@qt.io>
* QtQml: std::move strings rather than copying themUlf Hermann2025-08-121-2/+2
| | | | | | | | Coverity-Id: 486699 Coverity-Id: 486697 Coverity-Id: 486715 Change-Id: Icdd15ff578f8be55fe9db3ffc38e893f667edc40 Reviewed-by: Olivier De Cannière <olivier.decanniere@qt.io>
* QtQml: Drop dead codeUlf Hermann2025-08-121-2/+0
| | | | | | | | | The propertyList is an array allocated on the JavaScript stack. None of it can be null. Coverity-Id: 486709 Change-Id: I3178181aa89bfff86fb5aa469660a912b4f1691c Reviewed-by: Olivier De Cannière <olivier.decanniere@qt.io>
* QtQml: Deduplicate enum handling in QtObject and clean up APIOlivier De Cannière2025-08-111-0/+25
| | | | | | | | | | | | | QJSValue is slow and can be avoided. Use more specific types. Also, switch to an exception based error handling instead of returning undefined. Amends 5e312953f6c41f244344bbd05a41f205a8d3f86d, found in API review Pick-to: 6.10 Change-Id: Ie7c304a0dd76c8096e7c1f9b7cc3cfe7471649da Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
* Harden namespacingTim Blechmann2025-08-088-16/+35
| | | | | | | | | | | | | | | When using namespaced Qt, we need to prevent symbol clashes with symbols of the same name. * namespace some publicly visible classes * hide classes in implementation in an anonymous namespace * rename read/write to readValue/writeValue to avoid name clash with c functions. Task-number: QTBUG-138543 Pick-to: 6.10 Change-Id: Ica77462c1f81f1e01cc60477e5b56ecfe3c1abb4 Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
* QtQml: Assert on currentStackFrame in direct eval callUlf Hermann2025-08-071-2/+12
| | | | | | | | | | | If we're called directly from a CallPossiblyDirectEval instruction, that instruction must live in a function which must have created a stack frame. Coverity-Id: 486651 Change-Id: I8136f40a8b6058ad499a7fdaaed99bf85485b11c Reviewed-by: Olivier De Cannière <olivier.decanniere@qt.io> Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
* QtQml: Allow eval() in global contextUlf Hermann2025-08-051-9/+9
| | | | | | | | | | We don't have to crash if we can't determine a function to query for strictness or if there is no explicit "this" object. Pick-to: 6.10 6.9 6.8 6.5 Fixes: QTBUG-136688 Change-Id: I541f2d906e10a7512d8364a9286885bd6afa4423 Reviewed-by: Sami Shalayel <sami.shalayel@qt.io>
* Fix typo: rename uneccessary to unnecessaryTian Shilin2025-07-241-1/+1
| | | | | | | | | The function name had a spelling error. This change improves code readability and follows Qt naming conventions. Fixes: QTBUG-138663 Change-Id: I6965c85e541b4d641a4fae938fc0ddd43e9411be Reviewed-by: Shawn Rutledge <shawn.rutledge@qt.io>
* Expose XMLHttpRequest to qmltypesFabian Kosmale2025-07-222-2/+10
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | In QML, one can use XMLHttpRequest. Not so with a plain JS engine. The reason for that lies in the fact that a JS engine did not have any network access, because all network functionality was in the type loader, and the type loader was coupled to the QV4::Engine. This has changed in d2bc4a4330254c0c68a0ade51b59a71c4b67b470, but we stil don't expose XMLHttpRequest to a plain QJSEngine. Nevertheless, it conceptually lives in the global object, and we need to collect information about it to enable code completion and linting. Consequently, expose a function in QV4::Engine, which allows us to manually trigger the registration, and call it in qmljsrootgen. Going forward, we should arguably have a QJSEngine::Extension for XMLHttpReuqest, after which we could remove the hack. Note that as before, qmljsrootgen prints a few warnings, because we call functions in contexts in which they must not be called. As before, we ignore this for now. As a side-effect, this adds a few more entries to the qmltypes file for new entries on the global Qt object. Task-number: QTBUG-137075 Pick-to: 6.10 Change-Id: I21e9d62bf075e8d4356db8f357502feb927717e7 Reviewed-by: Olivier De Cannière <olivier.decanniere@qt.io>
* Rename QV4::Value::undefindedLuca Di Sera2025-07-141-1/+1
| | | | | | | | | | | | | | | The method provides an easier construction of a QV4::Value representing the Undefined value and was thus intended to be called "undefined", as it can be inferred from the introducing patch at ac2d9bf0f2c32bdd6a64b8421c414a28369cbe2e. The current name is thus almost certainly an uncaught typo and is now renamed to the more descriptive and originally intended "undefined". The only usage site of the method was modified to use the new name. Change-Id: Ic00d910960d281c84550af3ab5ccaab52283daca Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
* QtQml: Fix leftovers from V8Ulf Hermann2025-07-113-7/+7
| | | | | | | Some comments and header guards still had V8 in them. Change-Id: I71e888fb72916fcd948a293d9fd50fb54a9499c3 Reviewed-by: Sami Shalayel <sami.shalayel@qt.io>
* Reduce access to uninitialized scoped allocationsLuca Di Sera2025-07-0818-134/+133
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | `Scope` provides a mean of performing uninitialized scoped allocations on the JS stack. This can generally be unsafe as this form of allocation temporarily leaves an element representing garbage memory on the JS stack, which could be accessed by other parts of the program. Indeed, a set of bugs related to this kind of behavior was recently solved. Hence, to reduce the surface of those kind of bugs, the usages of uninitialized scoped allocations were reduced to a minimum. The solution to the recent set of bugs related to uninitialized scoped allocations introduced a series of `construct` methods that ensure that the uninitialized allocation and the initialization of the allocated elements are performed as a single step of computation, reducing the surface for incorrect usages of those kind of allocations. The solution was expanded by the introduction of new `construct` methods that cover initialization from other types and some different means of initialization that were used around the code-base to work with uninitialized scoped allocations. Similarly, the various allocation methods in `Scope` were subsumed by the new `construct` methods, with the only remaining means of allocation being the uninitialized one that is used as a building block for the `construct` methods. In particular, `Scope` provided three forms of allocation under the various `alloc` methods. The aforementioned uninitialized allocation and an allocation that performed initialization to either the Undefined or the Empty value. The latter two forms of allocation were converted to forms of `construct`. Since they directly map to the same concept of allocation plus initialization, the conversion avoids having two names for the same concept. More specifically, the form of allocation that initialized to the Undefined value was converted to the new `constructUndefined` which keeps the same behavior. The different naming from the basic `construct` methods is justified by the different interface, which doesn't require choosing a initial value, and the different implementation which is built on the more general `construct` methods rather than the lower level allocation routines. The form of allocation that initialized to the Empty value was removed as it was found to be unused in the code-base. The converted allocation methods generally provides the same interface and behavior with the exception of always requiring the user to specify the amount of allocate objects. This is a change compared to the previous interface which allowed a zero-argument version that allocated a single element. The writer of the patch considered the additional terseness inconsequential compared to the required additional code so that the possibility was not preserved. The code related to the converted allocation forms was removed as a consequence of the conversion. The remaining uninitialized allocation form was made private, to avoid general usage outside of `Scope`, and favoring usages of the substitute `construct` methods. A comment that was related to usages of uninitialized scoped allocations was moved to the lower level `jsAlloca`, which forms the basis for those allocations and creates the abovementioned issues, where it was expanded upon. Usages of the non-uninitialized allocation forms around the code-base were modified to use the new `constructUndefined` method. Most usages of the uninitialized allocation form were modified to use the new `construct` methods that were added to replace them. Exceptions were made for those cases where the initialization routine is either very complex or depends on details that shouldn't belong to `Scope` such that they cannot be trivially encapsulated in a `construct` method. Instead, the relevant function or object was friended by `Scope` to allow accesses to the now private form of allocation. Those usages were previously checked and are supposed to be safe but should be scrutinized if they are modified or the code around them is modified. One of the friended functions, `callDatafromJs`, previously offered a default argument that was not made use of in the code-base. The default value for the argument was removed to simplify friending the function, considering the difficulty the language has with friended function with default arguments and considering that it would have required the default value to be moved out of the function definition into a forward declaration in the unrelated header that defines `Scope`. It is expected that the changes will reduce the surface of usage of uninitialized scoped allocations in favor of a slightly safer approach, make the issue that those usages can produce more apparent and generally centralize the usages as much as possible to make them easier to evaluate and keep track of. Change-Id: I351329f2c139201e0728791df6da297698170f55 Reviewed-by: Ulf Hermann <ulf.hermann@qt.io> Reviewed-by: Sami Shalayel <sami.shalayel@qt.io>
* Avoid accessing garbage memory on the js stackLuca Di Sera2025-07-032-7/+21
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | When allocating an object on the JS heap the garbage collector might be run as part of the allocation, in particular as a way to possibly make space when the memory space is starting to get filled up. When the garbage collector runs, it is possible, as part of its normal processing, that it will access the JS stack, and try to interact with the objects that are stored on it. In particular, while collecting from the JS stack, the garbage collector will need to mark all Managed objects that are found on it. When allocating on the JS stack it is possible that the allocation and the initialization of the allocated memory are performed in separate steps. When this is so, it is possible for the allocated element on the stack to represent garbage memory in between being allocated and being initialized. Since the garbage collector can inspect all elements on the stack as part of its processing, it is possible for it to inspect an element that represents garbage memory if it runs in between the allocation and initialization of that stack element. Furthermore, since each allocation might run the garbage collector, then any allocation in between the allocation and initialization of such a stack element can access garbage memory. In particular, if the garbage memory represents a pointer to a previously existing Managed object that was swept, the garbage collector might try to mark an object that shouldn't be marked. There are a few cases of this currently in the code-base. While instantiating a QML file, `QQmlObjectCreator` keeps track of objects that are created in the process, to avoid premature collection. As part of this, `ObjectInCreationGCAnchoList::trackObject` will be called, in turn allocating on an element on the js stack and then initializing it separately by the creation of `QObjectWrapper`. The creation of a `QObjectWrapper` generally allocates, such that it can incur into the above problem. As part of dealing with the JS spread operator, in particular when processing the spread element, we juggle with multiple allocation of uninitialized elements on the js stack. During this processing multiple part of the code can allocate. For example, the spread element is handled through the use of an iterator that, during its creation, might allocate as during the creation process we might convert the spread argument to object so that the iterator can deal with it, which would be the case for a spread argument that is a string. When allocating an element on the js stack that is bound to a certain scope, we sometime allow a conversion to be performed on the original element. This conversion routine might allocate, and it does do so for the currently existing conversion to a String and to an Object. The conversion routine is called after an uninitialized element is pushed on the stack, and can thus incur into the above issue. To fix the issue, an additional method was added, `construct`, that ensures that allocation and initialization happen sequentially with no allocation in-between, using an initialization value that is passed as an argument. The new method was applied to the code affected by the bug, in practice, reordering the operations in the affected cases such that the bug-producing allocations happens before the allocation on the stack such as to avoid the bug while keeping the same semantics. An exception was taken for the handling of the spread argument, which has a more complex control flow, where the solution that was used is to initialize the memory to the empty value as part of the allocation. A series of test cases showing an example of the issues were added to `tst_qv4mm`. The tests make use of the fact that we assert when we find a Managed object on the js stack that is not in use, as that is a logical error for the garbage collector, to observe the issue and are thus skipped when assertions are not enabled. Change-Id: Id478e16ee22e20e77d01fdfae9a0269d6d709892 Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
* QV4: Replace MaxSizeOf7 template with a generic fold expressionOlivier De Cannière2025-06-301-11/+4
| | | | | Change-Id: I5a9e5f75e3beee2c690630acc3632bad133e63f1 Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
* QtQml: Avoid infinite recursion in Array.joinFabian Kosmale2025-06-271-0/+1
| | | | | | | | | | | | | So far, self-referencing arrays can lead to infinite recursion in Array.join. The standard allows us to throw an exception in this case, just like we already do in ObjectPrototype.toString(). This is not what browsers do, but arguably they are diverging from the spec. Pick-to: 6.10 6.9 6.8 6.5 Fixes: QTBUG-124157 Change-Id: Iac241a90ba7e583e53f52ec635add7b5cf05b200 Reviewed-by: Ulf Hermann <ulf.hermann@qt.io> Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
* QtQml: Allow access to base object members from VariantAssociationObjectUlf Hermann2025-06-251-1/+9
| | | | | | | Pick-to: 6.10 6.9 Fixes: QTBUG-137328 Change-Id: I6bb58dc58a8e29eed4d73b51104deb4d58f4cec0 Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
* QtQml: Move ExecutionEngine in to QJSEnginePrivateUlf Hermann2025-06-242-0/+3
| | | | | | | | | | | | | | The ExecutionEngine can live without a QQmlEngine or a QJSEngine, but not vice versa. Therefore, the ExecutionEngine has to outlive QQmlEngine and QJSEngine on shutdown. Since the ExecutionEngine lives longer now, we also need to postpone the pruning of the type registry. The engine might still hold on to types after all. Task-number: QTBUG-137848 Change-Id: Ib574cac84b5f2d974cbc24ed79550a58b69a7a1c Reviewed-by: Sami Shalayel <sami.shalayel@qt.io>
* Mark QML's JSON parser as criticalFabian Kosmale2025-06-241-0/+1
| | | | | | | | | | | We're doing fully custom parsing here, and external JSON must not cause security issues. Pick-to: 6.10 6.9 6.8 QUIP: 23 Task-number: QTBUG-136970 Change-Id: I43f8280a31ebc170382485e6f5f3e7c06aa7db1a Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
* Add some missing Q_MANAGED_TYPELuca Di Sera2025-06-195-0/+15
| | | | | | | | | | | | | `ArrayData`, `MemberData` and `StringOrSymbol` are the only direct children of `Managed` that do not define their own type-tag, thus inheriting `Type_Invalid`. Both for consistency with other similar elements and as it can be useful to indiscriminately inspect the type-tag while debugging, a type-tag has been added through the use of `Q_MANAGED_TYPE` to the relevant types. Change-Id: Ia13e1d6f0adc5e8e3f8f1d27c4e36a6cb35a56f2 Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
* Add a validation mode for the garbage collectorLuca Di Sera2025-06-192-4/+10
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | A new environment variable, "QV4_MM_CROSS_VALIDATE_INCREMENTAL_GC", is introduced that turns on, when set, additional debug behavior in the GC. In particular, when the mode is enabled and the GC is running in incremental mode, after every mark phase, some additional validation will be performed to catch some amount of issues that could be introduced by the usage of the incremental garbage collector. In more details, a snapshot of which object was marked by the incremental run is stored, the mark phase of the GC is then run a second time in a stop-the-world manner. The result of the second phase is then compared to the original, making sure that supposedly bug-induced discrepancies are logged. Generally, any discrepancy should indicate something that has gone wrong in one run or the other, possibly both independently. Nonetheless, for this mode, we assume that non-incremental runs of the GC can be considered to have a baseline correctness that can be used as a verifier for the output of the mark phase of a GC run, and in particular a run of the incremental mode of the GC. A new state was added to the GC that is intended to run between the end of the mark phase and the start of the sweep phase. The implementation for the execution of the `markReady` state was modified to traverse to this new state during an incremental run when the relevant environment variable was set during the creation of a `MemoryManager` instance. The new state generally implements the algorithm described above. In particular, a copy of the black bitmaps of each allocator, which are the result of the mark phase and are enough to pinpoint which part of the memory was marked, is stored away. The relevant state that is hold by the GC, is reset to a state that allows running the mark phase again. The mark phase is then run from start to finish and the new state of the black bitmaps of each allocator is compared to the one produced by the latest run. Errors are reported when we find that the incremental run has not marked an object that was considered alive by the non-incremental run, that is, that we are going to collect an object that is still alive. Cases where the new run has found an object, that was considered to be alive by an incremental-run, to be dead, are ignored. This is due to the incremental run of a GC sometimes being unable to directly identify an unreachable object as dead, for example when allocations are performed at certain points in the incremental run. The implementation of `Managed::className` was modified by extracting the formatting part out so that it can be accessed as part of the newly added error reporting. Some documentation for the new environment variable with a brief and generic description of the new mode was added to the "Configuring the JavaScript Engine" documentation page, where similar GC-related environment variables are documented. A test was added to ensure that the specific case of discrepancies that we are interested into are caught by enabling the validation mode. To allow for the testing process itself to be performed by the fictitious introduction of bugs of the class we intend to uncover, we ensure that the entry of the new state in the relevant `GCState` enum is positioned as if it was part of the sweep phase. Normally, the state that performs the verification will need to redrain the stack to take into account changes that can have occurred between the last state and the start of the verification state, as otherwise false positives could be introduced by the partial snapshot of the black bitmaps. Nonetheless, a redrain can and should re-observe some objects that could have already been marked in precedence. When this is so, any object that is unmarked fictitiously, could be marked back again, preventing the test, which has to mutate the the state at the boundaries of the computation, from correctly observing the process. By ensuring that the validation step is performed as if "it was part of the sweep phase", it will use, during a normal run, the general redrain process that is commonly part of the execution loop (as performed by `transition`), so that the embedding of the redrain in the validation step itself can be avoided. The test can then perform the necessary run of the GC without passing by the normal execution loop, knowing that it controls when allocations are performed, so that it can introduce the necessary mutations at the boundaries without the risk of some of them being overwritten. To simplify the testing process, and in particular to avoid having to capture `qDebug` output during the test run, test-specific code that saves an intermediate state that can be used as a witness of the algorithm working correctly was added to the GC, behind the "QT_BUILD_INTERNAL" flag. Fixes: QTBUG-135064 Change-Id: If3f9ef029b51b77aaa5b68f349cbb1b20330be70 Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
* QtQml: Remove local file loading from qv4engine.cppUlf Hermann2025-06-183-117/+48
| | | | | | | | | | Scripts (including modules) shall be loaded via QQmlTypeLoader, to preserve network transparency. Since the last users of loadModule() and friends have been removed, we can now drop the relevant code. Task-number: QTBUG-19407 Change-Id: I8d5aa177266d376fb77f5b61f94ab1277b4c64c4 Reviewed-by: Sami Shalayel <sami.shalayel@qt.io>
* QtQml: Ensure that dependencies of modules are properly loadedUlf Hermann2025-06-182-21/+33
| | | | | | | | | The type loader should make sure that they are available. Prove that by wrapping all access to dependencies into an accessor that checks the dependent scripts. Change-Id: I6e0153fcb213e1a5b6ece79e3fbc0e27dc1b292c Reviewed-by: Sami Shalayel <sami.shalayel@qt.io>
* QV4::Script: Remove createFromFileOrCache()Ulf Hermann2025-06-172-54/+0
| | | | | | | | It isn't used anymore and it was bad since it unconditionally loaded from a local file, subverting the network transparency. Change-Id: I3c8d045b03a5250eb390731b9d8a8df6f74586a0 Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
* QtQml: Use QQmlScriptBlob in Qt.includeUlf Hermann2025-06-174-171/+116
| | | | | | | | | | | | | | Invent a new URL fragment "include" for this. We need to make sure the included JS code inherits the context. We want to get rid of the local file loading in qv4engine.cpp since it undermines network transparency. Qt.include therefore has to use the type loader. For remote files it so far used a hand-rolled network loading machinery which duplicated the type loader code. By using the type loader right away, this becomes unnecessary. Change-Id: Iae5c1ad764b98b101c1d90dbb78e46d3950541aa Reviewed-by: Sami Shalayel <sami.shalayel@qt.io>
* QtQml: Avoid direct file access in ECMAScript test runnerUlf Hermann2025-06-171-1/+4
| | | | | | | | | | | | | | | | | | We want the type loader to do this job rather than poorly duplicate it in the test. In particular, the local implementation didn't properly register the dependencies of loaded ECMAScript modules. So far we could only load ECMAScript modules using the type loader if their file names ended it ".mjs". The ECMAScript test suite does not follow this convention. In order to deal with that, we need to add a second characteristic. ECMAScript modules can now also be marked using a URL fragment "#module". Furthermore, since JavaScript files loaded outside any QML document get full access to the global context, we introduce another URL fragment "#global" to discern them from the same files loaded from a QML document. Change-Id: I625088335d16d5b8eeaa2673f07718367dca1605 Reviewed-by: Sami Shalayel <sami.shalayel@qt.io>
* QtQml: Register all ECMAScript module requests as dependenciesUlf Hermann2025-06-172-10/+43
| | | | | | | | | | | | | | Without this, freeUnusedTypesAndCaches() could drop dependencies of a live ECMAScript module. This would be unfortunate. Since ECMAScript modules can form cycles, we now need to clear the dependent scripts separately before clearing the compilation units. The downside of this is that actually cyclic ECMAScript modules cannot be cleared at all without clearing the whole type registry. However, this situation should be rare. Change-Id: Ib2d523f7c291bb5c472b6603bd947c3977b77b85 Reviewed-by: Sami Shalayel <sami.shalayel@qt.io>
* QtQml: Hold QQmlTypeLoader in QV4::ExecutionEngineUlf Hermann2025-06-173-28/+25
| | | | | | | | | | | ... rather than QQmlEngine. This paves the way for having the type loader attached to ExecutionEngine rather than QQmlEngine. Also, reference the execution engine in the type loader, in turn. Task-number: QTBUG-19407 Change-Id: I04e571c5c6ac5bce5e82537cb96c6940c7186f3a Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
* qv4script.cpp: Add missing QT_{BEGIN|END}_NAMESPACEUlf Hermann2025-06-131-0/+4
| | | | | Change-Id: I6293d620671851f790fbbc3739901b444da27807 Reviewed-by: Sami Shalayel <sami.shalayel@qt.io>
* QtQml: Move URL normalization to QQmlMetaTypeUlf Hermann2025-06-121-2/+2
| | | | | | | | We need it in many places and it's better to have it next to equalBaseUrls(). Also, it can be inline there. Change-Id: Ie83ad7a345a25a67f418c6cf9886ba8116f7a762 Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
* QtQml: Do not crash when registering native modules on QQmlEngineUlf Hermann2025-06-121-2/+3
| | | | | | | | | | | | We need to tell the type loader that this is an ECMAScript module since it cannot determine it from the file name. Amends commit dc60c305a20d518012d4f034c4fa2a7395ebf31f Pick-to: 6.10 6.9 6.8 Change-Id: Ie91bce86a08a81ff3df6c11d016308e3e380f15f Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io> Reviewed-by: Sami Shalayel <sami.shalayel@qt.io>
* gc: Assume less if hasConstWrapper is setFabian Kosmale2025-06-101-16/+14
| | | | | | | | | | | | | | | | | | | | | QQmlData is attached to a QObject, and consequently can't be used to track engine local state. Whether a _given_ engine has a const wrapper for a QObject is an example of such local state. False assumptions based on hasConstWrapper in turn led to asserts when using multiple engines. Fix this by changing the meaning of hasConstWrapper: It now only indicates that at some point, a given engine had created a const wrapper. If that flag is not set, we know that we can skip lookups in m_multiplyWrappedQObjects. If it is set, we can't assume anything, and have to consult our engines m_multiplyWrappedQObjects to truly know whether we have a const wrapper or not. Pick-to: 6.10 6.9 6.8 Change-Id: Id26823bdc942b227c991571334f45f45b8b109c3 Reviewed-by: Oliver Eftevaag <oliver.eftevaag@qt.io> Reviewed-by: Ulf Hermann <ulf.hermann@qt.io> Reviewed-by: Sami Shalayel <sami.shalayel@qt.io>
* Qml: Warn about using enums as type annotations in functionsOlivier De Cannière2025-06-101-2/+64
| | | | | | | | | | | | | | | | | | | | | | | | | | The warning emitted when calling functions with parameters type annotated with enums does not communicate what's wrong or how to fix it: "1 should be coerced to void because the function called is insufficiently annotated. The original value is retained. This will change in a future version of Qt." Until we support a proper representation of enums in the type system, all we can do is warn the user that this does not work. Add another warning that fires once when the function is constructed that has a better description of what is going wrong. This should provide the user with the info to solve the issue unlike the original warning. This does mean that we warn more for the same issue but it should still be beneficial overall. Task-number: QTBUG-135255 Pick-to: 6.10 6.9 6.8 6.5 Change-Id: Icd8f8d80c6a4b9bd2b33c660394b9cf5a228a346 Reviewed-by: Sami Shalayel <sami.shalayel@qt.io>
* QtQml: Only hold CU in ResolvedTypeReference where neededUlf Hermann2025-06-072-67/+32
| | | | | | | | | | | | | | | The only place that actually needs the compilation unit is the object creator. The object creator will only touch type references we need to create objects from. For everything else, the property cache and the QQmlType are good enough. Therefore, always store property cache and QQmlType in a uniform way. In turn drop the CU where we can. Task-number: QTBUG-135286 Change-Id: I1dfac132a1580679b165c2f891a8d9439fa14d1e Reviewed-by: Sami Shalayel <sami.shalayel@qt.io> Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
* QtQml: Better encapsulate QV4::ScriptUlf Hermann2025-06-053-91/+129
| | | | | | | Make members private, add accessors, add m_ to member names, etc. Change-Id: I497db10b62bbfb32f55dca227af9a518da6eaa70 Reviewed-by: Sami Shalayel <sami.shalayel@qt.io>
* QML: Turn warning into a syntax errorUlf Hermann2025-06-041-3/+8
| | | | | | | | | | | | | It has wanted to be a syntax error since Qt 5.12. [ChangeLog][QtQml] Using a bare function expression in eval() is now correctly recognized as syntax error. You have to surround it in parentheses to make it a statement. This has been generating warnings since Qt 5.11 and it should have become an error already in 5.12. Change-Id: Icb80ff62bf75d3510c43767ccc3477600af6cb63 Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io> Reviewed-by: Olivier De Cannière <olivier.decanniere@qt.io>
* VariantAssociationObject: mark own member during gcFabian Kosmale2025-06-041-0/+2
| | | | | | | | | | We were missing the DECLARE_MARKOBJECTS macro, which could lead to heap corruption if the mapping was actually in use. Pick-to: 6.10 6.9 Fixes: QTBUG-137350 Change-Id: Idd9184a3a3c35faa7caf35d0e3ac8c901f99afb7 Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
* Qml: Allow accessing unscoped enums values as <Component>.<Enum>.<Key>Olivier De Cannière2025-05-311-5/+5
| | | | | | | | | | [ChangeLog][QML] It is now possible to access unscoped enum values in a scoped way as <component name>.<enum name>.<key>. Previously, it was only possible to access them in an unscoped way. Task-number: QTBUG-116513 Change-Id: Iff56cd3365516215e1e195a147fae66ee17d39e3 Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
* QtQml: Guard against missing root property cachesUlf Hermann2025-05-222-16/+6
| | | | | | | | | | | | | | A compilation unit can be created from a script, in which case there is no property cache. We shouldn't crash then. Amends commit c1bd8ee91fd1462235d4bccbcf5286864d0fcbf7 Pick-to: 6.9 6.8 Fixes: QTBUG-137072 Change-Id: Ic10dfd7a640067639894f885496dfa13719b4bf5 Reviewed-by: Sami Shalayel <sami.shalayel@qt.io> Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io> Reviewed-by: Waqar Ahmed <waqar.ahmed@kdab.com>
* QtQml: Remove object/binding/parser status counts from CUsUlf Hermann2025-05-201-4/+0
| | | | | | | | | | | | | | Calculating those is a rather complex affair, and unlikely to pay off. Previously they were used to pre-allocate space in the object creator. We use standard containers with standard allocation strategies everywhere else. If this turns out to be an actual problem, we could record the actual numbers when we create a component and record those in the ExecutableCompilationUnit for next time. Task-number: QTBUG-135286 Change-Id: Ia44bbc9c49cbfb638f5d4bbbb345c48124e4fb09 Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
* Revert "QtQml: Remove dependency hashing"Ulf Hermann2025-05-152-0/+30
| | | | | | | | | | | This reverts commit 18c421fe6159dc921643c72ae335cf189eb1cc3a. Removing the dependency hashing is not safe because there are various other bits covered by it, not only the alias target IDs. Task-number: QTBUG-136806 Change-Id: I4a8a57d810203a47945ce67916ee5b54ee7a603d Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
* QtQml: Remove dependency hashingUlf Hermann2025-05-132-30/+0
| | | | | | | | | Since we don't store any property indices in the compilation units anymore, we don't need to hash the dependencies anymore. Task-number: QTBUG-135286 Change-Id: I2ea05c920475749f2a2d6cf309d0956a74d6c688 Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
* fix typo: QSrtingFrederik Gladhorn2025-04-131-2/+3
| | | | | | | Also make clang-format happy with the comment. Change-Id: Ia38a103dcfe01bace097ea6290bdf65494fc9282 Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
* Port away from QPairZhao Yuhang2025-04-123-14/+15
| | | | | | | | QPair is just an alias of std::pair anyway. Task-number: QTBUG-115841 Change-Id: I26fc90adcc775aac9955ad57304af914dc4ed48f Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
* Improve "could not convert argument" error messageMitch Curtis2025-04-021-1/+2
| | | | | | | | | | | | | | | | | | | | | Add the actual types involved in the attempted conversion, rather than just saying that it couldn't be done. Before: "Could not convert argument 0 at" "expression for onCompleted@qrc:/qt/qml/quick2/Main.qml:34" qrc:/qt/qml/quick2/Main.qml:34: TypeError: Passing incompatible arguments to C++ functions from JavaScript is not allowed. After: "Could not convert argument 0 from QQmlComponent(0x5b72731bd710) to QQuickItem*" "expression for onCompleted@qrc:/qt/qml/quick2/Main.qml:34" qrc:/qt/qml/quick2/Main.qml:34: TypeError: Passing incompatible arguments to C++ functions from JavaScript is not allowed. Pick-to: 6.8 6.9 Change-Id: Ia4144ad61332e53c662a280dd8b68dc99aa09cf8 Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
* QtQml: Don't use bindables for bindings on value type aliasesUlf Hermann2025-03-241-4/+9
| | | | | | | | | | | | | | | | | | | | | | Forwarding the bindability of aliases is a complicated affair because a single alias can encompass two properties (the "core" and the "value type" property). This change adds another flag to discern between "can use the bindable for notifications" and "can install a QBinding on this property". Those are different aspects. Deep aliases can still notify via the bindable of the core property, but they cannot accept a QBinding. Accordingly, when querying the metaobject for a bindable of a value type alias, return the bindable of the core property. This is the one you at least meaningfully install an observer on. The bindable of the value type property would be entirely useless. Amends commit 1f40e12a844ca2939c86f19610590920841efb15. Pick-to: 6.9 6.8 6.5 Task-number: QTBUG-134688 Change-Id: Ib219657bcbd2e263285d54f8736cada74ac594f5 Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
* QV4::ForInIteratorObject::nextProperty: fix null pointer dereferenceDavid Faure2025-03-181-1/+1
| | | | | | | | | | | | | | | | UBSAN says /opt/workspace/qtsrc/qtdeclarative/src/qml/jsruntime/qv4object_p.h:105:5: runtime error: member access within null pointer of type 'struct Object' #0 0x7fdead25f886 in QV4::Object::d() const /opt/workspace/qtsrc/qtdeclarative/src/qml/jsruntime/qv4object_p.h:105 #1 0x7fdead6c2ba5 in QV4::ForInIteratorObject::nextProperty() const /opt/workspace/qtsrc/qtdeclarative/src/qml/jsruntime/qv4objectiterator.cpp:162 and indeed the if (!c) just after this line indicates that c can be null. Pick-to: 6.9 6.8 6.5 Change-Id: I3124ccf7aeebf4594d316b1d81c001638c290e24 Reviewed-by: Olivier De Cannière <olivier.decanniere@qt.io> Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io> Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
* QJSEngine: Trim compilation units after evaluating a programOlivier De Cannière2025-03-122-1/+13
| | | | | | | | | | | | | | | Not doing so might lead them to accumulate until the js engine is destroyed. We only trim compilation units with the final url that was passed in to evaluate. This way, we prevent accumulation while also preserving compilation units from actual files. Fixes: QTBUG-132931 Pick-to: 6.9 6.8 Change-Id: Ie4f09287e293075de4940ced6146a862c4da3b5b Reviewed-by: Ulf Hermann <ulf.hermann@qt.io> Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
* QtQml: Add sticky bit to QQmlAbstractBindingUlf Hermann2025-03-111-2/+5
| | | | | | | | | | | QUntypedPropertyBinding has a sticky bit already. We need the same in QQmlAbstractBinding so that we can create bindings that don't break if you write to their targets. Task-number: QTBUG-132420 Change-Id: Ia5fa21120722ce1f8b1088a85b9b57405ab3b57d Reviewed-by: Sami Shalayel <sami.shalayel@qt.io> Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>