From 29e4b97bad6511ebd6aa009a47594395957c0e8e Mon Sep 17 00:00:00 2001 From: Simon Hausmann Date: Thu, 16 Aug 2018 11:45:27 +0200 Subject: Add support for disk caching of ES modules Two minor fixes needed for this otherwise straight-forward change: (1) When compiling modules, use the full url for the source file of the compilation unit, as that's what we use for the relocation check when loading the cache file. (2) Record the proper source time stamp for cache invalidation. As a bonus, when importing scripts from .qml files, we now also attempt to use the cached version that we created on the fly in an effort to replace heap memory with mmap backed memory - just like we do for .qml files. Change-Id: I5b03a18e3c44d537c3242cb1d969636df32fe42a Reviewed-by: Lars Knoll --- src/qml/jsruntime/qv4engine.cpp | 14 +++++++++----- src/qml/jsruntime/qv4engine_p.h | 4 ++-- src/qml/qml/qqmltypeloader.cpp | 15 ++++++++++----- src/qml/qml/qqmltypeloader_p.h | 2 ++ 4 files changed, 23 insertions(+), 12 deletions(-) (limited to 'src') diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp index 14bc5f084e..c5eec33d18 100644 --- a/src/qml/jsruntime/qv4engine.cpp +++ b/src/qml/jsruntime/qv4engine.cpp @@ -1633,17 +1633,19 @@ QQmlRefPointer ExecutionEngine::compileModule(con return nullptr; } + const QDateTime timeStamp = QFileInfo(f).lastModified(); + const QString sourceCode = QString::fromUtf8(f.readAll()); f.close(); - return compileModule(url, sourceCode); + return compileModule(url, sourceCode, timeStamp); } -QQmlRefPointer ExecutionEngine::compileModule(const QUrl &url, const QString &sourceCode) +QQmlRefPointer ExecutionEngine::compileModule(const QUrl &url, const QString &sourceCode, const QDateTime &sourceTimeStamp) { QList diagnostics; - auto unit = compileModule(/*debugMode*/debugger() != nullptr, url, sourceCode, &diagnostics); + auto unit = compileModule(/*debugMode*/debugger() != nullptr, url, sourceCode, sourceTimeStamp, &diagnostics); for (const QQmlJS::DiagnosticMessage &m : diagnostics) { if (m.isError()) { throwSyntaxError(m.message, url.toString(), m.loc.startLine, m.loc.startColumn); @@ -1656,7 +1658,8 @@ QQmlRefPointer ExecutionEngine::compileModule(con return unit; } -QQmlRefPointer ExecutionEngine::compileModule(bool debugMode, const QUrl &url, const QString &sourceCode, QList *diagnostics) +QQmlRefPointer ExecutionEngine::compileModule(bool debugMode, const QUrl &url, const QString &sourceCode, + const QDateTime &sourceTimeStamp, QList *diagnostics) { QQmlJS::Engine ee; QQmlJS::Lexer lexer(&ee); @@ -1683,9 +1686,10 @@ QQmlRefPointer ExecutionEngine::compileModule(boo using namespace QV4::Compiler; Compiler::Module compilerModule(debugMode); compilerModule.unitFlags |= CompiledData::Unit::IsESModule; + compilerModule.sourceTimeStamp = sourceTimeStamp; JSUnitGenerator jsGenerator(&compilerModule); Codegen cg(&jsGenerator, /*strictMode*/true); - cg.generateFromModule(url.fileName(), url.toString(), sourceCode, moduleNode, &compilerModule); + cg.generateFromModule(url.toString(), url.toString(), sourceCode, moduleNode, &compilerModule); auto errors = cg.errors(); if (diagnostics) *diagnostics << errors; diff --git a/src/qml/jsruntime/qv4engine_p.h b/src/qml/jsruntime/qv4engine_p.h index 8312adee48..c8f8efaebf 100644 --- a/src/qml/jsruntime/qv4engine_p.h +++ b/src/qml/jsruntime/qv4engine_p.h @@ -577,8 +577,8 @@ public: #ifndef V4_BOOTSTRAP QQmlRefPointer compileModule(const QUrl &url); - QQmlRefPointer compileModule(const QUrl &url, const QString &sourceCode); - static QQmlRefPointer compileModule(bool debugMode, const QUrl &url, const QString &sourceCode, QList *diagnostics); + QQmlRefPointer compileModule(const QUrl &url, const QString &sourceCode, const QDateTime &sourceTimeStamp); + static QQmlRefPointer compileModule(bool debugMode, const QUrl &url, const QString &sourceCode, const QDateTime &sourceTimeStamp, QList *diagnostics); mutable QMutex moduleMutex; QHash> modules; diff --git a/src/qml/qml/qqmltypeloader.cpp b/src/qml/qml/qqmltypeloader.cpp index daa4604dca..209a32b8cc 100644 --- a/src/qml/qml/qqmltypeloader.cpp +++ b/src/qml/qml/qqmltypeloader.cpp @@ -3003,7 +3003,7 @@ void QQmlScriptBlob::dataReceived(const SourceCodeData &data) if (m_isModule) { QList diagnostics; - unit = QV4::ExecutionEngine::compileModule(isDebugging(), url(), source, &diagnostics); + unit = QV4::ExecutionEngine::compileModule(isDebugging(), url(), source, data.sourceTimeStamp(), &diagnostics); QList errors = QQmlEnginePrivate::qmlErrorFromDiagnostics(urlString(), diagnostics); if (!errors.isEmpty()) { setError(errors); @@ -3034,12 +3034,17 @@ void QQmlScriptBlob::dataReceived(const SourceCodeData &data) QmlIR::QmlUnitGenerator qmlGenerator; qmlGenerator.generate(irUnit); + } - if ((!disableDiskCache() || forceDiskCache()) && !isDebugging()) { - QString errorString; - if (!unit->saveToDisk(url(), &errorString)) { - qCDebug(DBG_DISK_CACHE()) << "Error saving cached version of" << unit->fileName() << "to disk:" << errorString; + if ((!disableDiskCache() || forceDiskCache()) && !isDebugging()) { + QString errorString; + if (unit->saveToDisk(url(), &errorString)) { + QString error; + if (!unit->loadFromDisk(url(), data.sourceTimeStamp(), &error)) { + // ignore error, keep using the in-memory compilation unit. } + } else { + qCDebug(DBG_DISK_CACHE()) << "Error saving cached version of" << unit->fileName() << "to disk:" << errorString; } } diff --git a/src/qml/qml/qqmltypeloader_p.h b/src/qml/qml/qqmltypeloader_p.h index 26090c6af7..5d85773be3 100644 --- a/src/qml/qml/qqmltypeloader_p.h +++ b/src/qml/qml/qqmltypeloader_p.h @@ -542,6 +542,8 @@ public: QV4::ReturnedValue scriptValueForContext(QQmlContextData *parentCtxt); + QQmlRefPointer compilationUnit() const { return m_precompiledScript; } + protected: void clear() override; // From QQmlCleanup -- cgit v1.2.3