aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSimon Hausmann <simon.hausmann@qt.io>2017-03-15 16:52:10 +0100
committerSimon Hausmann <simon.hausmann@qt.io>2017-03-21 21:54:06 +0000
commit5ce2235f425b3c5047faf709c87c9b5c8e414b8b (patch)
tree5bd74cf139185d284a9379f095e31e0b8f1b6f36
parentfc0254a48c775cdfea693402d0472b73c8b940e5 (diff)
Avoid reading (not parsing) .qml files when using the cache
By making SourceCodeData copyable we can delay the reading of the source file until we really need to. This also allows persisting the QFileInfo object and therefore having only one stat() call to check if the file exists, what its size is and what the last modification time is. Change-Id: Ic7e4d5f566d870f3b1fa8302227417fa813cb139 Reviewed-by: Lars Knoll <lars.knoll@qt.io>
-rw-r--r--src/qml/qml/qqmltypeloader.cpp78
-rw-r--r--src/qml/qml/qqmltypeloader_p.h12
2 files changed, 54 insertions, 36 deletions
diff --git a/src/qml/qml/qqmltypeloader.cpp b/src/qml/qml/qqmltypeloader.cpp
index 193239e680..c5d4945bf1 100644
--- a/src/qml/qml/qqmltypeloader.cpp
+++ b/src/qml/qml/qqmltypeloader.cpp
@@ -1246,8 +1246,7 @@ void QQmlTypeLoader::setData(QQmlDataBlob *blob, const QByteArray &data)
{
QML_MEMORY_SCOPE_URL(blob->url());
QQmlDataBlob::SourceCodeData d;
- d.inlineSourceCodeOrFileName = QString::fromUtf8(data);
- d.sourceCodeAvailable = true;
+ d.inlineSourceCode = QString::fromUtf8(data);
setData(blob, d);
}
@@ -1255,8 +1254,7 @@ void QQmlTypeLoader::setData(QQmlDataBlob *blob, const QString &fileName)
{
QML_MEMORY_SCOPE_URL(blob->url());
QQmlDataBlob::SourceCodeData d;
- d.inlineSourceCodeOrFileName = fileName;
- d.sourceCodeAvailable = false;
+ d.fileInfo = QFileInfo(fileName);
setData(blob, d);
}
@@ -2237,7 +2235,7 @@ void QQmlTypeData::done()
qCDebug(DBG_DISK_CACHE) << "Checksum mismatch for cached version of" << m_compiledData->url().toString();
if (!loadFromSource())
return;
- m_backupSourceCode.clear();
+ m_backupSourceCode = SourceCodeData();
m_compiledData = nullptr;
}
@@ -2346,11 +2344,7 @@ bool QQmlTypeData::loadImplicitImport()
void QQmlTypeData::dataReceived(const SourceCodeData &data)
{
- QString error;
- m_backupSourceCode = data.readAll(&error, &m_sourceTimeStamp);
- // if we failed to read the source code, process it _after_ we've tried
- // to use the disk cache, in order to support scenarios where the source
- // was removed deliberately.
+ m_backupSourceCode = data;
if (tryLoadFromDiskCache())
return;
@@ -2358,8 +2352,8 @@ void QQmlTypeData::dataReceived(const SourceCodeData &data)
if (isError())
return;
- if (!error.isEmpty()) {
- setError(error);
+ if (!m_backupSourceCode.exists()) {
+ setError(QQmlTypeLoader::tr("No such file or directory"));
return;
}
@@ -2379,10 +2373,18 @@ void QQmlTypeData::initializeFromCachedUnit(const QQmlPrivate::CachedQmlUnit *un
bool QQmlTypeData::loadFromSource()
{
m_document.reset(new QmlIR::Document(isDebugging()));
- m_document->jsModule.sourceTimeStamp = m_sourceTimeStamp;
+ m_document->jsModule.sourceTimeStamp = m_backupSourceCode.sourceTimeStamp();
QQmlEngine *qmlEngine = typeLoader()->engine();
QmlIR::IRBuilder compiler(QV8Engine::get(qmlEngine)->illegalNames());
- if (!compiler.generateFromQml(m_backupSourceCode, finalUrlString(), m_document.data())) {
+
+ QString sourceError;
+ const QString source = m_backupSourceCode.readAll(&sourceError);
+ if (!sourceError.isEmpty()) {
+ setError(sourceError);
+ return false;
+ }
+
+ if (!compiler.generateFromQml(source, finalUrlString(), m_document.data())) {
QList<QQmlError> errors;
errors.reserve(compiler.errors.count());
for (const QQmlJS::DiagnosticMessage &msg : qAsConst(compiler.errors)) {
@@ -2891,8 +2893,9 @@ void QQmlScriptBlob::dataReceived(const SourceCodeData &data)
QmlIR::Document irUnit(isDebugging());
+ irUnit.jsModule.sourceTimeStamp = data.sourceTimeStamp();
QString error;
- QString source = data.readAll(&error, &irUnit.jsModule.sourceTimeStamp);
+ QString source = data.readAll(&error);
if (!error.isEmpty()) {
setError(error);
return;
@@ -3071,28 +3074,19 @@ void QQmlQmldirData::initializeFromCachedUnit(const QQmlPrivate::CachedQmlUnit *
Q_UNIMPLEMENTED();
}
-QString QQmlDataBlob::SourceCodeData::readAll(QString *error, qint64 *sourceTimeStamp) const
+QString QQmlDataBlob::SourceCodeData::readAll(QString *error) const
{
error->clear();
- if (sourceCodeAvailable) {
- if (sourceTimeStamp)
- *sourceTimeStamp = 0;
- return inlineSourceCodeOrFileName;
- }
- QFile f(inlineSourceCodeOrFileName);
+ if (!inlineSourceCode.isEmpty())
+ return inlineSourceCode;
+
+ QFile f(fileInfo.absoluteFilePath());
if (!f.open(QIODevice::ReadOnly)) {
*error = f.errorString();
return QString();
}
- if (sourceTimeStamp) {
- QDateTime timeStamp = QFileInfo(f).lastModified();
- // Files from the resource system do not have any time stamps, so fall back to the application
- // executable.
- if (!timeStamp.isValid())
- timeStamp = QFileInfo(QCoreApplication::applicationFilePath()).lastModified();
- *sourceTimeStamp = timeStamp.toMSecsSinceEpoch();
- }
- QByteArray data(f.size(), Qt::Uninitialized);
+
+ QByteArray data(fileInfo.size(), Qt::Uninitialized);
if (f.read(data.data(), data.length()) != data.length()) {
*error = f.errorString();
return QString();
@@ -3100,6 +3094,28 @@ QString QQmlDataBlob::SourceCodeData::readAll(QString *error, qint64 *sourceTime
return QString::fromUtf8(data);
}
+qint64 QQmlDataBlob::SourceCodeData::sourceTimeStamp() const
+{
+ if (!inlineSourceCode.isEmpty())
+ return 0;
+
+ QDateTime timeStamp = fileInfo.lastModified();
+ if (timeStamp.isValid())
+ return timeStamp.toMSecsSinceEpoch();
+
+ static qint64 appTimeStamp = 0;
+ if (appTimeStamp == 0)
+ appTimeStamp = QFileInfo(QCoreApplication::applicationFilePath()).lastModified().toMSecsSinceEpoch();
+ return appTimeStamp;
+}
+
+bool QQmlDataBlob::SourceCodeData::exists() const
+{
+ if (!inlineSourceCode.isEmpty())
+ return true;
+ return fileInfo.exists();
+}
+
QT_END_NAMESPACE
#include "qqmltypeloader.moc"
diff --git a/src/qml/qml/qqmltypeloader_p.h b/src/qml/qml/qqmltypeloader_p.h
index c1b3548fa6..0bae857874 100644
--- a/src/qml/qml/qqmltypeloader_p.h
+++ b/src/qml/qml/qqmltypeloader_p.h
@@ -54,6 +54,7 @@
#include <QtQml/qtqmlglobal.h>
#include <QtCore/qobject.h>
#include <QtCore/qatomic.h>
+#include <QtCore/qfileinfo.h>
#if QT_CONFIG(qml_network)
#include <QtNetwork/qnetworkreply.h>
#endif
@@ -132,12 +133,14 @@ public:
class SourceCodeData {
public:
- QString readAll(QString *error, qint64 *sourceTimeStamp = 0) const;
+ QString readAll(QString *error) const;
+ qint64 sourceTimeStamp() const;
+ bool exists() const;
private:
friend class QQmlDataBlob;
friend class QQmlTypeLoader;
- QString inlineSourceCodeOrFileName;
- bool sourceCodeAvailable = false;
+ QString inlineSourceCode;
+ QFileInfo fileInfo;
};
protected:
@@ -460,8 +463,7 @@ private:
void scriptImported(QQmlScriptBlob *blob, const QV4::CompiledData::Location &location, const QString &qualifier, const QString &nameSpace) override;
- qint64 m_sourceTimeStamp = 0;
- QString m_backupSourceCode; // used when cache verification fails.
+ SourceCodeData m_backupSourceCode; // used when cache verification fails.
QScopedPointer<QmlIR::Document> m_document;
QV4::CompiledData::TypeReferenceMap m_typeReferences;