diff options
Diffstat (limited to 'src/qml/common')
-rw-r--r-- | src/qml/common/qv4compileddata.cpp | 114 | ||||
-rw-r--r-- | src/qml/common/qv4compileddata_p.h | 8 |
2 files changed, 122 insertions, 0 deletions
diff --git a/src/qml/common/qv4compileddata.cpp b/src/qml/common/qv4compileddata.cpp new file mode 100644 index 0000000000..4ed53e6907 --- /dev/null +++ b/src/qml/common/qv4compileddata.cpp @@ -0,0 +1,114 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +#include "qv4compileddata_p.h" + +#include <QtQml/qqmlfile.h> + +#include <QtCore/qcryptographichash.h> +#include <QtCore/qdir.h> +#include <QtCore/qscopeguard.h> +#include <QtCore/qstandardpaths.h> + +QT_BEGIN_NAMESPACE + +namespace QV4 { +namespace CompiledData { + +QString CompilationUnit::localCacheFilePath(const QUrl &url) +{ + static const QByteArray envCachePath = qgetenv("QML_DISK_CACHE_PATH"); + + const QString localSourcePath = QQmlFile::urlToLocalFileOrQrc(url); + const QString cacheFileSuffix + = QFileInfo(localSourcePath + QLatin1Char('c')).completeSuffix(); + QCryptographicHash fileNameHash(QCryptographicHash::Sha1); + fileNameHash.addData(localSourcePath.toUtf8()); + QString directory = envCachePath.isEmpty() + ? QStandardPaths::writableLocation(QStandardPaths::CacheLocation) + + QLatin1String("/qmlcache/") + : QString::fromLocal8Bit(envCachePath) + QLatin1String("/"); + QDir::root().mkpath(directory); + return directory + QString::fromUtf8(fileNameHash.result().toHex()) + + QLatin1Char('.') + cacheFileSuffix; +} + +bool CompilationUnit::loadFromDisk( + const QUrl &url, const QDateTime &sourceTimeStamp, QString *errorString) +{ + if (!QQmlFile::isLocalFile(url)) { + *errorString = QStringLiteral("File has to be a local file."); + return false; + } + + const QString sourcePath = QQmlFile::urlToLocalFileOrQrc(url); + auto cacheFile = std::make_unique<CompilationUnitMapper>(); + + const QStringList cachePaths = { sourcePath + QLatin1Char('c'), localCacheFilePath(url) }; + for (const QString &cachePath : cachePaths) { + Unit *mappedUnit = cacheFile->get(cachePath, sourceTimeStamp, errorString); + if (!mappedUnit) + continue; + + const Unit *oldData = unitData(); + const Unit * const oldDataPtr + = (oldData && !(oldData->flags & Unit::StaticData)) + ? oldData + : nullptr; + + auto dataPtrRevert = qScopeGuard([this, oldData](){ + setUnitData(oldData); + }); + setUnitData(mappedUnit); + + if (mappedUnit->sourceFileIndex != 0) { + if (mappedUnit->sourceFileIndex >= + mappedUnit->stringTableSize + dynamicStrings.size()) { + *errorString = QStringLiteral("QML source file index is invalid."); + continue; + } + if (sourcePath != + QQmlFile::urlToLocalFileOrQrc(stringAt(mappedUnit->sourceFileIndex))) { + *errorString = QStringLiteral("QML source file has moved to a different location."); + continue; + } + } + + dataPtrRevert.dismiss(); + free(const_cast<Unit*>(oldDataPtr)); + backingFile = std::move(cacheFile); + return true; + } + + return false; +} + +bool CompilationUnit::saveToDisk(const QUrl &unitUrl, QString *errorString) +{ + if (unitData()->sourceTimeStamp == 0) { + *errorString = QStringLiteral("Missing time stamp for source file"); + return false; + } + + if (!QQmlFile::isLocalFile(unitUrl)) { + *errorString = QStringLiteral("File has to be a local file."); + return false; + } + + return SaveableUnitPointer(unitData()).saveToDisk<char>( + [&unitUrl, errorString](const char *data, quint32 size) { + const QString cachePath = localCacheFilePath(unitUrl); + if (SaveableUnitPointer::writeDataToFile( + cachePath, data, size, errorString)) { + CompilationUnitMapper::invalidate(cachePath); + return true; + } + + return false; + }); +} + +} // namespace CompiledData +} // namespace QV4 + +QT_END_NAMESPACE diff --git a/src/qml/common/qv4compileddata_p.h b/src/qml/common/qv4compileddata_p.h index 82424c1c9d..f7654661e2 100644 --- a/src/qml/common/qv4compileddata_p.h +++ b/src/qml/common/qv4compileddata_p.h @@ -32,6 +32,7 @@ #include <private/qendian_p.h> #include <private/qqmlrefcount_p.h> #include <private/qv4staticvalue_p.h> +#include <private/qv4compilationunitmapper_p.h> #include <functional> #include <limits.h> @@ -1434,6 +1435,8 @@ struct CompilationUnit final : public QQmlRefCounted<CompilationUnit> // pointers either to data->constants() or little-endian memory copy. const StaticValue *constants = nullptr; + + std::unique_ptr<CompilationUnitMapper> backingFile; public: using CompiledObject = CompiledData::Object; @@ -1550,6 +1553,11 @@ public: return constants[binding->value.constantValueIndex].doubleValue(); } + Q_QML_EXPORT static QString localCacheFilePath(const QUrl &url); + Q_QML_EXPORT bool loadFromDisk( + const QUrl &url, const QDateTime &sourceTimeStamp, QString *errorString); + Q_QML_EXPORT bool saveToDisk(const QUrl &unitUrl, QString *errorString); + private: QString m_fileName; // initialized from data->sourceFileIndex QString m_finalUrlString; // initialized from data->finalUrlIndex |