aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorUlf Hermann <ulf.hermann@qt.io>2024-09-25 14:45:39 +0200
committerQt Cherry-pick Bot <cherrypick_bot@qt-project.org>2024-09-28 01:28:04 +0000
commit3aedb6a017d96221f7707827a0501102df0bdf23 (patch)
treead0a5d09c69536bb709423ff496afd2cc7a7587e
parentfafd134e79d659dcae97f704fbd6f4c2ea0db9b7 (diff)
QtQml: Disable AOT compiled code when QML-previewing6.7
We cannot replace AOT-compiled compilation units while an object is still holding on to them and we cannot delete all objects holding on to a CU because they might not belong to the preview to begin with. Pick-to: 6.5 Fixes: QTBUG-129329 Change-Id: Icbcb7822be770a440f3216955c0ae51151390e17 Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io> (cherry picked from commit 9a9a2184cefb777457984c965416c7ebf4c22e1a) Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org> (cherry picked from commit 18a066a0bdf65d20cdb230c54d4014beaf77b649)
-rw-r--r--src/plugins/qmltooling/qmldbg_preview/qqmlpreviewservice.cpp9
-rw-r--r--src/qml/jsruntime/qv4engine.cpp13
-rw-r--r--src/qml/jsruntime/qv4engine_p.h2
-rw-r--r--tests/auto/qml/debugger/qqmlpreview/tst_qqmlpreview.cpp40
4 files changed, 58 insertions, 6 deletions
diff --git a/src/plugins/qmltooling/qmldbg_preview/qqmlpreviewservice.cpp b/src/plugins/qmltooling/qmldbg_preview/qqmlpreviewservice.cpp
index 336395b131..5f69dc1ad2 100644
--- a/src/plugins/qmltooling/qmldbg_preview/qqmlpreviewservice.cpp
+++ b/src/plugins/qmltooling/qmldbg_preview/qqmlpreviewservice.cpp
@@ -120,8 +120,13 @@ void QQmlPreviewServiceImpl::engineAboutToBeRemoved(QJSEngine *engine)
void QQmlPreviewServiceImpl::stateChanged(QQmlDebugService::State state)
{
- m_fileEngine.reset(state == Enabled ? new QQmlPreviewFileEngineHandler(m_loader.data())
- : nullptr);
+ if (state == Enabled) {
+ QV4::ExecutionEngine::setPreviewing(true);
+ m_fileEngine.reset(new QQmlPreviewFileEngineHandler(m_loader.data()));
+ } else {
+ QV4::ExecutionEngine::setPreviewing(false);
+ m_fileEngine.reset();
+ }
}
void QQmlPreviewServiceImpl::forwardRequest(const QString &file)
diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp
index dd70e84dcc..0e51e7b143 100644
--- a/src/qml/jsruntime/qv4engine.cpp
+++ b/src/qml/jsruntime/qv4engine.cpp
@@ -105,7 +105,8 @@ using namespace QV4;
// odd while the statics are being initialized, and stays even afterwards.
// Any further engines created while the statics are being initialized busy-wait until engineSerial
// is even.
-static QBasicAtomicInt engineSerial = Q_BASIC_ATOMIC_INITIALIZER(1);
+Q_CONSTINIT static QBasicAtomicInt engineSerial = Q_BASIC_ATOMIC_INITIALIZER(1);
+Q_CONSTINIT static QBasicAtomicInt hasPreview = Q_BASIC_ATOMIC_INITIALIZER(0);
int ExecutionEngine::s_maxCallDepth = -1;
int ExecutionEngine::s_jitCallCountThreshold = 3;
int ExecutionEngine::s_maxJSStackSize = 4 * 1024 * 1024;
@@ -890,6 +891,12 @@ void ExecutionEngine::setProfiler(Profiling::Profiler *profiler)
Q_ASSERT(!m_profiler);
m_profiler.reset(profiler);
}
+
+void ExecutionEngine::setPreviewing(bool enabled)
+{
+ hasPreview.storeRelease(enabled);
+}
+
#endif // QT_CONFIG(qml_debug)
void ExecutionEngine::initRootContext()
@@ -2206,7 +2213,9 @@ ExecutionEngine::DiskCacheOptions ExecutionEngine::diskCacheOptions() const
return DiskCache::Disabled;
static const DiskCacheOptions options = qmlGetConfigOption<
DiskCacheOptions, transFormDiskCache>("QML_DISK_CACHE");
- return options;
+ return hasPreview.loadAcquire()
+ ? (options & ~DiskCacheOptions(DiskCache::Aot)) // Disable AOT if preview enabled
+ : options;
}
void ExecutionEngine::callInContext(QV4::Function *function, QObject *self,
diff --git a/src/qml/jsruntime/qv4engine_p.h b/src/qml/jsruntime/qv4engine_p.h
index 8ab3d62311..ebbb0b37f4 100644
--- a/src/qml/jsruntime/qv4engine_p.h
+++ b/src/qml/jsruntime/qv4engine_p.h
@@ -527,12 +527,14 @@ public:
void setDebugger(Debugging::Debugger *) {}
void setProfiler(Profiling::Profiler *) {}
+ static void setPreviewing(bool) {}
#else
QV4::Debugging::Debugger *debugger() const { return m_debugger.data(); }
QV4::Profiling::Profiler *profiler() const { return m_profiler.data(); }
void setDebugger(Debugging::Debugger *debugger);
void setProfiler(Profiling::Profiler *profiler);
+ static void setPreviewing(bool enabled);
#endif // QT_CONFIG(qml_debug)
// We don't want to #include <private/qv4stackframe_p.h> here, but we still want
diff --git a/tests/auto/qml/debugger/qqmlpreview/tst_qqmlpreview.cpp b/tests/auto/qml/debugger/qqmlpreview/tst_qqmlpreview.cpp
index 5874100ebd..2dabff4275 100644
--- a/tests/auto/qml/debugger/qqmlpreview/tst_qqmlpreview.cpp
+++ b/tests/auto/qml/debugger/qqmlpreview/tst_qqmlpreview.cpp
@@ -26,6 +26,8 @@ public:
private:
ConnectResult startQmlProcess(const QString &qmlFile);
void serveRequest(const QString &path);
+ void serveFile(const QString &path, const QByteArray &contents);
+
QList<QQmlDebugClient *> createClients() override;
void verifyProcessOutputContains(const QString &string) const;
@@ -42,6 +44,7 @@ private slots:
void connect();
void load();
+ void loadFromQrc();
void rerun();
void blacklist();
void error();
@@ -70,8 +73,7 @@ void tst_QQmlPreview::serveRequest(const QString &path)
} else {
QFile file(path);
if (file.open(QIODevice::ReadOnly)) {
- m_files.append(path);
- m_client->sendFile(path, file.readAll());
+ serveFile(path, file.readAll());
} else {
m_filesNotFound.append(path);
m_client->sendError(path);
@@ -79,6 +81,12 @@ void tst_QQmlPreview::serveRequest(const QString &path)
}
}
+void tst_QQmlPreview::serveFile(const QString &path, const QByteArray &contents)
+{
+ m_files.append(path);
+ m_client->sendFile(path, contents);
+}
+
QList<QQmlDebugClient *> tst_QQmlPreview::createClients()
{
m_client = new QQmlPreviewClient(m_connection);
@@ -162,6 +170,34 @@ void tst_QQmlPreview::load()
QVERIFY(m_serviceErrors.isEmpty());
}
+void tst_QQmlPreview::loadFromQrc()
+{
+ // One of the configuration files built into the "qml" executable.
+ const QString fromQrc(":/qt-project.org/imports/QmlRuntime/Config/default.qml");
+
+ QCOMPARE(QQmlDebugTest::connectTo(
+ QLibraryInfo::path(QLibraryInfo::BinariesPath) + "/qml",
+ QStringLiteral("QmlPreview"), fromQrc, true),
+ ConnectSuccess);
+
+ QVERIFY(m_client);
+ QTRY_COMPARE(m_client->state(), QQmlDebugClient::Enabled);
+
+ serveFile(fromQrc, R"(
+ import QtQuick
+ Item {
+ Component.onCompleted: console.log("default.qml replaced")
+ }
+ )");
+
+ m_client->triggerLoad(QUrl("qrc" + fromQrc));
+ verifyProcessOutputContains("default.qml replaced");
+
+ m_process->stop();
+ QTRY_COMPARE(m_client->state(), QQmlDebugClient::NotConnected);
+ QVERIFY(m_serviceErrors.isEmpty());
+}
+
void tst_QQmlPreview::rerun()
{
const QString file("window.qml");