diff options
author | Ulf Hermann <ulf.hermann@qt.io> | 2020-03-24 19:31:55 +0100 |
---|---|---|
committer | Ulf Hermann <ulf.hermann@qt.io> | 2020-03-25 10:42:41 +0100 |
commit | b1f53bf6eaabc9caa4f1eb523ad605c6719c752c (patch) | |
tree | ca35ef9014a3d273b2616b137b552fa9e2197c19 /src/qml/jsruntime | |
parent | 20370505b3b38a5eaa73692557cd80a0ecc60bff (diff) |
QML: Avoid cyclic references between ResolvedTypeRefence and CU
The compilation unit keeps a list of references to used types. Usually
those are references to types in other compilation units. However, in
the case of inline components they can be references to the same
compilation unit. In that case we should not addref() the compilation
unit, as that forms a cyclic reference.
Fixes: QTBUG-82768
Change-Id: I29d28f3a4780aad4fabd4aa2ed02ca0d0108987e
Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
Diffstat (limited to 'src/qml/jsruntime')
-rw-r--r-- | src/qml/jsruntime/qv4executablecompilationunit.cpp | 46 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4executablecompilationunit_p.h | 66 |
2 files changed, 79 insertions, 33 deletions
diff --git a/src/qml/jsruntime/qv4executablecompilationunit.cpp b/src/qml/jsruntime/qv4executablecompilationunit.cpp index fa4a1f1ce4..29e1c6dbf7 100644 --- a/src/qml/jsruntime/qv4executablecompilationunit.cpp +++ b/src/qml/jsruntime/qv4executablecompilationunit.cpp @@ -406,9 +406,9 @@ void ExecutableCompilationUnit::finalizeCompositeType(QQmlEnginePrivate *qmlEngi const QV4::CompiledData::Object *obj = objectAt(/*root object*/0); auto *typeRef = resolvedTypes.value(obj->inheritedTypeNameIndex); Q_ASSERT(typeRef); - if (typeRef->compilationUnit) { - metaTypeId = typeRef->compilationUnit->metaTypeId; - listMetaTypeId = typeRef->compilationUnit->listMetaTypeId; + if (const auto compilationUnit = typeRef->compilationUnit()) { + metaTypeId = compilationUnit->metaTypeId; + listMetaTypeId = compilationUnit->listMetaTypeId; } else { metaTypeId = typeRef->type.typeId(); listMetaTypeId = typeRef->type.qListTypeId(); @@ -453,17 +453,17 @@ void ExecutableCompilationUnit::finalizeCompositeType(QQmlEnginePrivate *qmlEngi ++inlineComponentData[lastICRoot].totalParserStatusCount; ++inlineComponentData[lastICRoot].totalObjectCount; - if (typeRef->compilationUnit) { + 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 = typeRef->compilationUnit->icRoot; + auto icRoot = compilationUnit->icRoot; if (typeRef->type.isInlineComponentType()) { icRoot = typeRef->type.inlineComponendId(); } - QScopedValueRollback<int> rollback {typeRef->compilationUnit->icRoot, icRoot}; - inlineComponentData[lastICRoot].totalBindingCount += typeRef->compilationUnit->totalBindingsCount(); - inlineComponentData[lastICRoot].totalParserStatusCount += typeRef->compilationUnit->totalParserStatusCount(); - inlineComponentData[lastICRoot].totalObjectCount += typeRef->compilationUnit->totalObjectCount(); + QScopedValueRollback<int> rollback {compilationUnit->icRoot, icRoot}; + inlineComponentData[lastICRoot].totalBindingCount += compilationUnit->totalBindingsCount(); + inlineComponentData[lastICRoot].totalParserStatusCount += compilationUnit->totalParserStatusCount(); + inlineComponentData[lastICRoot].totalObjectCount += compilationUnit->totalObjectCount(); } } } @@ -481,15 +481,15 @@ void ExecutableCompilationUnit::finalizeCompositeType(QQmlEnginePrivate *qmlEngi if (typeRef->type.isValid() && typeRef->type.parserStatusCast() != -1) ++parserStatusCount; ++objectCount; - if (typeRef->compilationUnit) { - auto icRoot = typeRef->compilationUnit->icRoot; + if (const auto compilationUnit = typeRef->compilationUnit()) { + auto icRoot = compilationUnit->icRoot; if (typeRef->type.isInlineComponentType()) { icRoot = typeRef->type.inlineComponendId(); } - QScopedValueRollback<int> rollback {typeRef->compilationUnit->icRoot, icRoot}; - bindingCount += typeRef->compilationUnit->totalBindingsCount(); - parserStatusCount += typeRef->compilationUnit->totalParserStatusCount(); - objectCount += typeRef->compilationUnit->totalObjectCount(); + QScopedValueRollback<int> rollback {compilationUnit->icRoot, icRoot}; + bindingCount += compilationUnit->totalBindingsCount(); + parserStatusCount += compilationUnit->totalParserStatusCount(); + objectCount += compilationUnit->totalObjectCount(); } } } @@ -806,7 +806,7 @@ QQmlRefPointer<QQmlPropertyCache> ResolvedTypeReference::propertyCache() const if (type.isValid()) return typePropertyCache; else - return compilationUnit->rootPropertyCache(); + return m_compilationUnit->rootPropertyCache(); } /*! @@ -820,8 +820,8 @@ QQmlRefPointer<QQmlPropertyCache> ResolvedTypeReference::createPropertyCache(QQm typePropertyCache = QQmlEnginePrivate::get(engine)->cache(type.metaObject(), minorVersion); return typePropertyCache; } else { - Q_ASSERT(compilationUnit); - return compilationUnit->rootPropertyCache(); + Q_ASSERT(m_compilationUnit); + return m_compilationUnit->rootPropertyCache(); } } @@ -832,10 +832,10 @@ bool ResolvedTypeReference::addToHash(QCryptographicHash *hash, QQmlEngine *engi hash->addData(createPropertyCache(engine)->checksum(&ok)); return ok; } - if (!compilationUnit) + if (!m_compilationUnit) return false; - hash->addData(compilationUnit->data->md5Checksum, - sizeof(compilationUnit->data->md5Checksum)); + hash->addData(m_compilationUnit->data->md5Checksum, + sizeof(m_compilationUnit->data->md5Checksum)); return true; } @@ -856,8 +856,8 @@ void ResolvedTypeReference::doDynamicTypeCheck() mo = typePropertyCache->firstCppMetaObject(); else if (type.isValid()) mo = type.metaObject(); - else if (compilationUnit) - mo = compilationUnit->rootPropertyCache()->firstCppMetaObject(); + else if (m_compilationUnit) + mo = m_compilationUnit->rootPropertyCache()->firstCppMetaObject(); isFullyDynamicType = qtTypeInherits<QQmlPropertyMap>(mo); } diff --git a/src/qml/jsruntime/qv4executablecompilationunit_p.h b/src/qml/jsruntime/qv4executablecompilationunit_p.h index 8cad18a3dc..7bfb68da9d 100644 --- a/src/qml/jsruntime/qv4executablecompilationunit_p.h +++ b/src/qml/jsruntime/qv4executablecompilationunit_p.h @@ -325,27 +325,73 @@ private: struct ResolvedTypeReference { +public: ResolvedTypeReference() - : majorVersion(0) - , minorVersion(0) - , isFullyDynamicType(false) + : m_compilationUnit(nullptr) + , m_stronglyReferencesCompilationUnit(true) + , majorVersion(0) + , minorVersion(0) + , isFullyDynamicType(false) {} + ~ResolvedTypeReference() + { + if (m_stronglyReferencesCompilationUnit && m_compilationUnit) + m_compilationUnit->release(); + } + + QQmlRefPointer<QV4::ExecutableCompilationUnit> compilationUnit() { return m_compilationUnit; } + void setCompilationUnit(QQmlRefPointer<QV4::ExecutableCompilationUnit> unit) + { + if (m_compilationUnit == unit.data()) + return; + if (m_stronglyReferencesCompilationUnit) { + if (m_compilationUnit) + m_compilationUnit->release(); + m_compilationUnit = unit.take(); + } else { + m_compilationUnit = unit.data(); + } + } + + bool referencesCompilationUnit() const { return m_stronglyReferencesCompilationUnit; } + void setReferencesCompilationUnit(bool doReference) + { + if (doReference == m_stronglyReferencesCompilationUnit) + return; + m_stronglyReferencesCompilationUnit = doReference; + if (!m_compilationUnit) + return; + if (doReference) { + m_compilationUnit->addref(); + } else if (m_compilationUnit->count() == 1) { + m_compilationUnit->release(); + m_compilationUnit = nullptr; + } else { + m_compilationUnit->release(); + } + } + + QQmlRefPointer<QQmlPropertyCache> propertyCache() const; + QQmlRefPointer<QQmlPropertyCache> createPropertyCache(QQmlEngine *); + bool addToHash(QCryptographicHash *hash, QQmlEngine *engine); + + void doDynamicTypeCheck(); + QQmlType type; QQmlRefPointer<QQmlPropertyCache> typePropertyCache; - QQmlRefPointer<QV4::ExecutableCompilationUnit> compilationUnit; +private: + Q_DISABLE_COPY_MOVE(ResolvedTypeReference) + + QV4::ExecutableCompilationUnit *m_compilationUnit; + bool m_stronglyReferencesCompilationUnit; +public: int majorVersion; int minorVersion; // Types such as QQmlPropertyMap can add properties dynamically at run-time and // therefore cannot have a property cache installed when instantiated. bool isFullyDynamicType; - - QQmlRefPointer<QQmlPropertyCache> propertyCache() const; - QQmlRefPointer<QQmlPropertyCache> createPropertyCache(QQmlEngine *); - bool addToHash(QCryptographicHash *hash, QQmlEngine *engine); - - void doDynamicTypeCheck(); }; IdentifierHash ExecutableCompilationUnit::namedObjectsPerComponent(int componentObjectIndex) |