aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml/jsruntime/qv4engine.cpp
diff options
context:
space:
mode:
authorUlf Hermann <ulf.hermann@qt.io>2025-06-06 10:45:37 +0200
committerUlf Hermann <ulf.hermann@qt.io>2025-06-17 18:44:42 +0200
commitf26af148f4ad84f07c193c4200a686e490c60cb5 (patch)
treec0d1861f8267fce1faa2c14ce71ea42c21dec00f /src/qml/jsruntime/qv4engine.cpp
parent9cc23ca91c404f24fff3c36e8c9425ae674f341d (diff)
QtQml: Register all ECMAScript module requests as dependencies
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>
Diffstat (limited to 'src/qml/jsruntime/qv4engine.cpp')
-rw-r--r--src/qml/jsruntime/qv4engine.cpp51
1 files changed, 41 insertions, 10 deletions
diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp
index 1f27ca1f1e..afb4355af9 100644
--- a/src/qml/jsruntime/qv4engine.cpp
+++ b/src/qml/jsruntime/qv4engine.cpp
@@ -13,6 +13,7 @@
#include <private/qqmljsdiagnosticmessage_p.h>
#include <private/qqmllist_p.h>
#include <private/qqmllistwrapper_p.h>
+#include <private/qqmlscriptdata_p.h>
#include <private/qqmltypeloader_p.h>
#include <private/qqmltypewrapper_p.h>
#include <private/qqmlvaluetype_p.h>
@@ -2051,6 +2052,9 @@ QQmlRefPointer<ExecutableCompilationUnit> ExecutionEngine::compileModule(const Q
{
QQmlMetaType::CachedUnitLookupError cacheError = QQmlMetaType::CachedUnitLookupError::NoError;
const DiskCacheOptions options = diskCacheOptions();
+
+ QQmlRefPointer<ExecutableCompilationUnit> cu;
+
if (const QQmlPrivate::CachedQmlUnit *cachedUnit = (options & DiskCache::Aot)
? QQmlMetaType::findCachedCompilationUnit(
url,
@@ -2059,24 +2063,40 @@ QQmlRefPointer<ExecutableCompilationUnit> ExecutionEngine::compileModule(const Q
: QQmlMetaType::RequireFullyTyped,
&cacheError)
: nullptr) {
- return executableCompilationUnit(
+ cu = executableCompilationUnit(
QQml::makeRefPointer<QV4::CompiledData::CompilationUnit>(
cachedUnit->qmlData, cachedUnit->aotCompiledFunctions, url.fileName(),
url.toString()));
- }
+ } else {
- QFile f(QQmlFile::urlToLocalFileOrQrc(url));
- if (!f.open(QIODevice::ReadOnly)) {
- throwError(QStringLiteral("Could not open module %1 for reading").arg(url.toString()));
- return nullptr;
+ QFile f(QQmlFile::urlToLocalFileOrQrc(url));
+ if (!f.open(QIODevice::ReadOnly)) {
+ throwError(QStringLiteral("Could not open module %1 for reading").arg(url.toString()));
+ return nullptr;
+ }
+
+ const QDateTime timeStamp = QFileInfo(f).lastModified();
+
+ const QString sourceCode = QString::fromUtf8(f.readAll());
+ f.close();
+
+ cu = compileModule(url, sourceCode, timeStamp);
}
- const QDateTime timeStamp = QFileInfo(f).lastModified();
+ const auto baseCompilationUnit = cu->baseCompilationUnit();
+ const auto data = cu->unitData();
+ for (uint i = 0, end = data->moduleRequestTableSize; i < end; ++i) {
+ cu->baseCompilationUnit()->dependentScripts.append(scriptDataForDependency(
+ loadModule(cu->urlAt(data->moduleRequestTable()[i]), cu.data())));
+ }
- const QString sourceCode = QString::fromUtf8(f.readAll());
- f.close();
+ // Only register with the type registry when the dependentScripts are ready!
+ // Otherwise we get thread safety problems.
+ baseCompilationUnit->qmlType = QQmlMetaType::findCompositeType(
+ url, baseCompilationUnit, QQmlMetaType::JavaScript);
+ QQmlMetaType::registerInternalCompositeType(baseCompilationUnit);
- return compileModule(url, sourceCode, timeStamp);
+ return cu;
}
@@ -2156,6 +2176,17 @@ void ExecutionEngine::trimCompilationUnitsForUrl(const QUrl &url)
}
}
+QQmlRefPointer<QQmlScriptData> ExecutionEngine::scriptDataForDependency(
+ const ExecutionEngine::Module &dependency)
+{
+ QQmlRefPointer<QQmlScriptData> scriptData(
+ new QQmlScriptData, QQmlRefPointer<QQmlScriptData>::Adopt);
+ scriptData->url = dependency->finalUrl();
+ scriptData->urlString = dependency->finalUrlString();
+ scriptData->m_precompiledScript = dependency->baseCompilationUnit();
+ return scriptData;
+}
+
template<typename NotFound>
ExecutionEngine::Module doFindModule(
const QMultiHash<QUrl, QQmlRefPointer<ExecutableCompilationUnit>> &compilationUnits,