diff options
Diffstat (limited to 'src/qml/jsruntime/qv4executablecompilationunit.cpp')
-rw-r--r-- | src/qml/jsruntime/qv4executablecompilationunit.cpp | 466 |
1 files changed, 84 insertions, 382 deletions
diff --git a/src/qml/jsruntime/qv4executablecompilationunit.cpp b/src/qml/jsruntime/qv4executablecompilationunit.cpp index 898f911334..34d737cdae 100644 --- a/src/qml/jsruntime/qv4executablecompilationunit.cpp +++ b/src/qml/jsruntime/qv4executablecompilationunit.cpp @@ -17,36 +17,14 @@ #include <private/qqmlscriptdata_p.h> #include <private/qv4module_p.h> #include <private/qv4compilationunitmapper_p.h> -#include <private/qml_compile_hash_p.h> #include <private/qqmltypewrapper_p.h> -#include <private/inlinecomponentutils_p.h> #include <private/qv4resolvedtypereference_p.h> #include <private/qv4objectiterator_p.h> -#include <QtQml/qqmlfile.h> #include <QtQml/qqmlpropertymap.h> -#include <QtCore/qdir.h> -#include <QtCore/qstandardpaths.h> #include <QtCore/qfileinfo.h> -#include <QtCore/qscopeguard.h> #include <QtCore/qcryptographichash.h> -#include <QtCore/QScopedValueRollback> - -static_assert(QV4::CompiledData::QmlCompileHashSpace > QML_COMPILE_HASH_LENGTH); - -#if defined(QML_COMPILE_HASH) && defined(QML_COMPILE_HASH_LENGTH) && QML_COMPILE_HASH_LENGTH > 0 -# ifdef Q_OS_LINUX -// Place on a separate section on Linux so it's easier to check from outside -// what the hash version is. -__attribute__((section(".qml_compile_hash"))) -# endif -const char qml_compile_hash[QV4::CompiledData::QmlCompileHashSpace] = QML_COMPILE_HASH; -static_assert(sizeof(QV4::CompiledData::Unit::libraryVersionHash) > QML_COMPILE_HASH_LENGTH, - "Compile hash length exceeds reserved size in data structure. Please adjust and bump the format version"); -#else -# error "QML_COMPILE_HASH must be defined for the build of QtDeclarative to ensure version checking for cache files" -#endif QT_BEGIN_NAMESPACE @@ -55,28 +33,16 @@ namespace QV4 { ExecutableCompilationUnit::ExecutableCompilationUnit() = default; ExecutableCompilationUnit::ExecutableCompilationUnit( - CompiledData::CompilationUnit &&compilationUnit) - : CompiledData::CompilationUnit(std::move(compilationUnit)) -{} - -ExecutableCompilationUnit::~ExecutableCompilationUnit() + QQmlRefPointer<CompiledData::CompilationUnit> &&compilationUnit) + : m_compilationUnit(std::move(compilationUnit)) { - unlink(); + constants = m_compilationUnit->constants; } -QString ExecutableCompilationUnit::localCacheFilePath(const QUrl &url) +ExecutableCompilationUnit::~ExecutableCompilationUnit() { - 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; + if (engine) + clear(); } static QString toString(QV4::ReturnedValue v) @@ -104,25 +70,30 @@ static void dumpConstantTable(const StaticValue *constants, uint count) } } -QV4::Function *ExecutableCompilationUnit::linkToEngine(ExecutionEngine *engine) +void ExecutableCompilationUnit::populate() { - this->engine = engine; - engine->compilationUnits.insert(this); + /* In general, we should use QV4::Scope whenever we allocate heap objects, and employ write barriers + for member variables pointing to heap objects. However, ExecutableCompilationUnit is special, as it + is always part of the root set. So instead of using scopde allocations and write barriers, we use a + slightly different approach: We temporarily block the gc from running. Afterwards, at the end of the + function we check whether the gc was already running, and mark the ExecutableCompilationUnit. This + ensures that all the newly allocated objects of the compilation unit will be marked in turn. + If the gc was not running, we don't have to do anything, because everything will be marked when the + gc starts marking the root set at the start of a run. + */ + const CompiledData::Unit *data = m_compilationUnit->data; + GCCriticalSection<ExecutableCompilationUnit> criticalSection(engine, this); Q_ASSERT(!runtimeStrings); + Q_ASSERT(engine); Q_ASSERT(data); const quint32 stringCount = totalStringCount(); - runtimeStrings = (QV4::Heap::String **)malloc(stringCount * sizeof(QV4::Heap::String*)); - // memset the strings to 0 in case a GC run happens while we're within the loop below - memset(runtimeStrings, 0, stringCount * sizeof(QV4::Heap::String*)); + runtimeStrings = (QV4::Heap::String **)calloc(stringCount, sizeof(QV4::Heap::String*)); for (uint i = 0; i < stringCount; ++i) runtimeStrings[i] = engine->newString(stringAt(i)); runtimeRegularExpressions = new QV4::Value[data->regexpTableSize]; - // memset the regexps to 0 in case a GC run happens while we're within the loop below - memset(runtimeRegularExpressions, 0, - data->regexpTableSize * sizeof(QV4::Value)); for (uint i = 0; i < data->regexpTableSize; ++i) { const CompiledData::RegExp *re = data->regexpAt(i); uint f = re->flags(); @@ -155,11 +126,9 @@ QV4::Function *ExecutableCompilationUnit::linkToEngine(ExecutionEngine *engine) if (data->jsClassTableSize) { runtimeClasses - = (QV4::Heap::InternalClass **)malloc(data->jsClassTableSize - * sizeof(QV4::Heap::InternalClass *)); - // memset the regexps to 0 in case a GC run happens while we're within the loop below - memset(runtimeClasses, 0, - data->jsClassTableSize * sizeof(QV4::Heap::InternalClass *)); + = (QV4::Heap::InternalClass **)calloc(data->jsClassTableSize, + sizeof(QV4::Heap::InternalClass *)); + for (uint i = 0; i < data->jsClassTableSize; ++i) { int memberCount = 0; const CompiledData::JSClassMember *member @@ -182,13 +151,13 @@ QV4::Function *ExecutableCompilationUnit::linkToEngine(ExecutionEngine *engine) = qEnvironmentVariableIsSet("QV4_FORCE_INTERPRETER") || !(engine->diskCacheOptions() & ExecutionEngine::DiskCache::AotNative); - const QQmlPrivate::TypedFunction *aotFunction - = ignoreAotCompiledFunctions ? nullptr : aotCompiledFunctions; + const QQmlPrivate::AOTCompiledFunction *aotFunction + = ignoreAotCompiledFunctions ? nullptr : m_compilationUnit->aotCompiledFunctions; - auto advanceAotFunction = [&](int i) -> const QQmlPrivate::TypedFunction * { + auto advanceAotFunction = [&](int i) -> const QQmlPrivate::AOTCompiledFunction * { if (aotFunction) { if (aotFunction->functionPtr) { - if (aotFunction->extraData == i) + if (aotFunction->functionIndex == i) return aotFunction++; } else { aotFunction = nullptr; @@ -234,15 +203,14 @@ QV4::Function *ExecutableCompilationUnit::linkToEngine(ExecutionEngine *engine) << (data->indexOfRootFunction != -1 ? data->indexOfRootFunction : 0); } - - if (data->indexOfRootFunction != -1) - return runtimeFunctions[data->indexOfRootFunction]; - else - return nullptr; } Heap::Object *ExecutableCompilationUnit::templateObjectAt(int index) const { + const CompiledData::Unit *data = m_compilationUnit->data; + Q_ASSERT(data); + Q_ASSERT(engine); + Q_ASSERT(index < int(data->templateObjectTableSize)); if (!templateObjects.size()) templateObjects.resize(data->templateObjectTableSize); @@ -271,33 +239,17 @@ Heap::Object *ExecutableCompilationUnit::templateObjectAt(int index) const return templateObjects.at(index); } -void ExecutableCompilationUnit::unlink() +void ExecutableCompilationUnit::clear() { - if (engine) - nextCompilationUnit.remove(); - - if (isRegistered) { - Q_ASSERT(data && propertyCaches.count() > 0 && propertyCaches.at(/*root object*/0)); - QQmlMetaType::unregisterInternalCompositeType(this); - } - - propertyCaches.clear(); + delete [] imports; + imports = nullptr; if (runtimeLookups) { - for (uint i = 0; i < data->lookupTableSize; ++i) + const uint lookupTableSize = unitData()->lookupTableSize; + for (uint i = 0; i < lookupTableSize; ++i) runtimeLookups[i].releasePropertyCache(); } - dependentScripts.clear(); - - typeNameCache.reset(); - - qDeleteAll(resolvedTypes); - resolvedTypes.clear(); - - engine = nullptr; - qmlEngine = nullptr; - delete [] runtimeLookups; runtimeLookups = nullptr; @@ -313,8 +265,10 @@ void ExecutableCompilationUnit::unlink() runtimeClasses = nullptr; } -void ExecutableCompilationUnit::markObjects(QV4::MarkStack *markStack) +void ExecutableCompilationUnit::markObjects(QV4::MarkStack *markStack) const { + const CompiledData::Unit *data = m_compilationUnit->data; + if (runtimeStrings) { for (uint i = 0, end = totalStringCount(); i < end; ++i) if (runtimeStrings[i]) @@ -362,174 +316,29 @@ IdentifierHash ExecutableCompilationUnit::createNamedObjectsPerComponent(int com return *namedObjectsPerComponentCache.insert(componentObjectIndex, namedObjectCache); } -void ExecutableCompilationUnit::finalizeCompositeType(QQmlEnginePrivate *qmlEngine, CompositeMetaTypeIds types) -{ - this->qmlEngine = qmlEngine; - - // Add to type registry of composites - if (propertyCaches.needsVMEMetaObject(/*root object*/0)) { - // typeIds is only valid for types that have references to themselves. - if (!types.isValid()) - types = CompositeMetaTypeIds::fromCompositeName(rootPropertyCache()->className()); - typeIds = types; - QQmlMetaType::registerInternalCompositeType(this); - - } else { - const QV4::CompiledData::Object *obj = objectAt(/*root object*/0); - auto *typeRef = resolvedTypes.value(obj->inheritedTypeNameIndex); - Q_ASSERT(typeRef); - if (const auto compilationUnit = typeRef->compilationUnit()) { - typeIds = compilationUnit->typeIds; - } else { - const auto type = typeRef->type(); - typeIds = CompositeMetaTypeIds{ type.typeId(), type.qListTypeId() }; - } - } - - // Collect some data for instantiation later. - using namespace icutils; - std::vector<QV4::CompiledData::InlineComponent> allICs {}; - for (int i=0; i != objectCount(); ++i) { - const CompiledObject *obj = objectAt(i); - for (auto it = obj->inlineComponentsBegin(); it != obj->inlineComponentsEnd(); ++it) { - allICs.push_back(*it); - } - } - std::vector<Node> nodes; - nodes.resize(allICs.size()); - std::iota(nodes.begin(), nodes.end(), 0); - AdjacencyList adjacencyList; - adjacencyList.resize(nodes.size()); - fillAdjacencyListForInlineComponents(this, adjacencyList, nodes, allICs); - bool hasCycle = false; - auto nodesSorted = topoSort(nodes, adjacencyList, hasCycle); - Q_ASSERT(!hasCycle); // would have already been discovered by qqmlpropertycachcecreator - - // We need to first iterate over all inline components, as the containing component might create instances of them - // and in that case we need to add its object count - for (auto nodeIt = nodesSorted.rbegin(); nodeIt != nodesSorted.rend(); ++nodeIt) { - const auto &ic = allICs.at(nodeIt->index()); - int lastICRoot = ic.objectIndex; - for (int i = ic.objectIndex; i<objectCount(); ++i) { - const QV4::CompiledData::Object *obj = objectAt(i); - bool leftCurrentInlineComponent - = (i != lastICRoot - && obj->hasFlag(QV4::CompiledData::Object::IsInlineComponentRoot)) - || !obj->hasFlag(QV4::CompiledData::Object::IsPartOfInlineComponent); - if (leftCurrentInlineComponent) - break; - inlineComponentData[lastICRoot].totalBindingCount += obj->nBindings; - - if (auto *typeRef = resolvedTypes.value(obj->inheritedTypeNameIndex)) { - const auto type = typeRef->type(); - if (type.isValid() && type.parserStatusCast() != -1) - ++inlineComponentData[lastICRoot].totalParserStatusCount; - - ++inlineComponentData[lastICRoot].totalObjectCount; - if (const auto compilationUnit = typeRef->compilationUnit()) { - // if the type is an inline component type, we have to extract the information from it - // This requires that inline components are visited in the correct order - auto icRoot = compilationUnit->icRoot; - if (type.isInlineComponentType()) - icRoot = type.inlineComponentId(); - QScopedValueRollback<int> rollback {compilationUnit->icRoot, icRoot}; - inlineComponentData[lastICRoot].totalBindingCount += compilationUnit->totalBindingsCount(); - inlineComponentData[lastICRoot].totalParserStatusCount += compilationUnit->totalParserStatusCount(); - inlineComponentData[lastICRoot].totalObjectCount += compilationUnit->totalObjectCount(); - } - } - } - } - int bindingCount = 0; - int parserStatusCount = 0; - int objectCount = 0; - for (quint32 i = 0, count = this->objectCount(); i < count; ++i) { - const QV4::CompiledData::Object *obj = objectAt(i); - if (obj->hasFlag(QV4::CompiledData::Object::IsPartOfInlineComponent)) - continue; - - bindingCount += obj->nBindings; - if (auto *typeRef = resolvedTypes.value(obj->inheritedTypeNameIndex)) { - const auto type = typeRef->type(); - if (type.isValid() && type.parserStatusCast() != -1) - ++parserStatusCount; - ++objectCount; - if (const auto compilationUnit = typeRef->compilationUnit()) { - auto icRoot = compilationUnit->icRoot; - if (type.isInlineComponentType()) - icRoot = type.inlineComponentId(); - QScopedValueRollback<int> rollback {compilationUnit->icRoot, icRoot}; - bindingCount += compilationUnit->totalBindingsCount(); - parserStatusCount += compilationUnit->totalParserStatusCount(); - objectCount += compilationUnit->totalObjectCount(); - } - } - } - - m_totalBindingsCount = bindingCount; - m_totalParserStatusCount = parserStatusCount; - m_totalObjectCount = objectCount; -} - -int ExecutableCompilationUnit::totalBindingsCount() const { - if (icRoot == -1) - return m_totalBindingsCount; - return inlineComponentData[icRoot].totalBindingCount; -} - -int ExecutableCompilationUnit::totalObjectCount() const { - if (icRoot == -1) - return m_totalObjectCount; - return inlineComponentData[icRoot].totalObjectCount; -} - -int ExecutableCompilationUnit::totalParserStatusCount() const { - if (icRoot == -1) - return m_totalParserStatusCount; - return inlineComponentData[icRoot].totalParserStatusCount; -} - -bool ExecutableCompilationUnit::verifyChecksum(const CompiledData::DependentTypesHasher &dependencyHasher) const +QQmlRefPointer<ExecutableCompilationUnit> ExecutableCompilationUnit::create( + QQmlRefPointer<CompiledData::CompilationUnit> &&compilationUnit, ExecutionEngine *engine) { - if (!dependencyHasher) { - for (size_t i = 0; i < sizeof(data->dependencyMD5Checksum); ++i) { - if (data->dependencyMD5Checksum[i] != 0) - return false; - } - return true; - } - const QByteArray checksum = dependencyHasher(); - return checksum.size() == sizeof(data->dependencyMD5Checksum) - && memcmp(data->dependencyMD5Checksum, checksum.constData(), - sizeof(data->dependencyMD5Checksum)) == 0; -} - -CompositeMetaTypeIds ExecutableCompilationUnit::typeIdsForComponent(int objectid) const -{ - if (objectid == 0) - return typeIds; - return inlineComponentData[objectid].typeIds; + auto result = QQmlRefPointer<ExecutableCompilationUnit>( + new ExecutableCompilationUnit(std::move(compilationUnit)), + QQmlRefPointer<ExecutableCompilationUnit>::Adopt); + result->engine = engine; + return result; } -QStringList ExecutableCompilationUnit::moduleRequests() const +Heap::Module *ExecutableCompilationUnit::instantiate() { - QStringList requests; - requests.reserve(data->moduleRequestTableSize); - for (uint i = 0; i < data->moduleRequestTableSize; ++i) - requests << stringAt(data->moduleRequestTable()[i]); - return requests; -} + const CompiledData::Unit *data = m_compilationUnit->data; -Heap::Module *ExecutableCompilationUnit::instantiate(ExecutionEngine *engine) -{ if (isESModule() && module()) return module(); if (data->indexOfRootFunction < 0) return nullptr; - if (!this->engine) - linkToEngine(engine); + Q_ASSERT(engine); + if (!runtimeStrings) + populate(); Scope scope(engine); Scoped<Module> module(scope, engine->memoryManager->allocate<Module>(engine, this)); @@ -537,13 +346,14 @@ Heap::Module *ExecutableCompilationUnit::instantiate(ExecutionEngine *engine) if (isESModule()) setModule(module->d()); - for (const QString &request: moduleRequests()) { + const QStringList moduleRequests = m_compilationUnit->moduleRequests(); + for (const QString &request: moduleRequests) { const QUrl url(request); const auto dependentModuleUnit = engine->loadModule(url, this); if (engine->hasException) return nullptr; if (dependentModuleUnit.compiled) - dependentModuleUnit.compiled->instantiate(engine); + dependentModuleUnit.compiled->instantiate(); } ScopedString importName(scope); @@ -657,6 +467,11 @@ const Value *ExecutableCompilationUnit::resolveExportRecursively( if (exportName->toQString() == QLatin1String("*")) return &module()->self; + const CompiledData::Unit *data = m_compilationUnit->data; + + Q_ASSERT(data); + Q_ASSERT(engine); + Scope scope(engine); if (auto localExport = lookupNameInExportTable( @@ -767,6 +582,11 @@ void ExecutableCompilationUnit::getExportedNamesRecursively( names->append(name); }; + const CompiledData::Unit *data = m_compilationUnit->data; + + Q_ASSERT(data); + Q_ASSERT(engine); + for (uint i = 0; i < data->localExportEntryTableSize; ++i) { const CompiledData::ExportEntry &entry = data->localExportEntryTable()[i]; append(stringAt(entry.exportName)); @@ -799,6 +619,8 @@ void ExecutableCompilationUnit::getExportedNamesRecursively( void ExecutableCompilationUnit::evaluate() { + Q_ASSERT(engine); + QV4::Scope scope(engine); QV4::Scoped<Module> mod(scope, module()); mod->evaluate(); @@ -806,7 +628,10 @@ void ExecutableCompilationUnit::evaluate() void ExecutableCompilationUnit::evaluateModuleRequests() { - for (const QString &request: moduleRequests()) { + Q_ASSERT(engine); + + const QStringList moduleRequests = m_compilationUnit->moduleRequests(); + for (const QString &request: moduleRequests) { auto dependentModule = engine->loadModule(QUrl(request), this); if (dependentModule.native) continue; @@ -821,88 +646,6 @@ void ExecutableCompilationUnit::evaluateModuleRequests() } } -bool ExecutableCompilationUnit::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) { - CompiledData::Unit *mappedUnit = cacheFile->get(cachePath, sourceTimeStamp, errorString); - if (!mappedUnit) - continue; - - const CompiledData::Unit * const oldDataPtr - = (data && !(data->flags & QV4::CompiledData::Unit::StaticData)) ? data - : nullptr; - const CompiledData::Unit *oldData = data; - auto dataPtrRevert = qScopeGuard([this, oldData](){ - setUnitData(oldData); - }); - setUnitData(mappedUnit); - - if (data->sourceFileIndex != 0 - && sourcePath != QQmlFile::urlToLocalFileOrQrc(stringAt(data->sourceFileIndex))) { - *errorString = QStringLiteral("QML source file has moved to a different location."); - continue; - } - - dataPtrRevert.dismiss(); - free(const_cast<CompiledData::Unit*>(oldDataPtr)); - backingFile = std::move(cacheFile); - return true; - } - - return false; -} - -bool ExecutableCompilationUnit::saveToDisk(const QUrl &unitUrl, QString *errorString) -{ - if (data->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 CompiledData::SaveableUnitPointer(unitData()).saveToDisk<char>( - [&unitUrl, errorString](const char *data, quint32 size) { - return CompiledData::SaveableUnitPointer::writeDataToFile(localCacheFilePath(unitUrl), data, - size, errorString); - }); -} - -/*! - \internal - This function creates a temporary key vector and sorts it to guarantuee a stable - hash. This is used to calculate a check-sum on dependent meta-objects. - */ -bool ResolvedTypeReferenceMap::addToHash( - QCryptographicHash *hash, QHash<quintptr, QByteArray> *checksums) const -{ - std::vector<int> keys (size()); - int i = 0; - for (auto it = constBegin(), end = constEnd(); it != end; ++it) { - keys[i] = it.key(); - ++i; - } - std::sort(keys.begin(), keys.end()); - for (int key: keys) { - if (!this->operator[](key)->addToHash(hash, checksums)) - return false; - } - - return true; -} - QString ExecutableCompilationUnit::bindingValueAsString(const CompiledData::Binding *binding) const { #if QT_CONFIG(translation) @@ -919,7 +662,7 @@ QString ExecutableCompilationUnit::bindingValueAsString(const CompiledData::Bind break; } #endif - return CompilationUnit::bindingValueAsString(binding); + return m_compilationUnit->bindingValueAsString(binding); } QString ExecutableCompilationUnit::translateFrom(TranslationDataIndex index) const @@ -927,7 +670,7 @@ QString ExecutableCompilationUnit::translateFrom(TranslationDataIndex index) con #if !QT_CONFIG(translation) return QString(); #else - const CompiledData::TranslationData &translation = data->translations()[index.index]; + const CompiledData::TranslationData &translation = unitData()->translations()[index.index]; if (index.byId) { QByteArray id = stringAt(translation.stringIndex).toUtf8(); @@ -945,62 +688,21 @@ QString ExecutableCompilationUnit::translateFrom(TranslationDataIndex index) con return context.toUtf8(); }; - QByteArray context = stringAt(translation.contextIndex).toUtf8(); - QByteArray comment = stringAt(translation.commentIndex).toUtf8(); - QByteArray text = stringAt(translation.stringIndex).toUtf8(); - return QCoreApplication::translate( - context.isEmpty() ? fileContext() : context, text, comment, translation.number); -#endif -} - -bool ExecutableCompilationUnit::verifyHeader( - const CompiledData::Unit *unit, QDateTime expectedSourceTimeStamp, QString *errorString) -{ - if (strncmp(unit->magic, CompiledData::magic_str, sizeof(unit->magic))) { - *errorString = QStringLiteral("Magic bytes in the header do not match"); - return false; - } - - if (unit->version != quint32(QV4_DATA_STRUCTURE_VERSION)) { - *errorString = QString::fromUtf8("V4 data structure version mismatch. Found %1 expected %2") - .arg(unit->version, 0, 16).arg(QV4_DATA_STRUCTURE_VERSION, 0, 16); - return false; - } - - if (unit->qtVersion != quint32(QT_VERSION)) { - *errorString = QString::fromUtf8("Qt version mismatch. Found %1 expected %2") - .arg(unit->qtVersion, 0, 16).arg(QT_VERSION, 0, 16); - return false; - } - - if (unit->sourceTimeStamp) { - // Files from the resource system do not have any time stamps, so fall back to the application - // executable. - if (!expectedSourceTimeStamp.isValid()) - expectedSourceTimeStamp = QFileInfo(QCoreApplication::applicationFilePath()).lastModified(); - - if (expectedSourceTimeStamp.isValid() - && expectedSourceTimeStamp.toMSecsSinceEpoch() != unit->sourceTimeStamp) { - *errorString = QStringLiteral("QML source file has a different time stamp than cached file."); - return false; - } + const bool hasContext + = translation.contextIndex != QV4::CompiledData::TranslationData::NoContextIndex; + QByteArray context; + if (hasContext) { + context = stringAt(translation.contextIndex).toUtf8(); + } else { + auto pragmaTranslationContext = unitData()->translationContextIndex(); + context = stringAt(*pragmaTranslationContext).toUtf8(); + context = context.isEmpty() ? fileContext() : context; } -#if defined(QML_COMPILE_HASH) && defined(QML_COMPILE_HASH_LENGTH) && QML_COMPILE_HASH_LENGTH > 0 - if (qstrncmp(qml_compile_hash, unit->libraryVersionHash, QML_COMPILE_HASH_LENGTH) != 0) { - *errorString = QStringLiteral("QML compile hashes don't match. Found %1 expected %2") - .arg(QString::fromLatin1( - QByteArray(unit->libraryVersionHash, QML_COMPILE_HASH_LENGTH) - .toPercentEncoding()), - QString::fromLatin1( - QByteArray(qml_compile_hash, QML_COMPILE_HASH_LENGTH) - .toPercentEncoding())); - return false; - } -#else -#error "QML_COMPILE_HASH must be defined for the build of QtDeclarative to ensure version checking for cache files" + QByteArray comment = stringAt(translation.commentIndex).toUtf8(); + QByteArray text = stringAt(translation.stringIndex).toUtf8(); + return QCoreApplication::translate(context, text, comment, translation.number); #endif - return true; } } // namespace QV4 |