43 *errorString = QStringLiteral(
"Magic bytes in the header do not match");
48 *errorString = QString::fromUtf8(
"V4 data structure version mismatch. Found %1 expected %2")
53 if (qtVersion != quint32(QT_VERSION)) {
54 *errorString = QString::fromUtf8(
"Qt version mismatch. Found %1 expected %2")
55 .arg(qtVersion, 0, 16).arg(QT_VERSION, 0, 16);
59 if (sourceTimeStamp) {
62 if (!expectedSourceTimeStamp.isValid())
63 expectedSourceTimeStamp = QFileInfo(QCoreApplication::applicationFilePath()).lastModified();
65 if (expectedSourceTimeStamp.isValid()
66 && expectedSourceTimeStamp.toMSecsSinceEpoch() != sourceTimeStamp) {
67 *errorString = QStringLiteral(
"QML source file has a different time stamp than cached file.");
72#if defined(QML_COMPILE_HASH) && defined(QML_COMPILE_HASH_LENGTH) && QML_COMPILE_HASH_LENGTH > 0
73 if (qstrncmp(qml_compile_hash, libraryVersionHash, QML_COMPILE_HASH_LENGTH) != 0) {
74 *errorString = QStringLiteral(
"QML compile hashes don't match. Found %1 expected %2")
75 .arg(QString::fromLatin1(
76 QByteArray(libraryVersionHash, QML_COMPILE_HASH_LENGTH)
77 .toPercentEncoding()),
79 QByteArray(qml_compile_hash, QML_COMPILE_HASH_LENGTH)
80 .toPercentEncoding()));
84#error "QML_COMPILE_HASH must be defined for the build of QtDeclarative to ensure version checking for cache files"
139 static const QByteArray envCachePath = qgetenv(
"QML_DISK_CACHE_PATH");
141 const QString localSourcePath = QQmlFile::urlToLocalFileOrQrc(url);
142 const QString cacheFileSuffix
143 = QFileInfo(localSourcePath + QLatin1Char(
'c')).completeSuffix();
144 QCryptographicHash fileNameHash(QCryptographicHash::Sha1);
145 fileNameHash.addData(localSourcePath.toUtf8());
146 QString directory = envCachePath.isEmpty()
147 ? QStandardPaths::writableLocation(QStandardPaths::CacheLocation)
148 + QLatin1String(
"/qmlcache/")
149 : QString::fromLocal8Bit(envCachePath) + QLatin1String(
"/");
150 QDir::root().mkpath(directory);
151 return directory + QString::fromUtf8(fileNameHash.result().toHex())
152 + QLatin1Char(
'.') + cacheFileSuffix;
156 const QUrl &url,
const QDateTime &sourceTimeStamp, QString *errorString)
158 if (!QQmlFile::isLocalFile(url)) {
159 *errorString = QStringLiteral(
"File has to be a local file.");
163 const QString sourcePath = QQmlFile::urlToLocalFileOrQrc(url);
164 auto cacheFile = std::make_unique<CompilationUnitMapper>();
166 const QStringList cachePaths = { sourcePath + QLatin1Char(
'c'), localCacheFilePath(url) };
167 for (
const QString &cachePath : cachePaths) {
168 Unit *mappedUnit = cacheFile->get(cachePath, sourceTimeStamp, errorString);
172 const Unit *oldData = unitData();
173 const Unit *
const oldDataPtr
174 = (oldData && !(oldData->flags & Unit::StaticData))
178 auto dataPtrRevert = qScopeGuard([
this, oldData](){
179 setUnitData(oldData);
181 setUnitData(mappedUnit);
183 if (mappedUnit->sourceFileIndex != 0) {
184 if (mappedUnit->sourceFileIndex >=
185 mappedUnit->stringTableSize + dynamicStrings.size()) {
186 *errorString = QStringLiteral(
"QML source file index is invalid.");
190 QQmlFile::urlToLocalFileOrQrc(stringAt(mappedUnit->sourceFileIndex))) {
191 *errorString = QStringLiteral(
"QML source file has moved to a different location.");
196 dataPtrRevert.dismiss();
197 free(
const_cast<Unit*>(oldDataPtr));
198 backingFile = std::move(cacheFile);
208 *errorString = QStringLiteral(
"Missing time stamp for source file");
212 if (!QQmlFile::isLocalFile(unitUrl)) {
213 *errorString = QStringLiteral(
"File has to be a local file.");
217 return SaveableUnitPointer(
unitData()).saveToDisk<
char>(
218 [&unitUrl, errorString](
const char *data, quint32 size) {
219 const QString cachePath = localCacheFilePath(unitUrl);
220 if (SaveableUnitPointer::writeDataToFile(
221 cachePath, data, size, errorString)) {
222 CompilationUnitMapper::invalidate(cachePath);
278 if (propertyCaches.needsVMEMetaObject(0)) {
280 if (type.isValid()) {
283 qmlType = QQmlMetaType::findCompositeType(
284 url(),
this, (unitData()->flags & CompiledData::Unit::IsSingleton)
285 ? QQmlMetaType::Singleton
286 : QQmlMetaType::NonSingleton);
289 QQmlMetaType::registerInternalCompositeType(
this);
292 auto *typeRef =
resolvedTypes.value(obj->inheritedTypeNameIndex);
294 if (
const auto compilationUnit = typeRef->compilationUnit())
295 qmlType = compilationUnit->qmlType;
297 qmlType = typeRef->type();
301 using namespace icutils;
302 std::vector<QV4::CompiledData::InlineComponent> allICs {};
306 allICs.push_back(*it);
310 nodes.resize(allICs.size());
311 std::iota(nodes.begin(), nodes.end(), 0);
312 AdjacencyList adjacencyList;
313 adjacencyList.resize(nodes.size());
314 fillAdjacencyListForInlineComponents(
this, adjacencyList, nodes, allICs);
315 bool hasCycle =
false;
316 auto nodesSorted = topoSort(nodes, adjacencyList, hasCycle);
322 for (
auto nodeIt = nodesSorted.rbegin(); nodeIt != nodesSorted.rend(); ++nodeIt) {
323 const auto &ic = allICs.at(nodeIt->index());
324 const int lastICRoot = ic.objectIndex;
327 bool leftCurrentInlineComponent
331 if (leftCurrentInlineComponent)
333 const QString lastICRootName = stringAt(ic.nameIndex);
334 inlineComponentData[lastICRootName].totalBindingCount
337 if (
auto *typeRef = resolvedTypes.value(obj->inheritedTypeNameIndex)) {
338 const auto type = typeRef->type();
339 if (type.isValid() && type.parserStatusCast() != -1)
340 ++inlineComponentData[lastICRootName].totalParserStatusCount;
342 ++inlineComponentData[lastICRootName].totalObjectCount;
343 if (
const auto compilationUnit = typeRef->compilationUnit()) {
347 processInlinComponentType(type, [&](
const QString ¤tlyVisitedICName) {
348 auto &icData = inlineComponentData[lastICRootName];
349 icData.totalBindingCount += compilationUnit->totalBindingsCount(currentlyVisitedICName);
350 icData.totalParserStatusCount += compilationUnit->totalParserStatusCount(currentlyVisitedICName);
351 icData.totalObjectCount += compilationUnit->totalObjectCount(currentlyVisitedICName);
357 int bindingCount = 0;
358 int parserStatusCount = 0;
360 for (quint32 i = 0, count =
this->objectCount(); i < count; ++i) {
361 const QV4::CompiledData::Object *obj = objectAt(i);
362 if (obj->hasFlag(QV4::CompiledData::Object::IsPartOfInlineComponent))
365 bindingCount += obj->nBindings;
366 if (
auto *typeRef = resolvedTypes.value(obj->inheritedTypeNameIndex)) {
367 const auto type = typeRef->type();
368 if (type.isValid() && type.parserStatusCast() != -1)
371 if (
const auto compilationUnit = typeRef->compilationUnit()) {
372 processInlinComponentType(type, [&](
const QString ¤tlyVisitedICName){
373 bindingCount += compilationUnit->totalBindingsCount(currentlyVisitedICName);
374 parserStatusCount += compilationUnit->totalParserStatusCount(currentlyVisitedICName);
375 objectCount += compilationUnit->totalObjectCount(currentlyVisitedICName);
381 m_totalBindingsCount = bindingCount;
395 if (!dependencyHasher) {
396 for (size_t i = 0; i <
sizeof(data->dependencyMD5Checksum); ++i) {
397 if (data->dependencyMD5Checksum[i] != 0)
402 const QByteArray checksum = dependencyHasher();
403 return checksum.size() ==
sizeof(data->dependencyMD5Checksum)
404 && memcmp(data->dependencyMD5Checksum, checksum.constData(),
405 sizeof(data->dependencyMD5Checksum)) == 0;