diff options
-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 | ||||
-rw-r--r-- | tests/auto/qml/qmldiskcache/tst_qmldiskcache.cpp | 5 |
7 files changed, 32 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; diff --git a/tests/auto/qml/qmldiskcache/tst_qmldiskcache.cpp b/tests/auto/qml/qmldiskcache/tst_qmldiskcache.cpp index b4697a4a3b..f85f66378a 100644 --- a/tests/auto/qml/qmldiskcache/tst_qmldiskcache.cpp +++ b/tests/auto/qml/qmldiskcache/tst_qmldiskcache.cpp @@ -31,6 +31,7 @@ #include <private/qv4compileddata_p.h> #include <QQmlComponent> #include <QQmlEngine> +#include <QThread> class tst_qmldiskcache: public QObject { @@ -63,6 +64,10 @@ struct TestCompiler } mappedFile.close(); + // Qt API limits the precision of QFileInfo::modificationTime() to seconds, so to ensure that + // the newly written file has a modification date newer than an existing cache file, we must + // wait. + QThread::sleep(1); { QFile f(testFilePath); if (!f.open(QIODevice::WriteOnly | QIODevice::Truncate)) { |