From a2184b9ab7469bc5ca36478394243a04cda9006c Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Fri, 4 Mar 2022 14:56:36 +0100 Subject: QQmlPropertyCache: Store checksums in type loader The type loader is specific to the engine. This way we can calculate/retrieve the checksum without modifying the property cache, which makes checksum() threadsafe. The checksums are only needed for loading and storing compilation units from/to disk. Therefore, there is no point in keeping them inside the property caches anyway. Pick-to: 6.3 Task-number: QTBUG-73271 Change-Id: I7bea65e73769f76352bb5947d7229e256e7f2f25 Reviewed-by: Fabian Kosmale --- src/qml/jsruntime/qv4executablecompilationunit.cpp | 5 +++-- src/qml/jsruntime/qv4executablecompilationunit_p.h | 2 +- src/qml/jsruntime/qv4resolvedtypereference.cpp | 5 +++-- src/qml/jsruntime/qv4resolvedtypereference_p.h | 2 +- src/qml/qml/qqmlpropertycache.cpp | 24 ++++++++++++++-------- src/qml/qml/qqmlpropertycache_p.h | 3 +-- src/qml/qml/qqmltypedata.cpp | 10 +++++---- src/qml/qml/qqmltypeloader.cpp | 1 + src/qml/qml/qqmltypeloader_p.h | 4 ++++ 9 files changed, 35 insertions(+), 21 deletions(-) diff --git a/src/qml/jsruntime/qv4executablecompilationunit.cpp b/src/qml/jsruntime/qv4executablecompilationunit.cpp index 7c02391a1a..6e0d07210c 100644 --- a/src/qml/jsruntime/qv4executablecompilationunit.cpp +++ b/src/qml/jsruntime/qv4executablecompilationunit.cpp @@ -858,7 +858,8 @@ bool ExecutableCompilationUnit::saveToDisk(const QUrl &unitUrl, QString *errorSt 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) const +bool ResolvedTypeReferenceMap::addToHash( + QCryptographicHash *hash, QHash *checksums) const { std::vector keys (count()); int i = 0; @@ -868,7 +869,7 @@ bool ResolvedTypeReferenceMap::addToHash(QCryptographicHash *hash) const } std::sort(keys.begin(), keys.end()); for (int key: keys) { - if (!this->operator[](key)->addToHash(hash)) + if (!this->operator[](key)->addToHash(hash, checksums)) return false; } diff --git a/src/qml/jsruntime/qv4executablecompilationunit_p.h b/src/qml/jsruntime/qv4executablecompilationunit_p.h index 6798829898..c093033aab 100644 --- a/src/qml/jsruntime/qv4executablecompilationunit_p.h +++ b/src/qml/jsruntime/qv4executablecompilationunit_p.h @@ -94,7 +94,7 @@ class ResolvedTypeReference; // map from name index struct ResolvedTypeReferenceMap: public QHash { - bool addToHash(QCryptographicHash *hash) const; + bool addToHash(QCryptographicHash *hash, QHash *checksums) const; }; class Q_QML_PRIVATE_EXPORT ExecutableCompilationUnit final: public CompiledData::CompilationUnit, diff --git a/src/qml/jsruntime/qv4resolvedtypereference.cpp b/src/qml/jsruntime/qv4resolvedtypereference.cpp index 96bddccf83..4ac68611f4 100644 --- a/src/qml/jsruntime/qv4resolvedtypereference.cpp +++ b/src/qml/jsruntime/qv4resolvedtypereference.cpp @@ -100,11 +100,12 @@ QQmlRefPointer ResolvedTypeReference::createPropertyCache() } } -bool ResolvedTypeReference::addToHash(QCryptographicHash *hash) +bool ResolvedTypeReference::addToHash( + QCryptographicHash *hash, QHash *checksums) { if (m_type.isValid() && !m_type.isInlineComponentType()) { bool ok = false; - hash->addData(createPropertyCache()->checksum(&ok)); + hash->addData(createPropertyCache()->checksum(checksums, &ok)); return ok; } if (!m_compilationUnit) diff --git a/src/qml/jsruntime/qv4resolvedtypereference_p.h b/src/qml/jsruntime/qv4resolvedtypereference_p.h index 61e683ce17..582c3a5d0a 100644 --- a/src/qml/jsruntime/qv4resolvedtypereference_p.h +++ b/src/qml/jsruntime/qv4resolvedtypereference_p.h @@ -75,7 +75,7 @@ public: QQmlRefPointer propertyCache() const; QQmlRefPointer createPropertyCache(); - bool addToHash(QCryptographicHash *hash); + bool addToHash(QCryptographicHash *hash, QHash *checksums); void doDynamicTypeCheck(); diff --git a/src/qml/qml/qqmlpropertycache.cpp b/src/qml/qml/qqmlpropertycache.cpp index 66e83c1655..035098d4c5 100644 --- a/src/qml/qml/qqmlpropertycache.cpp +++ b/src/qml/qml/qqmlpropertycache.cpp @@ -1256,35 +1256,41 @@ bool QQmlPropertyCache::addToHash(QCryptographicHash &hash, const QMetaObject &m return true; } -QByteArray QQmlPropertyCache::checksum(bool *ok) +QByteArray QQmlPropertyCache::checksum(QHash *checksums, bool *ok) const { - if (!_checksum.isEmpty()) { + auto it = checksums->constFind(quintptr(this)); + if (it != checksums->constEnd()) { *ok = true; - return _checksum; + return *it; } // Generate a checksum on the meta-object data only on C++ types. if (!_metaObject || _metaObject.isShared()) { *ok = false; - return _checksum; + return QByteArray(); } QCryptographicHash hash(QCryptographicHash::Md5); if (_parent) { - hash.addData(_parent->checksum(ok)); + hash.addData(_parent->checksum(checksums, ok)); if (!*ok) return QByteArray(); } - if (!addToHash(hash, *createMetaObject())) { + if (!addToHash(hash, *_metaObject)) { *ok = false; return QByteArray(); } - _checksum = hash.result(); - *ok = !_checksum.isEmpty(); - return _checksum; + const QByteArray result = hash.result(); + if (result.isEmpty()) { + *ok = false; + } else { + *ok = true; + checksums->insert(quintptr(this), result); + } + return result; } /*! \internal diff --git a/src/qml/qml/qqmlpropertycache_p.h b/src/qml/qml/qqmlpropertycache_p.h index 68830ba716..4c10de7823 100644 --- a/src/qml/qml/qqmlpropertycache_p.h +++ b/src/qml/qml/qqmlpropertycache_p.h @@ -247,7 +247,7 @@ public: static bool determineMetaObjectSizes(const QMetaObject &mo, int *fieldCount, int *stringCount); static bool addToHash(QCryptographicHash &hash, const QMetaObject &mo); - QByteArray checksum(bool *ok); + QByteArray checksum(QHash *checksums, bool *ok) const; QTypeRevision allowedRevision(int index) const { return allowedRevisionCache[index]; } void setAllowedRevision(int index, QTypeRevision allowed) { allowedRevisionCache[index] = allowed; } @@ -333,7 +333,6 @@ private: QByteArray _listPropertyAssignBehavior; QString _defaultPropertyName; QQmlPropertyCacheMethodArguments *argumentsCache = nullptr; - QByteArray _checksum; int methodIndexCacheStart = 0; int signalHandlerIndexCacheStart = 0; int _jsFactoryMethodIndex = -1; diff --git a/src/qml/qml/qqmltypedata.cpp b/src/qml/qml/qqmltypedata.cpp index aa3be1cabf..448bae3cc5 100644 --- a/src/qml/qml/qqmltypedata.cpp +++ b/src/qml/qml/qqmltypedata.cpp @@ -253,7 +253,8 @@ void QQmlTypeData::createTypeAndPropertyCaches( } static bool addTypeReferenceChecksumsToHash( - const QList &typeRefs, QCryptographicHash *hash) + const QList &typeRefs, + QHash *checksums, QCryptographicHash *hash) { for (const auto &typeRef: typeRefs) { if (typeRef.typeData) { @@ -262,7 +263,7 @@ static bool addTypeReferenceChecksumsToHash( } else if (typeRef.type.isValid()) { const auto propertyCache = QQmlMetaType::propertyCache(typeRef.type.metaObject()); bool ok = false; - hash->addData(propertyCache->checksum(&ok)); + hash->addData(propertyCache->checksum(checksums, &ok)); if (!ok) return false; } @@ -420,8 +421,9 @@ void QQmlTypeData::done() const auto dependencyHasher = [&resolvedTypeCache, this]() { QCryptographicHash hash(QCryptographicHash::Md5); - return (resolvedTypeCache.addToHash(&hash) - && ::addTypeReferenceChecksumsToHash(m_compositeSingletons, &hash)) + return (resolvedTypeCache.addToHash(&hash, typeLoader()->checksumCache()) + && ::addTypeReferenceChecksumsToHash( + m_compositeSingletons, typeLoader()->checksumCache(), &hash)) ? hash.result() : QByteArray(); }; diff --git a/src/qml/qml/qqmltypeloader.cpp b/src/qml/qml/qqmltypeloader.cpp index 59c9f858f6..b41f15a7c2 100644 --- a/src/qml/qml/qqmltypeloader.cpp +++ b/src/qml/qml/qqmltypeloader.cpp @@ -1220,6 +1220,7 @@ void QQmlTypeLoader::clearCache() m_qmldirCache.clear(); m_importDirCache.clear(); m_importQmlDirCache.clear(); + m_checksumCache.clear(); QQmlMetaType::freeUnusedTypesAndCaches(); } diff --git a/src/qml/qml/qqmltypeloader_p.h b/src/qml/qml/qqmltypeloader_p.h index eb6e549911..10f96df735 100644 --- a/src/qml/qml/qqmltypeloader_p.h +++ b/src/qml/qml/qqmltypeloader_p.h @@ -78,6 +78,7 @@ class Q_QML_PRIVATE_EXPORT QQmlTypeLoader { Q_DECLARE_TR_FUNCTIONS(QQmlTypeLoader) public: + using ChecksumCache = QHash; enum Mode { PreferSynchronous, Asynchronous, Synchronous }; class Q_QML_PRIVATE_EXPORT Blob : public QQmlDataBlob @@ -141,6 +142,8 @@ public: ~QQmlTypeLoader(); QQmlImportDatabase *importDatabase() const; + ChecksumCache *checksumCache() { return &m_checksumCache; } + const ChecksumCache *checksumCache() const { return &m_checksumCache; } static QUrl normalize(const QUrl &unNormalizedUrl); @@ -247,6 +250,7 @@ private: QmldirCache m_qmldirCache; ImportDirCache m_importDirCache; ImportQmlDirCache m_importQmlDirCache; + ChecksumCache m_checksumCache; template void doLoad(const Loader &loader, QQmlDataBlob *blob, Mode mode); -- cgit v1.2.3