From 65a02ef32f7131f5e0b87dd18b4f81486d507ae3 Mon Sep 17 00:00:00 2001 From: Simon Hausmann Date: Fri, 17 Jan 2014 12:16:07 +0100 Subject: [new compiler] Fix refcounting leaks with property caches The TypeReference is not copy-safe, as it holds refcounted property cache pointers. For the new compiler code path, don't copy them but keep pointers to TypeReference objects around. Also make sure to ref the root property cache correctly and avoid the unnecessary addref for the property cache when creating new vme meta objects (initial refcount is 1). Change-Id: I0c4b952c8300c2167d926d9c35b8579fd505d596 Reviewed-by: Lars Knoll --- src/qml/compiler/qqmlcodegenerator.cpp | 10 +++-- src/qml/compiler/qqmltypecompiler.cpp | 80 +++++++++++++++++++--------------- src/qml/compiler/qqmltypecompiler_p.h | 8 ++-- src/qml/qml/qqmlcompileddata.cpp | 12 ++--- src/qml/qml/qqmlcompiler_p.h | 2 +- src/qml/qml/qqmlobjectcreator.cpp | 15 ++++--- src/qml/qml/qqmlobjectcreator_p.h | 2 +- 7 files changed, 72 insertions(+), 57 deletions(-) diff --git a/src/qml/compiler/qqmlcodegenerator.cpp b/src/qml/compiler/qqmlcodegenerator.cpp index 22ae1228c7..46bb07f8bc 100644 --- a/src/qml/compiler/qqmlcodegenerator.cpp +++ b/src/qml/compiler/qqmlcodegenerator.cpp @@ -1639,8 +1639,8 @@ bool SignalHandlerConverter::convertSignalHandlerExpressionsToFunctionDeclaratio QString elementName = stringAt(obj->inheritedTypeNameIndex); if (elementName.isEmpty()) continue; - QQmlCompiledData::TypeReference &tr = unit->resolvedTypes[obj->inheritedTypeNameIndex]; - if (tr.type && tr.type->customParser()) + QQmlCompiledData::TypeReference *tr = unit->resolvedTypes.value(obj->inheritedTypeNameIndex); + if (tr && tr->type && tr->type->customParser()) continue; QQmlPropertyCache *cache = unit->propertyCaches.value(objectIndex); Q_ASSERT(cache); @@ -1660,7 +1660,8 @@ bool SignalHandlerConverter::convertSignalHandlerExpressionsToFunctionDeclaratio // Attached property? if (binding->type == QV4::CompiledData::Binding::Type_AttachedProperty) { QmlObject *attachedObj = parsedQML->objects[binding->value.objectIndex]; - QQmlType *type = unit->resolvedTypes.value(binding->propertyNameIndex).type; + QQmlCompiledData::TypeReference *typeRef = unit->resolvedTypes.value(binding->propertyNameIndex); + QQmlType *type = typeRef ? typeRef->type : 0; const QMetaObject *attachedType = type ? type->attachedPropertiesType() : 0; if (!attachedType) COMPILE_EXCEPTION(binding->location, tr("Non-existent attached object")); @@ -1703,7 +1704,8 @@ bool SignalHandlerConverter::convertSignalHandlerExpressionsToFunctionDeclaratio const QString &originalPropertyName = stringAt(binding->propertyNameIndex); - const QQmlType *type = unit->resolvedTypes.value(obj->inheritedTypeNameIndex).type; + QQmlCompiledData::TypeReference *typeRef = unit->resolvedTypes.value(obj->inheritedTypeNameIndex); + const QQmlType *type = typeRef ? typeRef->type : 0; if (type) { COMPILE_EXCEPTION(binding->location, tr("\"%1.%2\" is not available in %3 %4.%5.").arg(typeName).arg(originalPropertyName).arg(type->module()).arg(type->majorVersion()).arg(type->minorVersion())); } else { diff --git a/src/qml/compiler/qqmltypecompiler.cpp b/src/qml/compiler/qqmltypecompiler.cpp index 91f5535f9c..4fe3008003 100644 --- a/src/qml/compiler/qqmltypecompiler.cpp +++ b/src/qml/compiler/qqmltypecompiler.cpp @@ -80,16 +80,16 @@ bool QQmlTypeCompiler::compile() const QHash &resolvedTypes = typeData->resolvedTypeRefs(); for (QHash::ConstIterator resolvedType = resolvedTypes.constBegin(), end = resolvedTypes.constEnd(); resolvedType != end; ++resolvedType) { - QQmlCompiledData::TypeReference ref; + QQmlCompiledData::TypeReference *ref = new QQmlCompiledData::TypeReference; if (resolvedType->typeData) { - ref.component = resolvedType->typeData->compiledData(); - ref.component->addref(); + ref->component = resolvedType->typeData->compiledData(); + ref->component->addref(); } else { - ref.type = resolvedType->type; - Q_ASSERT(ref.type); + ref->type = resolvedType->type; + Q_ASSERT(ref->type); } - ref.majorVersion = resolvedType->majorVersion; - ref.minorVersion = resolvedType->minorVersion; + ref->majorVersion = resolvedType->majorVersion; + ref->minorVersion = resolvedType->minorVersion; compiledData->resolvedTypes.insert(resolvedType.key(), ref); } @@ -175,13 +175,14 @@ bool QQmlTypeCompiler::compile() engine->registerInternalCompositeType(compiledData); else { const QV4::CompiledData::Object *obj = qmlUnit->objectAt(qmlUnit->indexOfRootObject); - QQmlCompiledData::TypeReference typeRef = compiledData->resolvedTypes.value(obj->inheritedTypeNameIndex); - if (typeRef.component) { - compiledData->metaTypeId = typeRef.component->metaTypeId; - compiledData->listMetaTypeId = typeRef.component->listMetaTypeId; + QQmlCompiledData::TypeReference *typeRef = compiledData->resolvedTypes.value(obj->inheritedTypeNameIndex); + Q_ASSERT(typeRef); + if (typeRef->component) { + compiledData->metaTypeId = typeRef->component->metaTypeId; + compiledData->listMetaTypeId = typeRef->component->listMetaTypeId; } else { - compiledData->metaTypeId = typeRef.type->typeId(); - compiledData->listMetaTypeId = typeRef.type->qListTypeId(); + compiledData->metaTypeId = typeRef->type->typeId(); + compiledData->listMetaTypeId = typeRef->type->qListTypeId(); } } @@ -220,7 +221,7 @@ const QQmlImports *QQmlTypeCompiler::imports() const return &typeData->imports(); } -QHash *QQmlTypeCompiler::resolvedTypes() +QHash *QQmlTypeCompiler::resolvedTypes() { return &compiledData->resolvedTypes; } @@ -241,6 +242,7 @@ void QQmlTypeCompiler::setPropertyCaches(const QVector &cac compiledData->propertyCaches = caches; Q_ASSERT(caches.count() >= parsedQML->indexOfRootObject); compiledData->rootPropertyCache = caches.at(parsedQML->indexOfRootObject); + compiledData->rootPropertyCache->addref(); } const QVector &QQmlTypeCompiler::propertyCaches() const @@ -369,8 +371,9 @@ bool QQmlPropertyCacheCreator::buildMetaObjectRecursively(int objectIndex, int r QString typeName = stringAt(obj->inheritedTypeNameIndex); if (!typeName.isEmpty()) { - QQmlCompiledData::TypeReference typeRef = resolvedTypes->value(obj->inheritedTypeNameIndex); - baseTypeCache = typeRef.createPropertyCache(QQmlEnginePrivate::get(enginePrivate)); + QQmlCompiledData::TypeReference *typeRef = resolvedTypes->value(obj->inheritedTypeNameIndex); + Q_ASSERT(typeRef); + baseTypeCache = typeRef->createPropertyCache(QQmlEnginePrivate::get(enginePrivate)); Q_ASSERT(baseTypeCache); } @@ -395,8 +398,9 @@ bool QQmlPropertyCacheCreator::ensureMetaObject(int objectIndex) if (!vmeMetaObjects.at(objectIndex).isEmpty()) return true; const QtQml::QmlObject *obj = qmlObjects.at(objectIndex); - QQmlCompiledData::TypeReference typeRef = resolvedTypes->value(obj->inheritedTypeNameIndex); - QQmlPropertyCache *baseTypeCache = typeRef.createPropertyCache(QQmlEnginePrivate::get(enginePrivate)); + QQmlCompiledData::TypeReference *typeRef = resolvedTypes->value(obj->inheritedTypeNameIndex); + Q_ASSERT(typeRef); + QQmlPropertyCache *baseTypeCache = typeRef->createPropertyCache(QQmlEnginePrivate::get(enginePrivate)); return createMetaObject(objectIndex, obj, baseTypeCache); } @@ -407,7 +411,6 @@ bool QQmlPropertyCacheCreator::createMetaObject(int objectIndex, const QtQml::Qm obj->functions->count + obj->properties->count + obj->qmlSignals->count, obj->qmlSignals->count + obj->properties->count); propertyCaches[objectIndex] = cache; - cache->addref(); struct TypeData { QV4::CompiledData::Property::Type dtype; @@ -776,7 +779,9 @@ void QQmlComponentAndAliasResolver::findAndRegisterImplicitComponents(const QtQm continue; const QtQml::QmlObject *targetObject = qmlObjects->at(binding->value.objectIndex); - QQmlType *targetType = resolvedTypes->value(targetObject->inheritedTypeNameIndex).type; + QQmlCompiledData::TypeReference *tr = resolvedTypes->value(targetObject->inheritedTypeNameIndex); + Q_ASSERT(tr); + QQmlType *targetType = tr->type; if (targetType && targetType->metaObject() == &QQmlComponent::staticMetaObject) continue; @@ -813,10 +818,10 @@ void QQmlComponentAndAliasResolver::findAndRegisterImplicitComponents(const QtQm syntheticComponent->init(pool, compiler->registerString(QString::fromUtf8(componentType->typeName())), compiler->registerString(QString())); if (!resolvedTypes->contains(syntheticComponent->inheritedTypeNameIndex)) { - QQmlCompiledData::TypeReference typeRef; - typeRef.type = componentType; - typeRef.majorVersion = componentType->majorVersion(); - typeRef.minorVersion = componentType->minorVersion(); + QQmlCompiledData::TypeReference *typeRef = new QQmlCompiledData::TypeReference; + typeRef->type = componentType; + typeRef->majorVersion = componentType->majorVersion(); + typeRef->minorVersion = componentType->minorVersion(); resolvedTypes->insert(syntheticComponent->inheritedTypeNameIndex, typeRef); } @@ -847,10 +852,11 @@ bool QQmlComponentAndAliasResolver::resolve() if (stringAt(obj->inheritedTypeNameIndex).isEmpty()) continue; - QQmlCompiledData::TypeReference tref = resolvedTypes->value(obj->inheritedTypeNameIndex); - if (!tref.type) + QQmlCompiledData::TypeReference *tref = resolvedTypes->value(obj->inheritedTypeNameIndex); + Q_ASSERT(tref); + if (!tref->type) continue; - if (tref.type->metaObject() != &QQmlComponent::staticMetaObject) { + if (tref->type->metaObject() != &QQmlComponent::staticMetaObject) { findAndRegisterImplicitComponents(obj, i); continue; } @@ -995,12 +1001,13 @@ bool QQmlComponentAndAliasResolver::resolveAliases() if (property.isEmpty()) { const QtQml::QmlObject *targetObject = qmlObjects->at(targetObjectIndex); - QQmlCompiledData::TypeReference typeRef = resolvedTypes->value(targetObject->inheritedTypeNameIndex); + QQmlCompiledData::TypeReference *typeRef = resolvedTypes->value(targetObject->inheritedTypeNameIndex); + Q_ASSERT(typeRef); - if (typeRef.type) - type = typeRef.type->typeId(); + if (typeRef->type) + type = typeRef->type->typeId(); else - type = typeRef.component->metaTypeId; + type = typeRef->component->metaTypeId; flags |= QML_ALIAS_FLAG_PTR; propertyFlags |= QQmlPropertyData::IsQObjectDerived; @@ -1125,9 +1132,10 @@ bool QQmlPropertyValidator::validateObject(int objectIndex) Q_ASSERT(propertyCache); QQmlCustomParser *customParser = 0; - QQmlCompiledData::TypeReference objectType = resolvedTypes.value(obj->inheritedTypeNameIndex); - if (objectType.type) - customParser = objectType.type->customParser(); + QQmlCompiledData::TypeReference *objectType = resolvedTypes.value(obj->inheritedTypeNameIndex); + Q_ASSERT(objectType); + if (objectType->type) + customParser = objectType->type->customParser(); QList customBindings; PropertyResolver propertyResolver(propertyCache); @@ -1162,8 +1170,8 @@ bool QQmlPropertyValidator::validateObject(int objectIndex) if (notInRevision) { QString typeName = stringAt(obj->inheritedTypeNameIndex); - if (objectType.type) { - COMPILE_EXCEPTION(binding, tr("\"%1.%2\" is not available in %3 %4.%5.").arg(typeName).arg(name).arg(objectType.type->module()).arg(objectType.majorVersion).arg(objectType.minorVersion)); + if (objectType->type) { + COMPILE_EXCEPTION(binding, tr("\"%1.%2\" is not available in %3 %4.%5.").arg(typeName).arg(name).arg(objectType->type->module()).arg(objectType->majorVersion).arg(objectType->minorVersion)); } else { COMPILE_EXCEPTION(binding, tr("\"%1.%2\" is not available due to component versioning.").arg(typeName).arg(name)); } diff --git a/src/qml/compiler/qqmltypecompiler_p.h b/src/qml/compiler/qqmltypecompiler_p.h index 4fde8f58c2..e6a34fa376 100644 --- a/src/qml/compiler/qqmltypecompiler_p.h +++ b/src/qml/compiler/qqmltypecompiler_p.h @@ -81,7 +81,7 @@ struct QQmlTypeCompiler QQmlEnginePrivate *enginePrivate() const { return engine; } const QQmlImports *imports() const; - QHash *resolvedTypes(); + QHash *resolvedTypes(); QList *qmlObjects(); int rootObjectIndex() const; void setPropertyCaches(const QVector &caches); @@ -130,7 +130,7 @@ protected: QQmlEnginePrivate *enginePrivate; const QList &qmlObjects; const QQmlImports *imports; - QHash *resolvedTypes; + QHash *resolvedTypes; QVector vmeMetaObjects; QVector propertyCaches; }; @@ -165,7 +165,7 @@ protected: QHash *_objectIndexToIdInScope; QList _objectsWithAliases; - QHash *resolvedTypes; + QHash *resolvedTypes; const QVector propertyCaches; QVector *vmeMetaObjectData; QHash *objectIndexToIdForRoot; @@ -190,7 +190,7 @@ private: bool isComponent(int objectIndex) const { return objectIndexToIdPerComponent.contains(objectIndex); } const QV4::CompiledData::QmlUnit *qmlUnit; - const QHash &resolvedTypes; + const QHash &resolvedTypes; const QVector &propertyCaches; const QHash > objectIndexToIdPerComponent; QHash *customParserData; diff --git a/src/qml/qml/qqmlcompileddata.cpp b/src/qml/qml/qqmlcompileddata.cpp index 76bf24fe6b..cc8fcdb6ba 100644 --- a/src/qml/qml/qqmlcompileddata.cpp +++ b/src/qml/qml/qqmlcompileddata.cpp @@ -117,13 +117,15 @@ QQmlCompiledData::~QQmlCompiledData() types.at(ii).typePropertyCache->release(); } - for (QHash::Iterator resolvedType = resolvedTypes.begin(), end = resolvedTypes.end(); + for (QHash::Iterator resolvedType = resolvedTypes.begin(), end = resolvedTypes.end(); resolvedType != end; ++resolvedType) { - if (resolvedType->component) - resolvedType->component->release(); - if (resolvedType->typePropertyCache) - resolvedType->typePropertyCache->release(); + if ((*resolvedType)->component) + (*resolvedType)->component->release(); + if ((*resolvedType)->typePropertyCache) + (*resolvedType)->typePropertyCache->release(); } + qDeleteAll(resolvedTypes); + resolvedTypes.clear(); for (int ii = 0; ii < propertyCaches.count(); ++ii) if (propertyCaches.at(ii)) diff --git a/src/qml/qml/qqmlcompiler_p.h b/src/qml/qml/qqmlcompiler_p.h index 788def0288..58943b206a 100644 --- a/src/qml/qml/qqmlcompiler_p.h +++ b/src/qml/qml/qqmlcompiler_p.h @@ -129,7 +129,7 @@ public: QList types; // --- new compiler: // map from name index - QHash resolvedTypes; + QHash resolvedTypes; // --- struct V8Program { diff --git a/src/qml/qml/qqmlobjectcreator.cpp b/src/qml/qml/qqmlobjectcreator.cpp index 963b8272f4..b1f4a8e1bf 100644 --- a/src/qml/qml/qqmlobjectcreator.cpp +++ b/src/qml/qml/qqmlobjectcreator.cpp @@ -642,7 +642,9 @@ bool QmlObjectCreator::setPropertyValue(QQmlPropertyData *property, int bindingI { if (binding->type == QV4::CompiledData::Binding::Type_AttachedProperty) { Q_ASSERT(stringAt(qmlUnit->objectAt(binding->value.objectIndex)->inheritedTypeNameIndex).isEmpty()); - QQmlType *attachedType = resolvedTypes.value(binding->propertyNameIndex).type; + QQmlCompiledData::TypeReference *tr = resolvedTypes.value(binding->propertyNameIndex); + Q_ASSERT(tr); + QQmlType *attachedType = tr->type; const int id = attachedType->attachedPropertiesId(); QObject *qmlObject = qmlAttachedPropertiesObjectById(id, _qobject); QQmlRefPointer cache = QQmlEnginePrivate::get(engine)->cache(qmlObject); @@ -931,8 +933,9 @@ QObject *QmlObjectCreator::createInstance(int index, QObject *parent) } else { const QV4::CompiledData::Object *obj = qmlUnit->objectAt(index); - QQmlCompiledData::TypeReference typeRef = resolvedTypes.value(obj->inheritedTypeNameIndex); - QQmlType *type = typeRef.type; + QQmlCompiledData::TypeReference *typeRef = resolvedTypes.value(obj->inheritedTypeNameIndex); + Q_ASSERT(typeRef); + QQmlType *type = typeRef->type; if (type) { instance = type->create(); if (!instance) { @@ -950,13 +953,13 @@ QObject *QmlObjectCreator::createInstance(int index, QObject *parent) customParser = type->customParser(); } else { - Q_ASSERT(typeRef.component); - if (typeRef.component->qmlUnit->isSingleton()) + Q_ASSERT(typeRef->component); + if (typeRef->component->qmlUnit->isSingleton()) { recordError(obj->location, tr("Composite Singleton Type %1 is not creatable").arg(stringAt(obj->inheritedTypeNameIndex))); return 0; } - QmlObjectCreator subCreator(context, typeRef.component); + QmlObjectCreator subCreator(context, typeRef->component); instance = subCreator.create(); if (!instance) { errors += subCreator.errors; diff --git a/src/qml/qml/qqmlobjectcreator_p.h b/src/qml/qml/qqmlobjectcreator_p.h index a198396467..951c3a2eed 100644 --- a/src/qml/qml/qqmlobjectcreator_p.h +++ b/src/qml/qml/qqmlobjectcreator_p.h @@ -86,7 +86,7 @@ private: const QV4::CompiledData::CompilationUnit *jsUnit; QQmlContextData *parentContext; QQmlContextData *context; - const QHash resolvedTypes; + const QHash resolvedTypes; const QVector propertyCaches; const QVector vmeMetaObjectData; QHash objectIndexToId; -- cgit v1.2.3