diff options
author | Ulf Hermann <ulf.hermann@qt.io> | 2021-01-11 17:46:00 +0100 |
---|---|---|
committer | Ulf Hermann <ulf.hermann@qt.io> | 2021-01-12 11:18:51 +0100 |
commit | 7660c30e08975011c7bd47bcb1796139b9d77196 (patch) | |
tree | 26e86cbc35560ac5bdf3327ea29f146cc1821787 /tests/auto/qml/qmldiskcache | |
parent | ccc4b52e95ac90c14c59001f675409c1a13c183b (diff) |
Cache static compilation units
If we load the same file multiple times, we can re-use the old mapping.
In fact we may leak memory if we don't. The fact that we have to use a
mutex here is somewhat regrettable, but I haven't found a better way
of serializing access.
Task-number: QTBUG-89659
Pick-to: 5.15
Change-Id: Iaa44ac80faa5e95f30c05e950ab35083a8b0416b
Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
Diffstat (limited to 'tests/auto/qml/qmldiskcache')
-rw-r--r-- | tests/auto/qml/qmldiskcache/tst_qmldiskcache.cpp | 128 |
1 files changed, 98 insertions, 30 deletions
diff --git a/tests/auto/qml/qmldiskcache/tst_qmldiskcache.cpp b/tests/auto/qml/qmldiskcache/tst_qmldiskcache.cpp index d0c8390a74..d96231e81e 100644 --- a/tests/auto/qml/qmldiskcache/tst_qmldiskcache.cpp +++ b/tests/auto/qml/qmldiskcache/tst_qmldiskcache.cpp @@ -64,6 +64,7 @@ private slots: void singletonDependency(); void cppRegisteredSingletonDependency(); void cacheModuleScripts(); + void reuseStaticMappings(); private: QDir m_qmlCacheDirectory; @@ -127,34 +128,43 @@ struct TestCompiler mappedFile.setFileName(cacheFilePath); } - bool compile(const QByteArray &contents) + void reset() { closeMapping(); engine->clearComponentCache(); - waitForFileSystem(); + } - { - QFile f(testFilePath); - if (!f.open(QIODevice::WriteOnly | QIODevice::Truncate)) { - lastErrorString = f.errorString(); - return false; - } - if (f.write(contents) != contents.size()) { - lastErrorString = f.errorString(); - return false; - } + bool writeTestFile(const QByteArray &contents) + { + QFile f(testFilePath); + if (!f.open(QIODevice::WriteOnly | QIODevice::Truncate)) { + lastErrorString = f.errorString(); + return false; + } + if (f.write(contents) != contents.size()) { + lastErrorString = f.errorString(); + return false; } + return true; + } + bool loadTestFile() + { CleanlyLoadingComponent component(engine, testFilePath); if (!component.isReady()) { lastErrorString = component.errorString(); return false; } - return true; } + bool compile(const QByteArray &contents) + { + reset(); + return writeTestFile(contents) && loadTestFile(); + } + const QV4::CompiledData::Unit *mapUnit() { if (!mappedFile.open(QIODevice::ReadOnly)) { @@ -173,29 +183,62 @@ struct TestCompiler } typedef void (*HeaderTweakFunction)(QV4::CompiledData::Unit *header); - bool tweakHeader(HeaderTweakFunction function) + bool tweakHeader(HeaderTweakFunction function, const QString &newName) { closeMapping(); - QFile f(cacheFilePath); - if (!f.open(QIODevice::ReadWrite)) + const QString targetTestFilePath = tempDir.path() + "/" + newName; + + { + QFile testFile(testFilePath); + if (!testFile.copy(targetTestFilePath)) + return false; + } + + const QString targetCacheFilePath = QV4::ExecutableCompilationUnit::localCacheFilePath( + QUrl::fromLocalFile(targetTestFilePath)); + + QFile source(cacheFilePath); + if (!source.copy(targetCacheFilePath)) return false; + + if (!source.open(QIODevice::ReadOnly)) + return false; + + QFile target(targetCacheFilePath); + if (!target.open(QIODevice::WriteOnly)) + return false; + QV4::CompiledData::Unit header; - if (f.read(reinterpret_cast<char *>(&header), sizeof(header)) != sizeof(header)) + if (source.read(reinterpret_cast<char *>(&header), sizeof(header)) != sizeof(header)) return false; function(&header); - f.seek(0); - return f.write(reinterpret_cast<const char *>(&header), sizeof(header)) == sizeof(header); + + return target.write(reinterpret_cast<const char *>(&header), sizeof(header)) + == sizeof(header); } - bool verify() + bool verify(const QString &fileName = QString()) + { + const QString path = fileName.isEmpty() ? testFilePath : tempDir.path() + "/" + fileName; + + QQmlRefPointer<QV4::ExecutableCompilationUnit> unit + = QV4::ExecutableCompilationUnit::create(); + return unit->loadFromDisk(QUrl::fromLocalFile(path), + QFileInfo(path).lastModified(), &lastErrorString); + } + + quintptr unitData() { QQmlRefPointer<QV4::ExecutableCompilationUnit> unit = QV4::ExecutableCompilationUnit::create(); return unit->loadFromDisk(QUrl::fromLocalFile(testFilePath), - QFileInfo(testFilePath).lastModified(), &lastErrorString); + QFileInfo(testFilePath).lastModified(), &lastErrorString) + ? quintptr(unit->unitData()) + : 0; } + void closeMapping() { if (currentMapping) { @@ -205,10 +248,11 @@ struct TestCompiler mappedFile.close(); } - void clearCache() + void clearCache(const QString &fileName = QString()) { + const QString path = fileName.isEmpty() ? testFilePath : tempDir.path() + "/" + fileName; closeMapping(); - QFile::remove(cacheFilePath); + QFile::remove(path); } QQmlEngine *engine; @@ -404,25 +448,28 @@ void tst_qmldiskcache::basicVersionChecks() testCompiler.clearCache(); QVERIFY2(testCompiler.compile(contents), qPrintable(testCompiler.lastErrorString)); - testCompiler.tweakHeader([](QV4::CompiledData::Unit *header) { + const QString qtVersionFile = QStringLiteral("qtversion.qml"); + QVERIFY(testCompiler.tweakHeader([](QV4::CompiledData::Unit *header) { header->qtVersion = 0; - }); + }, qtVersionFile)); - QVERIFY(!testCompiler.verify()); + QVERIFY(!testCompiler.verify(qtVersionFile)); QCOMPARE(testCompiler.lastErrorString, QString::fromUtf8("Qt version mismatch. Found 0 expected %1").arg(QT_VERSION, 0, 16)); - testCompiler.clearCache(); + testCompiler.clearCache(qtVersionFile); } { testCompiler.clearCache(); QVERIFY2(testCompiler.compile(contents), qPrintable(testCompiler.lastErrorString)); - testCompiler.tweakHeader([](QV4::CompiledData::Unit *header) { + const QString versionFile = QStringLiteral("version.qml"); + QVERIFY(testCompiler.tweakHeader([](QV4::CompiledData::Unit *header) { header->version = 0; - }); + }, versionFile)); - QVERIFY(!testCompiler.verify()); + QVERIFY(!testCompiler.verify(versionFile)); QCOMPARE(testCompiler.lastErrorString, QString::fromUtf8("V4 data structure version mismatch. Found 0 expected %1").arg(QV4_DATA_STRUCTURE_VERSION, 0, 16)); + testCompiler.clearCache(versionFile); } } @@ -963,6 +1010,27 @@ void tst_qmldiskcache::cacheModuleScripts() } } +void tst_qmldiskcache::reuseStaticMappings() +{ + QQmlEngine engine; + + TestCompiler testCompiler(&engine); + QVERIFY(testCompiler.tempDir.isValid()); + + testCompiler.reset(); + QVERIFY(testCompiler.writeTestFile("import QtQml\nQtObject { objectName: 'foobar' }\n")); + QVERIFY(testCompiler.loadTestFile()); + + const quintptr data1 = testCompiler.unitData(); + QVERIFY(data1 != 0); + QCOMPARE(testCompiler.unitData(), data1); + + testCompiler.reset(); + QVERIFY(testCompiler.loadTestFile()); + + QCOMPARE(testCompiler.unitData(), data1); +} + QTEST_MAIN(tst_qmldiskcache) #include "tst_qmldiskcache.moc" |