diff options
author | Simon Hausmann <simon.hausmann@qt.io> | 2016-07-19 10:13:26 +0200 |
---|---|---|
committer | Simon Hausmann <simon.hausmann@qt.io> | 2016-07-19 18:19:46 +0000 |
commit | 6a1667bc4e6d1074f547434d714cd47ed8ebfc41 (patch) | |
tree | 84285121878205ec1f5a2c2f5ddff3a20c1fc27f /src | |
parent | e0e50532d29d02c8bcbab01dbfb72377102eaf8f (diff) |
Improve robustness of qml cache expiry checking
Instead of relying on two time stamps in the file system (source file and cache
file), make the determination on whether the source file is newer than the
cache solely depend on the time stamp of only the source file. This means that
when cache files are stored in archives for example their modification date
does not need to be preserved upon extraction.
Change-Id: I0b4362663868c6fb9bd7e106028161b2d67274d4
Reviewed-by: Lars Knoll <lars.knoll@qt.io>
Diffstat (limited to 'src')
-rw-r--r-- | src/qml/compiler/qv4compileddata.cpp | 17 | ||||
-rw-r--r-- | src/qml/compiler/qv4compileddata_p.h | 2 | ||||
-rw-r--r-- | src/qml/compiler/qv4compiler.cpp | 1 | ||||
-rw-r--r-- | src/qml/compiler/qv4jsir_p.h | 2 | ||||
-rw-r--r-- | src/qml/qml/qqmltypeloader.cpp | 17 | ||||
-rw-r--r-- | src/qml/qml/qqmltypeloader_p.h | 2 |
6 files changed, 27 insertions, 14 deletions
diff --git a/src/qml/compiler/qv4compileddata.cpp b/src/qml/compiler/qv4compileddata.cpp index 6a30faba19..3f7c8df973 100644 --- a/src/qml/compiler/qv4compileddata.cpp +++ b/src/qml/compiler/qv4compileddata.cpp @@ -339,14 +339,6 @@ bool CompilationUnit::loadFromDisk(const QUrl &url, QString *errorString) QScopedPointer<QFile> cacheFile(new QFile(url.toLocalFile() + QLatin1Char('c'))); - { - QFileInfo sourceCode(url.toLocalFile()); - if (sourceCode.exists() && sourceCode.lastModified() >= QFileInfo(*cacheFile).lastModified()) { - *errorString = QStringLiteral("QML source file is equal or newer than cached file."); - return false; - } - } - if (!cacheFile->open(QIODevice::ReadOnly)) { *errorString = cacheFile->errorString(); return false; @@ -360,6 +352,15 @@ bool CompilationUnit::loadFromDisk(const QUrl &url, QString *errorString) QScopedValueRollback<const Unit *> dataPtrChange(data, reinterpret_cast<const Unit *>(cacheData)); + { + QFileInfo sourceCode(url.toLocalFile()); + if (sourceCode.exists() && sourceCode.lastModified().toMSecsSinceEpoch() != data->sourceTimeStamp) { + *errorString = QStringLiteral("QML source file has a different time stamp than cached file."); + return false; + } + } + + if (!memoryMapCode(errorString)) return false; diff --git a/src/qml/compiler/qv4compileddata_p.h b/src/qml/compiler/qv4compileddata_p.h index 0f85460a08..20b68026e9 100644 --- a/src/qml/compiler/qv4compileddata_p.h +++ b/src/qml/compiler/qv4compileddata_p.h @@ -96,6 +96,7 @@ typedef QJsonPrivate::q_littleendian<quint16> LEUInt16; typedef QJsonPrivate::q_littleendian<quint32> LEUInt32; typedef QJsonPrivate::q_littleendian<qint32> LEInt32; typedef QJsonPrivate::q_littleendian<quint64> LEUInt64; +typedef QJsonPrivate::q_littleendian<qint64> LEInt64; struct String; struct Function; @@ -599,6 +600,7 @@ struct Unit char magic[8]; LEInt16 architecture; LEInt16 version; + LEInt64 sourceTimeStamp; LEUInt32 unitSize; // Size of the Unit and any depending data. enum : unsigned int { diff --git a/src/qml/compiler/qv4compiler.cpp b/src/qml/compiler/qv4compiler.cpp index fc462bb1c6..5d13734247 100644 --- a/src/qml/compiler/qv4compiler.cpp +++ b/src/qml/compiler/qv4compiler.cpp @@ -404,6 +404,7 @@ QV4::CompiledData::Unit QV4::Compiler::JSUnitGenerator::generateHeader(QV4::Comp } unit.indexOfRootFunction = -1; unit.sourceFileIndex = getStringId(irModule->fileName); + unit.sourceTimeStamp = irModule->sourceTimeStamp; 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 2d6d7d728f..de84accbb1 100644 --- a/src/qml/compiler/qv4jsir_p.h +++ b/src/qml/compiler/qv4jsir_p.h @@ -932,6 +932,7 @@ struct Q_QML_PRIVATE_EXPORT Module { QVector<Function *> functions; Function *rootFunction; QString fileName; + qint64 sourceTimeStamp; bool isQmlModule; // implies rootFunction is always 0 bool debugMode; @@ -939,6 +940,7 @@ struct Q_QML_PRIVATE_EXPORT Module { Module(bool debugMode) : rootFunction(0) + , sourceTimeStamp(0) , isQmlModule(false) , debugMode(debugMode) {} diff --git a/src/qml/qml/qqmltypeloader.cpp b/src/qml/qml/qqmltypeloader.cpp index 8deb41c505..adeec52b74 100644 --- a/src/qml/qml/qqmltypeloader.cpp +++ b/src/qml/qml/qqmltypeloader.cpp @@ -2305,14 +2305,16 @@ void QQmlTypeData::dataReceived(const Data &data) if (tryLoadFromDiskCache()) return; + qint64 sourceTimeStamp; QString error; - QString code = QString::fromUtf8(data.readAll(&error)); + QString code = QString::fromUtf8(data.readAll(&error, &sourceTimeStamp)); if (!error.isEmpty()) { setError(error); return; } QQmlEngine *qmlEngine = typeLoader()->engine(); m_document.reset(new QmlIR::Document(QV8Engine::getV4(qmlEngine)->debugger != 0)); + m_document->jsModule.sourceTimeStamp = sourceTimeStamp; QmlIR::IRBuilder compiler(QV8Engine::get(qmlEngine)->illegalNames()); if (!compiler.generateFromQml(code, finalUrlString(), m_document.data())) { QList<QQmlError> errors; @@ -2833,15 +2835,16 @@ struct EmptyCompilationUnit : public QV4::CompiledData::CompilationUnit void QQmlScriptBlob::dataReceived(const Data &data) { + QV4::ExecutionEngine *v4 = QV8Engine::getV4(m_typeLoader->engine()); + QmlIR::Document irUnit(v4->debugger != 0); + QString error; - QString source = QString::fromUtf8(data.readAll(&error)); + QString source = QString::fromUtf8(data.readAll(&error, &irUnit.jsModule.sourceTimeStamp)); if (!error.isEmpty()) { setError(error); return; } - QV4::ExecutionEngine *v4 = QV8Engine::getV4(m_typeLoader->engine()); - QmlIR::Document irUnit(v4->debugger != 0); QmlIR::ScriptDirectivesCollector collector(&irUnit.jsParserEngine, &irUnit.jsGenerator); QList<QQmlError> errors; @@ -3006,11 +3009,13 @@ void QQmlQmldirData::initializeFromCachedUnit(const QQmlPrivate::CachedQmlUnit * Q_UNIMPLEMENTED(); } -QByteArray QQmlDataBlob::Data::readAll(QString *error) const +QByteArray QQmlDataBlob::Data::readAll(QString *error, qint64 *sourceTimeStamp) const { Q_ASSERT(!d.isNull()); error->clear(); if (d.isT1()) { + if (sourceTimeStamp) + *sourceTimeStamp = 0; return *d.asT1(); } QFile f(*d.asT2()); @@ -3018,6 +3023,8 @@ QByteArray QQmlDataBlob::Data::readAll(QString *error) const *error = f.errorString(); return QByteArray(); } + if (sourceTimeStamp) + *sourceTimeStamp = QFileInfo(f).lastModified().toMSecsSinceEpoch(); QByteArray data(f.size(), Qt::Uninitialized); if (f.read(data.data(), data.length()) != data.length()) { *error = f.errorString(); diff --git a/src/qml/qml/qqmltypeloader_p.h b/src/qml/qml/qqmltypeloader_p.h index 3e815878f8..4c57306ed7 100644 --- a/src/qml/qml/qqmltypeloader_p.h +++ b/src/qml/qml/qqmltypeloader_p.h @@ -131,7 +131,7 @@ public: class Data { public: - QByteArray readAll(QString *error) const; + QByteArray readAll(QString *error, qint64 *sourceTimeStamp = 0) const; private: friend class QQmlDataBlob; friend class QQmlTypeLoader; |