diff options
author | Ulf Hermann <ulf.hermann@qt.io> | 2024-09-25 14:45:39 +0200 |
---|---|---|
committer | Qt Cherry-pick Bot <cherrypick_bot@qt-project.org> | 2024-09-28 01:28:04 +0000 |
commit | 3aedb6a017d96221f7707827a0501102df0bdf23 (patch) | |
tree | ad0a5d09c69536bb709423ff496afd2cc7a7587e | |
parent | fafd134e79d659dcae97f704fbd6f4c2ea0db9b7 (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.cpp | 9 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4engine.cpp | 13 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4engine_p.h | 2 | ||||
-rw-r--r-- | tests/auto/qml/debugger/qqmlpreview/tst_qqmlpreview.cpp | 40 |
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"); |