From 5bd11b5a8c2f627bc9c9f1b6c02602772ad67dae Mon Sep 17 00:00:00 2001 From: Simon Hausmann Date: Thu, 16 Mar 2017 09:44:50 +0100 Subject: [PATCH] Avoid an extra stat() on the source .qml file when loading cache For timestamp comparison it is not necessary to create another QFileInfo() object and call exists() and lastModified(), when we can pass that information through from the type loader. Change-Id: I225cd36e672f1f390bddb4e6ebfafa3fc1269795 Reviewed-by: Lars Knoll --- src/qml/compiler/qv4compilationunitmapper.cpp | 7 +------ src/qml/compiler/qv4compilationunitmapper_p.h | 4 ++-- .../compiler/qv4compilationunitmapper_unix.cpp | 5 +++-- .../compiler/qv4compilationunitmapper_win.cpp | 4 ++-- src/qml/compiler/qv4compileddata.cpp | 4 ++-- src/qml/compiler/qv4compileddata_p.h | 2 +- src/qml/compiler/qv4compiler.cpp | 2 +- src/qml/compiler/qv4jsir_p.h | 4 ++-- src/qml/qml/qqmltypeloader.cpp | 18 +++++++++--------- src/qml/qml/qqmltypeloader_p.h | 2 +- .../auto/qml/qmldiskcache/tst_qmldiskcache.cpp | 2 +- tools/qmljs/qmljs.cpp | 2 +- 12 files changed, 26 insertions(+), 30 deletions(-) diff --git a/src/qml/compiler/qv4compilationunitmapper.cpp b/src/qml/compiler/qv4compilationunitmapper.cpp index 1ae0fb190c..d94f7ac238 100644 --- a/src/qml/compiler/qv4compilationunitmapper.cpp +++ b/src/qml/compiler/qv4compilationunitmapper.cpp @@ -59,7 +59,7 @@ CompilationUnitMapper::~CompilationUnitMapper() close(); } -bool CompilationUnitMapper::verifyHeader(const CompiledData::Unit *header, const QString &sourcePath, QString *errorString) +bool CompilationUnitMapper::verifyHeader(const CompiledData::Unit *header, QDateTime sourceTimeStamp, QString *errorString) { if (strncmp(header->magic, CompiledData::magic_str, sizeof(header->magic))) { *errorString = QStringLiteral("Magic bytes in the header do not match"); @@ -77,11 +77,6 @@ bool CompilationUnitMapper::verifyHeader(const CompiledData::Unit *header, const } if (header->sourceTimeStamp) { - QFileInfo sourceCode(sourcePath); - QDateTime sourceTimeStamp; - if (sourceCode.exists()) - sourceTimeStamp = sourceCode.lastModified(); - // Files from the resource system do not have any time stamps, so fall back to the application // executable. if (!sourceTimeStamp.isValid()) diff --git a/src/qml/compiler/qv4compilationunitmapper_p.h b/src/qml/compiler/qv4compilationunitmapper_p.h index 5b6939f1cf..b24f98df7c 100644 --- a/src/qml/compiler/qv4compilationunitmapper_p.h +++ b/src/qml/compiler/qv4compilationunitmapper_p.h @@ -68,11 +68,11 @@ public: CompilationUnitMapper(); ~CompilationUnitMapper(); - CompiledData::Unit *open(const QString &cacheFilePath, const QString &sourcePath, QString *errorString); + CompiledData::Unit *open(const QString &cacheFilePath, const QDateTime &sourceTimeStamp, QString *errorString); void close(); private: - static bool verifyHeader(const QV4::CompiledData::Unit *header, const QString &sourcePath, QString *errorString); + static bool verifyHeader(const QV4::CompiledData::Unit *header, QDateTime sourceTimeStamp, QString *errorString); #if defined(Q_OS_UNIX) size_t length; diff --git a/src/qml/compiler/qv4compilationunitmapper_unix.cpp b/src/qml/compiler/qv4compilationunitmapper_unix.cpp index 1aa3e05f5f..38dabc41cf 100644 --- a/src/qml/compiler/qv4compilationunitmapper_unix.cpp +++ b/src/qml/compiler/qv4compilationunitmapper_unix.cpp @@ -43,6 +43,7 @@ #include #include #include +#include #include "qv4compileddata_p.h" @@ -50,7 +51,7 @@ QT_BEGIN_NAMESPACE using namespace QV4; -CompiledData::Unit *CompilationUnitMapper::open(const QString &cacheFileName, const QString &sourcePath, QString *errorString) +CompiledData::Unit *CompilationUnitMapper::open(const QString &cacheFileName, const QDateTime &sourceTimeStamp, QString *errorString) { close(); @@ -72,7 +73,7 @@ CompiledData::Unit *CompilationUnitMapper::open(const QString &cacheFileName, co return nullptr; } - if (!verifyHeader(&header, sourcePath, errorString)) + if (!verifyHeader(&header, sourceTimeStamp, errorString)) return nullptr; // Data structure and qt version matched, so now we can access the rest of the file safely. diff --git a/src/qml/compiler/qv4compilationunitmapper_win.cpp b/src/qml/compiler/qv4compilationunitmapper_win.cpp index 37cac846a0..d7a93ae233 100644 --- a/src/qml/compiler/qv4compilationunitmapper_win.cpp +++ b/src/qml/compiler/qv4compilationunitmapper_win.cpp @@ -49,7 +49,7 @@ QT_BEGIN_NAMESPACE using namespace QV4; -CompiledData::Unit *CompilationUnitMapper::open(const QString &cacheFileName, const QString &sourcePath, QString *errorString) +CompiledData::Unit *CompilationUnitMapper::open(const QString &cacheFileName, const QDateTime &sourceTimeStamp, QString *errorString) { close(); @@ -87,7 +87,7 @@ CompiledData::Unit *CompilationUnitMapper::open(const QString &cacheFileName, co return nullptr; } - if (!verifyHeader(&header, sourcePath, errorString)) + if (!verifyHeader(&header, sourceTimeStamp, errorString)) return nullptr; const uint mappingFlags = header.flags & QV4::CompiledData::Unit::ContainsMachineCode diff --git a/src/qml/compiler/qv4compileddata.cpp b/src/qml/compiler/qv4compileddata.cpp index 4688f936cc..1805ab3f54 100644 --- a/src/qml/compiler/qv4compileddata.cpp +++ b/src/qml/compiler/qv4compileddata.cpp @@ -343,7 +343,7 @@ bool CompilationUnit::verifyChecksum(QQmlEngine *engine, sizeof(data->dependencyMD5Checksum)) == 0; } -bool CompilationUnit::loadFromDisk(const QUrl &url, EvalISelFactory *iselFactory, QString *errorString) +bool CompilationUnit::loadFromDisk(const QUrl &url, const QDateTime &sourceTimeStamp, EvalISelFactory *iselFactory, QString *errorString) { if (!QQmlFile::isLocalFile(url)) { *errorString = QStringLiteral("File has to be a local file."); @@ -353,7 +353,7 @@ bool CompilationUnit::loadFromDisk(const QUrl &url, EvalISelFactory *iselFactory const QString sourcePath = QQmlFile::urlToLocalFileOrQrc(url); QScopedPointer cacheFile(new CompilationUnitMapper()); - CompiledData::Unit *mappedUnit = cacheFile->open(cacheFilePath(url), sourcePath, errorString); + CompiledData::Unit *mappedUnit = cacheFile->open(cacheFilePath(url), sourceTimeStamp, errorString); if (!mappedUnit) return false; diff --git a/src/qml/compiler/qv4compileddata_p.h b/src/qml/compiler/qv4compileddata_p.h index 6d219b85aa..8cf5437928 100644 --- a/src/qml/compiler/qv4compileddata_p.h +++ b/src/qml/compiler/qv4compileddata_p.h @@ -899,7 +899,7 @@ struct Q_QML_PRIVATE_EXPORT CompilationUnit : public CompilationUnitBase, public void destroy() Q_DECL_OVERRIDE; - bool loadFromDisk(const QUrl &url, EvalISelFactory *iselFactory, QString *errorString); + bool loadFromDisk(const QUrl &url, const QDateTime &sourceTimeStamp, EvalISelFactory *iselFactory, QString *errorString); protected: virtual void linkBackendToEngine(QV4::ExecutionEngine *engine) = 0; diff --git a/src/qml/compiler/qv4compiler.cpp b/src/qml/compiler/qv4compiler.cpp index 9cfac4a676..64f034ddcb 100644 --- a/src/qml/compiler/qv4compiler.cpp +++ b/src/qml/compiler/qv4compiler.cpp @@ -425,7 +425,7 @@ QV4::CompiledData::Unit QV4::Compiler::JSUnitGenerator::generateHeader(QV4::Comp } unit.indexOfRootFunction = -1; unit.sourceFileIndex = getStringId(irModule->fileName); - unit.sourceTimeStamp = irModule->sourceTimeStamp; + unit.sourceTimeStamp = irModule->sourceTimeStamp.isValid() ? irModule->sourceTimeStamp.toMSecsSinceEpoch() : 0; unit.nImports = 0; unit.offsetToImports = 0; unit.nObjects = 0; diff --git a/src/qml/compiler/qv4jsir_p.h b/src/qml/compiler/qv4jsir_p.h index 23ebe0c962..d9192c1a3b 100644 --- a/src/qml/compiler/qv4jsir_p.h +++ b/src/qml/compiler/qv4jsir_p.h @@ -61,6 +61,7 @@ #include #include #include +#include #include #if defined(CONST) && defined(Q_OS_WIN) @@ -942,7 +943,7 @@ struct Q_QML_PRIVATE_EXPORT Module { QVector functions; Function *rootFunction; QString fileName; - qint64 sourceTimeStamp; + QDateTime sourceTimeStamp; bool isQmlModule; // implies rootFunction is always 0 uint unitFlags; // flags merged into CompiledData::Unit::flags #ifdef QT_NO_QML_DEBUGGER @@ -955,7 +956,6 @@ struct Q_QML_PRIVATE_EXPORT Module { Module(bool debugMode) : rootFunction(0) - , sourceTimeStamp(0) , isQmlModule(false) , unitFlags(0) #ifndef QT_NO_QML_DEBUGGER diff --git a/src/qml/qml/qqmltypeloader.cpp b/src/qml/qml/qqmltypeloader.cpp index c5d4945bf1..9526615c0d 100644 --- a/src/qml/qml/qqmltypeloader.cpp +++ b/src/qml/qml/qqmltypeloader.cpp @@ -2065,7 +2065,7 @@ bool QQmlTypeData::tryLoadFromDiskCache() QQmlRefPointer unit = v4->iselFactory->createUnitForLoading(); { QString error; - if (!unit->loadFromDisk(url(), v4->iselFactory.data(), &error)) { + if (!unit->loadFromDisk(url(), m_backupSourceCode.sourceTimeStamp(), v4->iselFactory.data(), &error)) { qCDebug(DBG_DISK_CACHE) << "Error loading" << url().toString() << "from disk cache:" << error; return false; } @@ -2522,7 +2522,7 @@ void QQmlTypeData::compile(const QQmlRefPointer &typeNameCach QString errorString; if (m_compiledData->saveToDisk(url(), &errorString)) { QString error; - if (!m_compiledData->loadFromDisk(url(), enginePrivate->v4engine()->iselFactory.data(), &error)) { + if (!m_compiledData->loadFromDisk(url(), m_backupSourceCode.sourceTimeStamp(), enginePrivate->v4engine()->iselFactory.data(), &error)) { // ignore error, keep using the in-memory compilation unit. } } else { @@ -2882,7 +2882,7 @@ void QQmlScriptBlob::dataReceived(const SourceCodeData &data) if (!disableDiskCache() || forceDiskCache()) { QQmlRefPointer unit = v4->iselFactory->createUnitForLoading(); QString error; - if (unit->loadFromDisk(url(), v4->iselFactory.data(), &error)) { + if (unit->loadFromDisk(url(), data.sourceTimeStamp(), v4->iselFactory.data(), &error)) { initializeFromCompilationUnit(unit); return; } else { @@ -3094,18 +3094,18 @@ QString QQmlDataBlob::SourceCodeData::readAll(QString *error) const return QString::fromUtf8(data); } -qint64 QQmlDataBlob::SourceCodeData::sourceTimeStamp() const +QDateTime QQmlDataBlob::SourceCodeData::sourceTimeStamp() const { if (!inlineSourceCode.isEmpty()) - return 0; + return QDateTime(); QDateTime timeStamp = fileInfo.lastModified(); if (timeStamp.isValid()) - return timeStamp.toMSecsSinceEpoch(); + return timeStamp; - static qint64 appTimeStamp = 0; - if (appTimeStamp == 0) - appTimeStamp = QFileInfo(QCoreApplication::applicationFilePath()).lastModified().toMSecsSinceEpoch(); + static QDateTime appTimeStamp; + if (!appTimeStamp.isValid()) + appTimeStamp = QFileInfo(QCoreApplication::applicationFilePath()).lastModified(); return appTimeStamp; } diff --git a/src/qml/qml/qqmltypeloader_p.h b/src/qml/qml/qqmltypeloader_p.h index 0bae857874..1bd2c7f1e1 100644 --- a/src/qml/qml/qqmltypeloader_p.h +++ b/src/qml/qml/qqmltypeloader_p.h @@ -134,7 +134,7 @@ public: class SourceCodeData { public: QString readAll(QString *error) const; - qint64 sourceTimeStamp() const; + QDateTime sourceTimeStamp() const; bool exists() const; private: friend class QQmlDataBlob; diff --git a/tests/auto/qml/qmldiskcache/tst_qmldiskcache.cpp b/tests/auto/qml/qmldiskcache/tst_qmldiskcache.cpp index b265607fd1..17aa6087d2 100644 --- a/tests/auto/qml/qmldiskcache/tst_qmldiskcache.cpp +++ b/tests/auto/qml/qmldiskcache/tst_qmldiskcache.cpp @@ -174,7 +174,7 @@ struct TestCompiler { QV4::ExecutionEngine *v4 = QV8Engine::getV4(engine); QQmlRefPointer unit = v4->iselFactory->createUnitForLoading(); - return unit->loadFromDisk(QUrl::fromLocalFile(testFilePath), v4->iselFactory.data(), &lastErrorString); + return unit->loadFromDisk(QUrl::fromLocalFile(testFilePath), QFileInfo(testFilePath).lastModified(), v4->iselFactory.data(), &lastErrorString); } void closeMapping() diff --git a/tools/qmljs/qmljs.cpp b/tools/qmljs/qmljs.cpp index 4d0f9d278f..14a20731c0 100644 --- a/tools/qmljs/qmljs.cpp +++ b/tools/qmljs/qmljs.cpp @@ -159,7 +159,7 @@ int main(int argc, char *argv[]) if (cache && QFile::exists(fn + QLatin1Char('c'))) { QQmlRefPointer unit = iSelFactory->createUnitForLoading(); QString error; - if (unit->loadFromDisk(QUrl::fromLocalFile(fn), iSelFactory, &error)) { + if (unit->loadFromDisk(QUrl::fromLocalFile(fn), QFileInfo(fn).lastModified(), iSelFactory, &error)) { script.reset(new QV4::Script(&vm, nullptr, unit)); } else { std::cout << "Error loading" << qPrintable(fn) << "from disk cache:" << qPrintable(error) << std::endl;