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 <lars.knoll@qt.io>
This commit is contained in:
Simon Hausmann 2017-03-16 09:44:50 +01:00
parent 9b70716374
commit 5bd11b5a8c
12 changed files with 26 additions and 30 deletions

View File

@ -59,7 +59,7 @@ CompilationUnitMapper::~CompilationUnitMapper()
close(); 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))) { if (strncmp(header->magic, CompiledData::magic_str, sizeof(header->magic))) {
*errorString = QStringLiteral("Magic bytes in the header do not match"); *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) { 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 // Files from the resource system do not have any time stamps, so fall back to the application
// executable. // executable.
if (!sourceTimeStamp.isValid()) if (!sourceTimeStamp.isValid())

View File

@ -68,11 +68,11 @@ public:
CompilationUnitMapper(); CompilationUnitMapper();
~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(); void close();
private: 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) #if defined(Q_OS_UNIX)
size_t length; size_t length;

View File

@ -43,6 +43,7 @@
#include <functional> #include <functional>
#include <private/qcore_unix_p.h> #include <private/qcore_unix_p.h>
#include <private/qdeferredcleanup_p.h> #include <private/qdeferredcleanup_p.h>
#include <QDateTime>
#include "qv4compileddata_p.h" #include "qv4compileddata_p.h"
@ -50,7 +51,7 @@ QT_BEGIN_NAMESPACE
using namespace QV4; 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(); close();
@ -72,7 +73,7 @@ CompiledData::Unit *CompilationUnitMapper::open(const QString &cacheFileName, co
return nullptr; return nullptr;
} }
if (!verifyHeader(&header, sourcePath, errorString)) if (!verifyHeader(&header, sourceTimeStamp, errorString))
return nullptr; return nullptr;
// Data structure and qt version matched, so now we can access the rest of the file safely. // Data structure and qt version matched, so now we can access the rest of the file safely.

View File

@ -49,7 +49,7 @@ QT_BEGIN_NAMESPACE
using namespace QV4; 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(); close();
@ -87,7 +87,7 @@ CompiledData::Unit *CompilationUnitMapper::open(const QString &cacheFileName, co
return nullptr; return nullptr;
} }
if (!verifyHeader(&header, sourcePath, errorString)) if (!verifyHeader(&header, sourceTimeStamp, errorString))
return nullptr; return nullptr;
const uint mappingFlags = header.flags & QV4::CompiledData::Unit::ContainsMachineCode const uint mappingFlags = header.flags & QV4::CompiledData::Unit::ContainsMachineCode

View File

@ -343,7 +343,7 @@ bool CompilationUnit::verifyChecksum(QQmlEngine *engine,
sizeof(data->dependencyMD5Checksum)) == 0; 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)) { if (!QQmlFile::isLocalFile(url)) {
*errorString = QStringLiteral("File has to be a local file."); *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); const QString sourcePath = QQmlFile::urlToLocalFileOrQrc(url);
QScopedPointer<CompilationUnitMapper> cacheFile(new CompilationUnitMapper()); QScopedPointer<CompilationUnitMapper> cacheFile(new CompilationUnitMapper());
CompiledData::Unit *mappedUnit = cacheFile->open(cacheFilePath(url), sourcePath, errorString); CompiledData::Unit *mappedUnit = cacheFile->open(cacheFilePath(url), sourceTimeStamp, errorString);
if (!mappedUnit) if (!mappedUnit)
return false; return false;

View File

@ -899,7 +899,7 @@ struct Q_QML_PRIVATE_EXPORT CompilationUnit : public CompilationUnitBase, public
void destroy() Q_DECL_OVERRIDE; 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: protected:
virtual void linkBackendToEngine(QV4::ExecutionEngine *engine) = 0; virtual void linkBackendToEngine(QV4::ExecutionEngine *engine) = 0;

View File

@ -425,7 +425,7 @@ QV4::CompiledData::Unit QV4::Compiler::JSUnitGenerator::generateHeader(QV4::Comp
} }
unit.indexOfRootFunction = -1; unit.indexOfRootFunction = -1;
unit.sourceFileIndex = getStringId(irModule->fileName); unit.sourceFileIndex = getStringId(irModule->fileName);
unit.sourceTimeStamp = irModule->sourceTimeStamp; unit.sourceTimeStamp = irModule->sourceTimeStamp.isValid() ? irModule->sourceTimeStamp.toMSecsSinceEpoch() : 0;
unit.nImports = 0; unit.nImports = 0;
unit.offsetToImports = 0; unit.offsetToImports = 0;
unit.nObjects = 0; unit.nObjects = 0;

View File

@ -61,6 +61,7 @@
#include <QtCore/QBitArray> #include <QtCore/QBitArray>
#include <QtCore/qurl.h> #include <QtCore/qurl.h>
#include <QtCore/QVarLengthArray> #include <QtCore/QVarLengthArray>
#include <QtCore/QDateTime>
#include <qglobal.h> #include <qglobal.h>
#if defined(CONST) && defined(Q_OS_WIN) #if defined(CONST) && defined(Q_OS_WIN)
@ -942,7 +943,7 @@ struct Q_QML_PRIVATE_EXPORT Module {
QVector<Function *> functions; QVector<Function *> functions;
Function *rootFunction; Function *rootFunction;
QString fileName; QString fileName;
qint64 sourceTimeStamp; QDateTime sourceTimeStamp;
bool isQmlModule; // implies rootFunction is always 0 bool isQmlModule; // implies rootFunction is always 0
uint unitFlags; // flags merged into CompiledData::Unit::flags uint unitFlags; // flags merged into CompiledData::Unit::flags
#ifdef QT_NO_QML_DEBUGGER #ifdef QT_NO_QML_DEBUGGER
@ -955,7 +956,6 @@ struct Q_QML_PRIVATE_EXPORT Module {
Module(bool debugMode) Module(bool debugMode)
: rootFunction(0) : rootFunction(0)
, sourceTimeStamp(0)
, isQmlModule(false) , isQmlModule(false)
, unitFlags(0) , unitFlags(0)
#ifndef QT_NO_QML_DEBUGGER #ifndef QT_NO_QML_DEBUGGER

View File

@ -2065,7 +2065,7 @@ bool QQmlTypeData::tryLoadFromDiskCache()
QQmlRefPointer<QV4::CompiledData::CompilationUnit> unit = v4->iselFactory->createUnitForLoading(); QQmlRefPointer<QV4::CompiledData::CompilationUnit> unit = v4->iselFactory->createUnitForLoading();
{ {
QString error; 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; qCDebug(DBG_DISK_CACHE) << "Error loading" << url().toString() << "from disk cache:" << error;
return false; return false;
} }
@ -2522,7 +2522,7 @@ void QQmlTypeData::compile(const QQmlRefPointer<QQmlTypeNameCache> &typeNameCach
QString errorString; QString errorString;
if (m_compiledData->saveToDisk(url(), &errorString)) { if (m_compiledData->saveToDisk(url(), &errorString)) {
QString error; 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. // ignore error, keep using the in-memory compilation unit.
} }
} else { } else {
@ -2882,7 +2882,7 @@ void QQmlScriptBlob::dataReceived(const SourceCodeData &data)
if (!disableDiskCache() || forceDiskCache()) { if (!disableDiskCache() || forceDiskCache()) {
QQmlRefPointer<QV4::CompiledData::CompilationUnit> unit = v4->iselFactory->createUnitForLoading(); QQmlRefPointer<QV4::CompiledData::CompilationUnit> unit = v4->iselFactory->createUnitForLoading();
QString error; QString error;
if (unit->loadFromDisk(url(), v4->iselFactory.data(), &error)) { if (unit->loadFromDisk(url(), data.sourceTimeStamp(), v4->iselFactory.data(), &error)) {
initializeFromCompilationUnit(unit); initializeFromCompilationUnit(unit);
return; return;
} else { } else {
@ -3094,18 +3094,18 @@ QString QQmlDataBlob::SourceCodeData::readAll(QString *error) const
return QString::fromUtf8(data); return QString::fromUtf8(data);
} }
qint64 QQmlDataBlob::SourceCodeData::sourceTimeStamp() const QDateTime QQmlDataBlob::SourceCodeData::sourceTimeStamp() const
{ {
if (!inlineSourceCode.isEmpty()) if (!inlineSourceCode.isEmpty())
return 0; return QDateTime();
QDateTime timeStamp = fileInfo.lastModified(); QDateTime timeStamp = fileInfo.lastModified();
if (timeStamp.isValid()) if (timeStamp.isValid())
return timeStamp.toMSecsSinceEpoch(); return timeStamp;
static qint64 appTimeStamp = 0; static QDateTime appTimeStamp;
if (appTimeStamp == 0) if (!appTimeStamp.isValid())
appTimeStamp = QFileInfo(QCoreApplication::applicationFilePath()).lastModified().toMSecsSinceEpoch(); appTimeStamp = QFileInfo(QCoreApplication::applicationFilePath()).lastModified();
return appTimeStamp; return appTimeStamp;
} }

View File

@ -134,7 +134,7 @@ public:
class SourceCodeData { class SourceCodeData {
public: public:
QString readAll(QString *error) const; QString readAll(QString *error) const;
qint64 sourceTimeStamp() const; QDateTime sourceTimeStamp() const;
bool exists() const; bool exists() const;
private: private:
friend class QQmlDataBlob; friend class QQmlDataBlob;

View File

@ -174,7 +174,7 @@ struct TestCompiler
{ {
QV4::ExecutionEngine *v4 = QV8Engine::getV4(engine); QV4::ExecutionEngine *v4 = QV8Engine::getV4(engine);
QQmlRefPointer<QV4::CompiledData::CompilationUnit> unit = v4->iselFactory->createUnitForLoading(); QQmlRefPointer<QV4::CompiledData::CompilationUnit> 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() void closeMapping()

View File

@ -159,7 +159,7 @@ int main(int argc, char *argv[])
if (cache && QFile::exists(fn + QLatin1Char('c'))) { if (cache && QFile::exists(fn + QLatin1Char('c'))) {
QQmlRefPointer<QV4::CompiledData::CompilationUnit> unit = iSelFactory->createUnitForLoading(); QQmlRefPointer<QV4::CompiledData::CompilationUnit> unit = iSelFactory->createUnitForLoading();
QString error; 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)); script.reset(new QV4::Script(&vm, nullptr, unit));
} else { } else {
std::cout << "Error loading" << qPrintable(fn) << "from disk cache:" << qPrintable(error) << std::endl; std::cout << "Error loading" << qPrintable(fn) << "from disk cache:" << qPrintable(error) << std::endl;