aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml/jit
Commit message (Collapse)AuthorAgeFilesLines
* Remove the bootstrap code from assembler and JITUlf Hermann2019-05-071-1/+1
| | | | | | | We don't build the assembler or the JIT in bootstrap mode. Change-Id: Idc3a56cc1e9cfba415bef9cba221c8a60ee75010 Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
* Make JavaScript execution interruptibleUlf Hermann2019-04-303-0/+11
| | | | | | | | | | | Add an atomic isInterrupted flag to BaseEngine and check that in addition to the hasException flag on checkException(). Add some more exception checks to cover all possible infinite loops. Also, remove the writeBarrierActive member from QV4::EngineBase. It isn't used. Fixes: QTBUG-49080 Change-Id: I86b3114e3e61aff3e5eb9b020749a908ed801c2b Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
* Remove tracing JIT infrastructureUlf Hermann2019-04-2928-9297/+58
| | | | | | | | The tracing JIT won't be finished. Therefore, remove the parts that have already been integrated. Change-Id: If72036be904bd7fc17ba9bcba0a317f8ed6cb30d Reviewed-by: Erik Verbruggen <erik.verbruggen@me.com>
* Transform V4_ENABLE_JIT into a featureUlf Hermann2019-04-256-18/+4
| | | | | | | | | | | | | | | | This way you can enable or disable the JIT when configuring Qt. The conditions for the availability of the JIT have also been cleaned up. There is no reason anymore to artificially restrict availability on x86 and x86_64. The reason for the existence of those clauses are old problems on windows that have been fixed by now. However, on arm and arm64, we need a specialization of the cacheFlush() function for each OS to be supported. Therefore, restrict to the systems for which such a specialization exists. iOS and tvOS are technically supported and you can enable the JIT via the feature flag now. Due to Apple's policy we disable it by default, though. Change-Id: I5fe2a2bf6799b2d11b7ae7c7a85962bcbf44f919 Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
* JIT: Avoid QString::sprintf()Ulf Hermann2019-04-172-3/+3
| | | | | | | It's deprecated Change-Id: Id901056e3a4ca378fb03486cd941e7e7222ffbc4 Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
* V4 tracing: Add a scheduler for the tracing JIT IRErik Verbruggen2019-03-2814-21/+3559
| | | | | | | | | | | | | | | | | | This is a scheduler for the graph nodes, which first reconstructs the control-flow graph, and then places all remaining nodes inside the basic blocks. The output of this pass is an MIFunction (MI = Machine Interface), which uses a representation suitable for feeding to an assembler. Note however that it still uses "virtual registers" at this point, so the next pass will have to place those virtual registers in physical registers or on a stack. The code for the dominator tree calculation, block scheduling, loop info and the blockset were lifted from the 5.10 JIT. Change-Id: I11c4cc3f64fedba6dd4275b35bbea85d30d76f7d Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
* V4: Add a lowering pass to the traced JITErik Verbruggen2019-03-224-1/+315
| | | | | | | | | | This pass converts high-level operations like e.g. a JSAdd to lower level operations, like a runtime call. This pass will be extended to take trace information, which can indicate that it can be lowered to e.g. an AddInt32. Change-Id: Ieae8df235217189c90048515e199f7e7c7f220b3 Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
* Merge remote-tracking branch 'origin/5.13' into HEADUlf Hermann2019-03-227-223/+48
|\ | | | | | | | | | | | | | | | | | | | | | | | | | | Conflicts: src/qml/compiler/qv4compileddata_p.h src/qml/jit/qv4baselinejit.cpp src/qml/jit/qv4jithelpers.cpp src/qml/jsruntime/qv4lookup.cpp src/qml/jsruntime/qv4runtime.cpp src/qml/jsruntime/qv4runtimeapi_p.h src/qml/jsruntime/qv4vme_moth.cpp src/qml/qml/qqmltypemodule_p.h Change-Id: If28793e9e08418457a11fc2c5832f03cab2fcc76
| * Merge remote-tracking branch 'origin/5.12' into 5.13Qt Forward Merge Bot2019-03-215-126/+42
| |\ | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Conflicts: src/qml/compiler/qqmltypecompiler.cpp src/qml/compiler/qv4bytecodehandler.cpp src/qml/compiler/qv4codegen.cpp src/qml/compiler/qv4compileddata_p.h src/qml/compiler/qv4compiler.cpp src/qml/compiler/qv4instr_moth.cpp src/qml/compiler/qv4instr_moth_p.h src/qml/jit/qv4baselinejit.cpp src/qml/jit/qv4baselinejit_p.h src/qml/jsruntime/qv4function.cpp src/qml/jsruntime/qv4vme_moth.cpp Change-Id: I8fb4d6f19677bcec0a4593b250f2eda5ae85e3d2
| | * Remove dead compile time QML context/scope property and id object codeSimon Hausmann2019-03-202-116/+0
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | After enabling lookups in QML files, we can remove all the code that tries to deal with (type) compile time detection of access to id objects and properties of the scope/context object. This also allows removing quite a bit of run-time code paths and even byte code instructions. Task-number: QTBUG-69898 Change-Id: I7b26d7983393594a3ef56466d3e633f1822b76f4 Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
| | * Implement dummy QML lookups for "global" variablesSimon Hausmann2019-03-204-0/+31
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | When resolving names in the context of QML bindings, we now direct runtime access to QQmlContextWrapper::resolveQmlPropertyLookupGetter. At the moment this does basically the same as Runtime::method_loadName, which we called earlier. However this now provides the opportunity to optimize lookups in the QML context in a central place. When performing a call on a scope or context object property, we also did not use a CallName() instruction - which would have gotten the thisObject wrong - but instead we use a dedicated CallScopeObjectProperty and CallContextObjectProperty instruction. These rely on identifying these properties at compile time, which goes away with lookups (and also doesn't work when using ahead-of-time compilation). Therefore the qml context property lookup is using a getPropertyAndBase style signature and Runtime::method_callQmlContextPropertyLookup uses that. For the tests to pass, some error expectations need adjusting. In particular the compile-time detection of write attempts to id objects is now delayed to the run-time. The old code path is still there and will be removed separately in the next commit (as it is massive). Task-number: QTBUG-69898 Change-Id: Iad1ff93d3758c4db984a7c2d003beee21ed2275c Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
| | * Baseline JIT: Save accumulator in toInt32LhsAcc()Ulf Hermann2019-03-191-16/+16
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | toInt32LhsAcc convertes both the lhs and the accumulator to int32. If the accumulator is not saved, a GC run during the conversion of the lhs might trash its value. Fixes: QTBUG-74058 Change-Id: Ic42693061c7d483bb430d77bcc095de6ff9a6843 Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
* | | V4: Add trace slot for UPlusErik Verbruggen2019-03-224-4/+4
| | | | | | | | | | | | | | | Change-Id: I0bb5055024e30c32b82e1555c820ea5ced8923f5 Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
* | | V4: Add IR that can use traced information to JITErik Verbruggen2019-03-0413-0/+5474
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | This is the in a series of patches for a JIT that can use traced information to generate better code. In this patch, traced information is not used/stored yet. It allows testing the basic infrastructure without trying to do any optimizations, therefore making it easier to debug, test, and review. Change-Id: I589bdadf731c36542331abe64e1b39e305b6723e Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
* | | Merge remote-tracking branch 'origin/5.13' into devQt Forward Merge Bot2019-02-162-11/+6
|\| | | | | | | | | | | Change-Id: I51cb42d253a83c0e6a76946c37cf1ff7c7cac150
| * | Merge remote-tracking branch 'origin/5.12' into 5.13Qt Forward Merge Bot2019-02-152-11/+6
| |\| | | | | | | | | | | | | | | | | | | Conflicts: src/qml/qml/qqmlpropertycache.cpp Change-Id: Ie7727499700b85cc0959ef3abb30d55dc728b659
| | * V4: Fix JS tail call crashes on win32/linux32Erik Verbruggen2019-02-142-11/+6
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | For platforms where arguments are passed on the stack, we would do an invalid (off-by-one) calcultion to see where we should put arguments for a tail call, thereby overwriting other values. As we don't write to these memory locations anywhere, and the arguments are exactly the same as calls to jitted code (which is done by design), we could just as well re-use them. Change-Id: If4118b2023da6dc301252a1579a36df0e0cbc3a5 Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
* | | V4: Clean up the runtime functions declarationsErik Verbruggen2019-02-056-436/+126
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | The declarations and usage of runtime functions have seen a number of changes: - we don't use the array of method pointers anymore because we don't use cross-platform AOT JITting - the check if a method can throw a JS exception was invalid, and was not used anymore - value-pointer vs. const-value-ref was inconsistent This patch cleans that up. By fixing the exception checking, we can now use it in the baseline JIT to automatically insert those checks. To make that work correctly, all runtime methods are in a struct, which gets annotated to indicate if that method throws. (The old way of checking which type of engine was used is fragile: some non-throwing methods do not take an engine parameter at all, and those got flagged as throwing). By using a struct, we can also get rid of a bunch of interesting macros. The flags in the struct (as mentioned above) can later be extended to capture more information, e.g. if a method will change the context. Change-Id: I1e0b9ba62a0bf538eb728b4378e2678136e29a64 Reviewed-by: Lars Knoll <lars.knoll@qt.io>
* | | V4: Change ByteCodeHandler::startInstruction to return an enumErik Verbruggen2019-02-012-2/+3
|/ / | | | | | | | | | | | | | | | | | | | | If ProcessInstruction is returned, the generate_* function and endInstruction will be called. If SkipInstruction is returned, they won't be called. This can be used by subclasses that can detect dead code, to suppress handling that code. Change-Id: I3b4a8eebb5701f287c8199bd40bc63fe04a35007 Reviewed-by: Ulf Hermann <ulf.hermann@qt.io> Reviewed-by: Eirik Aavitsland <eirik.aavitsland@qt.io>
* | V4: Move relative-to-absolute offset calculation to base classErik Verbruggen2019-01-312-11/+26
| | | | | | | | | | | | | | Now other subclasses of the BytecodeHandler can also use the method. Change-Id: Ib1a19e5ef6beb6c62b6a0214a6658f57b7e74a1a Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
* | V4: Generate labels for backward jumpsErik Verbruggen2019-01-315-28/+35
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | When analyzing the bytecode from top-to-bottom in a single pass, we don't know when a jump back to previously seen code occurs. For example, in the baseline JIT we would already have generated code for some bytecode when we see a jump back (like at the end of a loop body), and we can't go back and insert a label to jump to. As JavaScript has no goto's, the only backward jumps are at the end of loops, so there are very few cases where we need to actually generate labels. This was previously handled by analyzing the bytecode twice: once to collect all jump targets, and then second pass over the bytecode to do the actual JITting (which would use the jump targets to insert labels). We can now do that with one single pass. So the trade-off is to store 4 bytes more per function plus 4 bytes for each loop, instead of having to analyze all functions only to find where all jumps are each time that function is JITted. Change-Id: I3abfcb69f65851a397dbd4a9762ea5e9e57495f6 Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
* | V4: Collect trace information in the interpreterErik Verbruggen2019-01-256-57/+77
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Collect type information about values used in a function. These include all parameters, and the results of many bytecode instructions. For array loads/stores, it also tracks if the access is in-bounds of a SimpleArrayData. Collection is only enabled when the qml-tracing feature is turned on while configuring. In subsequent patches this is used to generated optimized JITted code. Change-Id: I63985c334c3fdc55fca7fb4addfe3e535989aac5 Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
* | V4: Change assembler dumping to use a logging categoryErik Verbruggen2019-01-111-2/+7
| | | | | | | | | | | | | | | | This includes removal of the QV4_SHOW_ASM environment variable. Change-Id: Ibbaf7f6eabd1b66e8539bcbcc3febdd79742e003 Reviewed-by: Ulf Hermann <ulf.hermann@qt.io> Reviewed-by: Lars Knoll <lars.knoll@qt.io>
* | Merge remote-tracking branch 'origin/5.12' into devQt Forward Merge Bot2019-01-102-13/+33
|\| | | | | | | | | | | | | Conflicts: .qmake.conf Change-Id: I6b2539bf17d3e9bc66d96b53c1bce95680113ed8
| * V4: Fix stack alignment in JITted codeErik Verbruggen2019-01-102-13/+33
| | | | | | | | | | | | | | | | | | | | | | Helper calls done for to-integer and to-number conversions did not align the stack on 16byte boundaries, which could lead to crashes if somewhere in that call a vector instruction is used that expects such alignment. Task-number: QTBUG-71325 Change-Id: Ieec05a93a1f69b538e6c8930b8eb64cbe85c35d4 Reviewed-by: Jüri Valdmann <juri.valdmann@qt.io> Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
* | V4: Generate function tables on 64bit windowsUlf Hermann2018-12-031-37/+7
|/ | | | | | | | | | | | | | In order for global exception handlers to be called reliably, the runtime needs to unwind through JIT-generated code. This can be facilitated by installing a "function table" for each JITed function that specifies "use the frame pointer". Also make sure to generate a function table for JIT'ed regular expressions. Those were forgotten also in the linux case. Fixes: QTBUG-50061 Change-Id: Ib0b8ae9356ed80afe1cab017e36efa4ccbe73f90 Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
* Merge remote-tracking branch 'origin/5.12.0' into 5.12Qt Forward Merge Bot2018-11-161-4/+4
|\ | | | | | | Change-Id: I7623438dde316ae1e97802f91991f2e7ccc205a5
| * V4: Fix 32bit moveReg to not use the return value registersErik Verbruggen2018-11-061-4/+4
| | | | | | | | | | | | | | | | | | | | | | As with the 64bit implementation: use the scratch register. The return value register is used to hold the newly allocated space on the JS stack. Fixes: QTBUG-71319 Change-Id: Ia924ad24ff7f4fbf5ec21b6e6237cce7d907bf3e Reviewed-by: Simon Hausmann <simon.hausmann@qt.io> Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
* | Create proper template objects for tagged templatesLars Knoll2018-11-052-0/+10
|/ | | | | | | | If a tagged template gets evaluated multiple times, the underlying template object is shared. Change-Id: Ie2f476fbc93d5991322ce1087c42719a8d8333ae Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
* Make sure not to clobber tail call arguments when unrolling stackErik Verbruggen2018-11-011-3/+6
| | | | | | | | | | | | | When the accumulator doesn't overlap the return value registers, we move the accumulator value there when doing a function exit. This happens for arm32 and arm64. This is a problem when doing a tail call: these registers are also used to store the first two arguments for the call, so restorating will wipe them. Task-number: QTBUG-71212 Change-Id: Ifd82729e8741418c1b54e804724893e02bd180c7 Reviewed-by: Ulf Hermann <ulf.hermann@qt.io> Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
* Revert "BaselineJIT: slightly improve arm codegen for shifts"Lars Knoll2018-10-151-3/+6
| | | | | | | | | This reverts commit 41e15cb21c2f8924eee56aacc4ba8aace950cae5. The patch causes us to hit assertions in the x86/x64 JIT. Somehow this slipped through CI. Change-Id: Ia77ecb956472172bf5543c01fdccd6dddedba168 Reviewed-by: Erik Verbruggen <erik.verbruggen@qt.io>
* BaselineJIT: slightly improve arm codegen for shiftsv5.12.0-beta2Erik Verbruggen2018-10-121-6/+3
| | | | | Change-Id: I7327f982d11a0d2942750ebfbc9f0d379093b87e Reviewed-by: Lars Knoll <lars.knoll@qt.io>
* Make the function name printing the same when dumping bytecodeErik Verbruggen2018-10-121-1/+1
| | | | | | | | So searching for "function blah" will find both the dumped bytecode and the generated assembler from the baseline JIT. Change-Id: Ia1e2debfb73068a1692653f304146f7b0f88aa16 Reviewed-by: Lars Knoll <lars.knoll@qt.io>
* V4: Conform method_objectLiteral arguments to equal other methodsErik Verbruggen2018-10-121-2/+2
| | | | | | | This runtime function was the only one taking argc before arguments. Change-Id: If0b049697f7fcc2746e8d287193a5b1230a6ea56 Reviewed-by: Lars Knoll <lars.knoll@qt.io>
* ES7: Implement Tail Position Calls in the runtimeErik Verbruggen2018-10-055-22/+124
| | | | | Change-Id: If1629109722496b3fd10b36b2376548440f2fee9 Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
* ES7: Detect Tail Position Calls and pass that to the runtimeErik Verbruggen2018-10-042-0/+14
| | | | | | | Doing the tail call in the runtime will come in a follow-up patch Change-Id: I8224aac0edbdc765ee9b97703948edd52fd33f3e Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
* Remove unused variable 'EmptyTag'Liang Qi2018-09-271-1/+0
| | | | | Change-Id: I5970e3261a8a0891965c99d4d8c352ebf4cc6681 Reviewed-by: Erik Verbruggen <erik.verbruggen@qt.io>
* Cleanups in Value/PrimitiveLars Knoll2018-09-172-6/+6
| | | | | | | | | | | | Get rid of Primitive and move the corresponding methods directly into Value. Mark many methods in Value as constexpr and turn Value into a POD type again. Keep Primitive as a pure alias to Value for source compatibility of other modules that might be using it. Change-Id: Icb47458947dd3482c8852e95782123ea4346f5ec Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
* Optimize the JIT helpersLars Knoll2018-09-143-14/+24
| | | | | | | | | Match the argument order to the lookup functions being called to minimize register shuffling that needs to be done inside the function. Change-Id: I0c55234d0c86b524dad021a519c6416d62d34c52 Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
* Add support for yield*Lars Knoll2018-09-072-0/+20
| | | | | Change-Id: I5b054b59519ed825459a5b0b0a7cd2c6fc8a3797 Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
* Throw a type error when trying to destructure null or undefinedLars Knoll2018-09-074-0/+19
| | | | | Change-Id: Id1bba1a729124bccb8a90dcf40252fe5c69d27a3 Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
* Fix exception handling while destructuringLars Knoll2018-09-072-2/+3
| | | | | | | | | | | | | | | When an exception happens during destructuring, IteratorClose needs to be called, unless the exception happened inside the IteratorNext call (in that case the iterator is assumed to be invalid and we shouldn't call close on it). Implement this, by ensuring that we set the done return variable of IteratorNext to true whenever IteratorNext throws an exception. IteratorClose will check the done state and not do anything in that case. Change-Id: I73a27f855f2c4d3134b8cc8980e64bf797d03886 Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
* Fix thisObject when calling super propertiesLars Knoll2018-08-312-0/+14
| | | | | Change-Id: Ia520d43ea2c29c16cfc8ffc86a32187a78848502 Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
* V4: Add JIT kind to disassemblyErik Verbruggen2018-08-303-4/+4
| | | | | Change-Id: I6dd1cd6f795a93a186e84f5ab1c606f7e23fb85d Reviewed-by: Lars Knoll <lars.knoll@qt.io>
* Initialize this to empty for derived constructorsLars Knoll2018-08-293-12/+1
| | | | | | | | | As per spec, this should be uninitialized in derived constructors, and the base constructor needs to get called exactly once. Change-Id: If31804e58d7ba62efde8fbf6cd852674f8da4495 Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
* Implement the dead temporal zoneSimon Hausmann2018-08-284-0/+38
| | | | | | | | | | | | | | With const and let it is possible to access the declared member before initialization. This is expected to throw a type reference error at run-time. We initialize such variables with the empty value when entering their scope and check upon access for that. For locals we place the lexically scoped variables at the end. For register allocated lexical variables we group them into one batch and remember the index/size. Change-Id: Icb493ee0de0525bb682e1bc58981a4dfd33f750e Reviewed-by: Lars Knoll <lars.knoll@qt.io>
* V4: Split PlatformAssemblerCommon (and base classes) in its own fileErik Verbruggen2018-08-277-1087/+1396
| | | | | | | | This makes it easier to re-use them later on, without inheriting all extra stuff that the baseline JIT needs. Change-Id: I9368b16017b8b9d99f8c005a5b47ec9f9ed09fb0 Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
* Implement IsConstructor for Function objectsLars Knoll2018-08-231-1/+3
| | | | | | | | Use the jsConstruct member in the function object for this and set it to a nullptr for methods that are not a constructor. Change-Id: I63d2971b23b2596a8e3b6d2781f0d9ed3208693b Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
* V4: clarify current vs. next instruction offset in ByteCodeHandlerErik Verbruggen2018-08-202-10/+13
| | | | | | | | | | | | | | | When executing an interpreter instruction, the code pointer points to the next instruction. However, sometimes a pointer to the current instruction is needed. That was hacked-around by having startInstruction be called before updating the pointer. This is confusing and leads to unexpected off-by-one-instruction cases. So now during startInstruction calls and generate_instructionName calls, there is a currentInstructionOffset() and a nextInstructionOffset() that do what's on the tin in both places. Change-Id: Ie8dd35ff0a7d236f008030ef4c29ec3f31c07349 Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
* Add initial basic support for ES6 modulesSimon Hausmann2018-08-094-0/+17
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | The entry point from the parsing perspective into modules is not QV4::Script but QV4::ExecutionEngine::compileModule. For convenience, the ESModule AST node gets a body, which is the statement list connected between the ModuleItemList items that are not import/export declarations. The QV4::Module allocates a call context where the exported variables are stored as named locals. This will also become the module namespace object. The imports in turn is an array of value pointers that point into the locals array of the context of the imported modules. The default module loading in ExecutionEngine assumes the accessibility of module urls via QFile (so local file system or resource). This is what qmljs also uses and QJSEngine as well via public API in the future. The test runner compiles the modules manually and injects them, because they need to be compiled together with the test harness code. The QML type loader will the mechanism for injection in the future for module imports from .qml files. Change-Id: I93be9cfe54c651fdbd08c5e1d22d58f47284e54f Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org> Reviewed-by: Lars Knoll <lars.knoll@qt.io>