diff options
author | Simon Hausmann <[email protected]> | 2016-06-20 10:26:40 +0200 |
---|---|---|
committer | Simon Hausmann <[email protected]> | 2016-07-15 20:31:51 +0000 |
commit | 8f19045ef5d308231716ddcb62a80cc43ebb2dd7 (patch) | |
tree | ad69181c5d22d4366799632bd77ea57500d63a47 /src/qml/compiler | |
parent | bf5f97e6c6900535a7131c6a26415459bfaca774 (diff) |
Split out creation of alias properties in the property caches
Similar to the regular property cache creation code, this also has to become a
template function so that it can be run on the compilation units loaded from
disk in the future. What is shared between the code path of a fresh compilation
vs. re-use of a unit from disk is the code to propagate the CompiledData::Alias
entries into entries in the property cache. The code for iterating through the
component spaces and resolving the alias references is not shared.
Change-Id: I04c2a5575310400156b457ae7b709cffecb7455e
Reviewed-by: Lars Knoll <[email protected]>
Diffstat (limited to 'src/qml/compiler')
-rw-r--r-- | src/qml/compiler/qqmlirbuilder_p.h | 2 | ||||
-rw-r--r-- | src/qml/compiler/qqmlpropertycachecreator_p.h | 234 | ||||
-rw-r--r-- | src/qml/compiler/qqmltypecompiler.cpp | 128 | ||||
-rw-r--r-- | src/qml/compiler/qqmltypecompiler_p.h | 4 | ||||
-rw-r--r-- | src/qml/compiler/qv4compileddata_p.h | 2 |
5 files changed, 250 insertions, 120 deletions
diff --git a/src/qml/compiler/qqmlirbuilder_p.h b/src/qml/compiler/qqmlirbuilder_p.h index 4e0d4e563b..821a6bba6d 100644 --- a/src/qml/compiler/qqmlirbuilder_p.h +++ b/src/qml/compiler/qqmlirbuilder_p.h @@ -400,6 +400,8 @@ public: FixedPoolArray<int> runtimeFunctionIndices; FixedPoolArray<quint32> namedObjectsInComponent; + int namedObjectsInComponentCount() const { return namedObjectsInComponent.count; } + const quint32 *namedObjectsInComponentTable() const { return namedObjectsInComponent.begin(); } private: friend struct IRLoader; diff --git a/src/qml/compiler/qqmlpropertycachecreator_p.h b/src/qml/compiler/qqmlpropertycachecreator_p.h index ff8bc49e6f..09a093d911 100644 --- a/src/qml/compiler/qqmlpropertycachecreator_p.h +++ b/src/qml/compiler/qqmlpropertycachecreator_p.h @@ -507,6 +507,240 @@ inline QQmlCompileError QQmlPropertyCacheCreator<ObjectContainer>::createMetaObj return noError; } +template <typename ObjectContainer> +class QQmlPropertyCacheAliasCreator +{ +public: + typedef typename ObjectContainer::CompiledObject CompiledObject; + + QQmlPropertyCacheAliasCreator(QQmlPropertyCacheVector *propertyCaches, const ObjectContainer *objectContainer); + + void appendAliasPropertiesToMetaObjects(); + + void appendAliasesToPropertyCache(const CompiledObject &component, int objectIndex); + +private: + void appendAliasPropertiesInMetaObjectsWithinComponent(const CompiledObject &component, int firstObjectIndex); + void propertyDataForAlias(const CompiledObject &component, const QV4::CompiledData::Alias &alias, int *type, quint32 *propertyFlags); + + void collectObjectsWithAliasesRecursively(int objectIndex, QVector<int> *objectsWithAliases) const; + + int objectForId(const CompiledObject &component, int id) const; + + QQmlPropertyCacheVector *propertyCaches; + const ObjectContainer *objectContainer; +}; + +template <typename ObjectContainer> +inline QQmlPropertyCacheAliasCreator<ObjectContainer>::QQmlPropertyCacheAliasCreator(QQmlPropertyCacheVector *propertyCaches, const ObjectContainer *objectContainer) + : propertyCaches(propertyCaches) + , objectContainer(objectContainer) +{ + +} + +template <typename ObjectContainer> +inline void QQmlPropertyCacheAliasCreator<ObjectContainer>::appendAliasPropertiesToMetaObjects() +{ + for (int i = 0; i < objectContainer->objectCount(); ++i) { + const CompiledObject &component = *objectContainer->objectAt(i); + if (!(component.flags & QV4::CompiledData::Object::IsComponent)) + continue; + + const auto rootBinding = component.bindingsBegin(); + appendAliasPropertiesInMetaObjectsWithinComponent(component, rootBinding->value.objectIndex); + } + + const int rootObjectIndex = objectContainer->rootObjectIndex(); + appendAliasPropertiesInMetaObjectsWithinComponent(*objectContainer->objectAt(rootObjectIndex), rootObjectIndex); +} + +template <typename ObjectContainer> +inline void QQmlPropertyCacheAliasCreator<ObjectContainer>::appendAliasPropertiesInMetaObjectsWithinComponent(const CompiledObject &component, int firstObjectIndex) +{ + QVector<int> objectsWithAliases; + collectObjectsWithAliasesRecursively(firstObjectIndex, &objectsWithAliases); + if (objectsWithAliases.isEmpty()) + return; + + const auto allAliasTargetsExist = [this, &component](const CompiledObject &object) { + for (auto alias = object.aliasesBegin(), end = object.aliasesEnd(); alias != end; ++alias) { + Q_ASSERT(alias->flags & QV4::CompiledData::Alias::Resolved); + + const int targetObjectIndex = objectForId(component, alias->targetObjectId); + Q_ASSERT(targetObjectIndex >= 0); + + if (alias->encodedMetaPropertyIndex == -1) + continue; + + const QQmlPropertyCache *targetCache = propertyCaches->at(targetObjectIndex); + Q_ASSERT(targetCache); + + int coreIndex; + QQmlPropertyData::decodeValueTypePropertyIndex(alias->encodedMetaPropertyIndex, &coreIndex); + QQmlPropertyData *targetProperty = targetCache->property(coreIndex); + if (!targetProperty) + return false; + } + return true; + }; + + do { + QVector<int> pendingObjects; + + for (int objectIndex: qAsConst(objectsWithAliases)) { + const CompiledObject &object = *objectContainer->objectAt(objectIndex); + + if (allAliasTargetsExist(object)) { + appendAliasesToPropertyCache(component, objectIndex); + } else { + pendingObjects.append(objectIndex); + } + + } + qSwap(objectsWithAliases, pendingObjects); + } while (!objectsWithAliases.isEmpty()); +} + +template <typename ObjectContainer> +inline void QQmlPropertyCacheAliasCreator<ObjectContainer>::collectObjectsWithAliasesRecursively(int objectIndex, QVector<int> *objectsWithAliases) const +{ + const CompiledObject &object = *objectContainer->objectAt(objectIndex); + if (object.aliasCount() > 0) + objectsWithAliases->append(objectIndex); + + // Stop at Component boundary + if (object.flags & QV4::CompiledData::Object::IsComponent && objectIndex != objectContainer->rootObjectIndex()) + return; + + for (auto binding = object.bindingsBegin(), end = object.bindingsEnd(); binding != end; ++binding) { + if (binding->type != QV4::CompiledData::Binding::Type_Object + && binding->type != QV4::CompiledData::Binding::Type_AttachedProperty + && binding->type != QV4::CompiledData::Binding::Type_GroupProperty) + continue; + + collectObjectsWithAliasesRecursively(binding->value.objectIndex, objectsWithAliases); + } +} + +template <typename ObjectContainer> +inline void QQmlPropertyCacheAliasCreator<ObjectContainer>::propertyDataForAlias(const CompiledObject &component, const QV4::CompiledData::Alias &alias, int *type, quint32 *propertyFlags) +{ + const int targetObjectIndex = objectForId(component, alias.targetObjectId); + Q_ASSERT(targetObjectIndex >= 0); + + const CompiledObject &targetObject = *objectContainer->objectAt(targetObjectIndex); + + *type = 0; + bool writable = false; + bool resettable = false; + + *propertyFlags = QQmlPropertyData::IsAlias; + + if (alias.aliasToLocalAlias) { + auto targetAlias = targetObject.aliasesBegin(); + for (uint i = 0; i < alias.localAliasIndex; ++i) + ++targetAlias; + propertyDataForAlias(component, *targetAlias, type, propertyFlags); + return; + } else if (alias.encodedMetaPropertyIndex == -1) { + Q_ASSERT(alias.flags & QV4::CompiledData::Alias::AliasPointsToPointerObject); + auto *typeRef = objectContainer->resolvedTypes.value(targetObject.inheritedTypeNameIndex); + Q_ASSERT(typeRef); + + if (typeRef->type) + *type = typeRef->type->typeId(); + else + *type = typeRef->compilationUnit->metaTypeId; + + *propertyFlags |= QQmlPropertyData::IsQObjectDerived; + } else { + int coreIndex; + int valueTypeIndex = QQmlPropertyData::decodeValueTypePropertyIndex(alias.encodedMetaPropertyIndex, &coreIndex); + + QQmlPropertyCache *targetCache = propertyCaches->at(targetObjectIndex); + Q_ASSERT(targetCache); + QQmlPropertyData *targetProperty = targetCache->property(coreIndex); + Q_ASSERT(targetProperty); + + *type = targetProperty->propType; + + writable = targetProperty->isWritable(); + resettable = targetProperty->isResettable(); + + if (valueTypeIndex != -1) { + const QMetaObject *valueTypeMetaObject = QQmlValueTypeFactory::metaObjectForMetaType(*type); + if (valueTypeMetaObject->property(valueTypeIndex).isEnumType()) + *type = QVariant::Int; + else + *type = valueTypeMetaObject->property(valueTypeIndex).userType(); + } else { + if (targetProperty->isEnum()) { + *type = QVariant::Int; + } else { + // Copy type flags + *propertyFlags |= targetProperty->getFlags() & QQmlPropertyData::PropTypeFlagMask; + + if (targetProperty->isVarProperty()) + *propertyFlags |= QQmlPropertyData::IsQVariant; + } + } + } + + if (!(alias.flags & QV4::CompiledData::Property::IsReadOnly) && writable) + *propertyFlags |= QQmlPropertyData::IsWritable; + else + *propertyFlags &= ~QQmlPropertyData::IsWritable; + + if (resettable) + *propertyFlags |= QQmlPropertyData::IsResettable; + else + *propertyFlags &= ~QQmlPropertyData::IsResettable; +} + +template <typename ObjectContainer> +inline void QQmlPropertyCacheAliasCreator<ObjectContainer>::appendAliasesToPropertyCache(const CompiledObject &component, int objectIndex) +{ + const CompiledObject &object = *objectContainer->objectAt(objectIndex); + if (!object.aliasCount()) + return; + + QQmlPropertyCache *propertyCache = propertyCaches->at(objectIndex); + Q_ASSERT(propertyCache); + + int effectiveSignalIndex = propertyCache->signalHandlerIndexCacheStart + propertyCache->propertyIndexCache.count(); + int effectivePropertyIndex = propertyCache->propertyIndexCacheStart + propertyCache->propertyIndexCache.count(); + + int aliasIndex = 0; + for (auto alias = object.aliasesBegin(), end = object.aliasesEnd(); alias != end; ++alias, ++aliasIndex) { + Q_ASSERT(alias->flags & QV4::CompiledData::Alias::Resolved); + + int type = 0; + quint32 propertyFlags = 0; + propertyDataForAlias(component, *alias, &type, &propertyFlags); + + const QString propertyName = objectContainer->stringAt(alias->nameIndex); + + if (object.defaultPropertyIsAlias && aliasIndex == object.indexOfDefaultPropertyOrAlias) + propertyCache->_defaultPropertyName = propertyName; + + propertyCache->appendProperty(propertyName, propertyFlags, effectivePropertyIndex++, + type, effectiveSignalIndex++); + } +} + +template <typename ObjectContainer> +inline int QQmlPropertyCacheAliasCreator<ObjectContainer>::objectForId(const CompiledObject &component, int id) const +{ + for (quint32 i = 0, count = component.namedObjectsInComponentCount(); i < count; ++i) { + const int candidateIndex = component.namedObjectsInComponentTable()[i]; + const CompiledObject &candidate = *objectContainer->objectAt(candidateIndex); + if (candidate.id == id) + return candidateIndex; + } + return -1; +} + QT_END_NAMESPACE #endif // QQMLPROPERTYCACHECREATOR_P_H diff --git a/src/qml/compiler/qqmltypecompiler.cpp b/src/qml/compiler/qqmltypecompiler.cpp index 83aaba791b..bb4d603f68 100644 --- a/src/qml/compiler/qqmltypecompiler.cpp +++ b/src/qml/compiler/qqmltypecompiler.cpp @@ -775,7 +775,6 @@ QQmlComponentAndAliasResolver::QQmlComponentAndAliasResolver(QQmlTypeCompiler *t , pool(typeCompiler->memoryPool()) , qmlObjects(typeCompiler->qmlObjects()) , indexOfRootObject(typeCompiler->rootObjectIndex()) - , _componentIndex(-1) , resolvedTypes(&typeCompiler->resolvedTypes) , propertyCaches(std::move(typeCompiler->takePropertyCaches())) { @@ -924,7 +923,6 @@ bool QQmlComponentAndAliasResolver::resolve() QmlIR::Object *component = qmlObjects->at(componentRoots.at(i)); const QmlIR::Binding *rootBinding = component->firstBinding(); - _componentIndex = i; _idToObjectIndex.clear(); _objectsWithAliases.clear(); @@ -932,24 +930,24 @@ bool QQmlComponentAndAliasResolver::resolve() if (!collectIdsAndAliases(rootBinding->value.objectIndex)) return false; - if (!resolveAliases()) - return false; - component->namedObjectsInComponent.allocate(pool, _idToObjectIndex); + + if (!resolveAliases(componentRoots.at(i))) + return false; } // Collect ids and aliases for root - _componentIndex = -1; _idToObjectIndex.clear(); _objectsWithAliases.clear(); collectIdsAndAliases(indexOfRootObject); - resolveAliases(); - QmlIR::Object *rootComponent = qmlObjects->at(indexOfRootObject); rootComponent->namedObjectsInComponent.allocate(pool, _idToObjectIndex); + if (!resolveAliases(indexOfRootObject)) + return false; + // Implicit component insertion may have added objects and thus we also need // to extend the symmetric propertyCaches. compiler->setPropertyCaches(std::move(propertyCaches)); @@ -991,10 +989,13 @@ bool QQmlComponentAndAliasResolver::collectIdsAndAliases(int objectIndex) return true; } -bool QQmlComponentAndAliasResolver::resolveAliases() +bool QQmlComponentAndAliasResolver::resolveAliases(int componentIndex) { if (_objectsWithAliases.isEmpty()) return true; + + QQmlPropertyCacheAliasCreator<QQmlTypeCompiler> aliasCacheCreator(&propertyCaches, compiler); + bool atLeastOneAliasResolved; do { atLeastOneAliasResolved = false; @@ -1011,7 +1012,7 @@ bool QQmlComponentAndAliasResolver::resolveAliases() } if (result == AllAliasesResolved) { - addAliasesToPropertyCache(objectIndex); + aliasCacheCreator.appendAliasesToPropertyCache(*qmlObjects->at(componentIndex), objectIndex); atLeastOneAliasResolved = true; } else if (result == SomeAliasesResolved) { atLeastOneAliasResolved = true; @@ -1153,113 +1154,6 @@ QQmlComponentAndAliasResolver::AliasResolutionResult QQmlComponentAndAliasResolv return SomeAliasesResolved; } -void QQmlComponentAndAliasResolver::propertyDataForAlias(QmlIR::Alias *alias, int *type, quint32 *propertyFlags) -{ - const auto objectForId = [this](int objectId) { - for (auto idIt = _idToObjectIndex.constBegin(), end = _idToObjectIndex.constEnd(); idIt != end; ++idIt) { - const QmlIR::Object *obj = qmlObjects->at(*idIt); - if (obj->id == objectId) - return *idIt; - } - return -1; - }; - - const int targetObjectIndex = objectForId(alias->targetObjectId); - Q_ASSERT(targetObjectIndex >= 0); - - const QmlIR::Object *targetObject = qmlObjects->at(targetObjectIndex); - - *type = 0; - bool writable = false; - bool resettable = false; - - *propertyFlags = QQmlPropertyData::IsAlias; - - if (alias->aliasToLocalAlias) { - auto targetAlias = targetObject->firstAlias(); - for (uint i = 0; i < alias->localAliasIndex; ++i) - targetAlias = targetAlias->next; - propertyDataForAlias(targetAlias, type, propertyFlags); - return; - } else if (alias->encodedMetaPropertyIndex == -1) { - Q_ASSERT(alias->flags & QV4::CompiledData::Alias::AliasPointsToPointerObject); - auto *typeRef = resolvedTypes->value(targetObject->inheritedTypeNameIndex); - Q_ASSERT(typeRef); - - if (typeRef->type) - *type = typeRef->type->typeId(); - else - *type = typeRef->compilationUnit->metaTypeId; - - *propertyFlags |= QQmlPropertyData::IsQObjectDerived; - } else { - int coreIndex; - int valueTypeIndex = QQmlPropertyData::decodeValueTypePropertyIndex(alias->encodedMetaPropertyIndex, &coreIndex); - - QQmlPropertyCache *targetCache = propertyCaches.at(targetObjectIndex); - Q_ASSERT(targetCache); - QQmlPropertyData *targetProperty = targetCache->property(coreIndex); - Q_ASSERT(targetProperty); - - *type = targetProperty->propType; - - writable = targetProperty->isWritable(); - resettable = targetProperty->isResettable(); - - if (valueTypeIndex != -1) { - const QMetaObject *valueTypeMetaObject = QQmlValueTypeFactory::metaObjectForMetaType(*type); - if (valueTypeMetaObject->property(valueTypeIndex).isEnumType()) - *type = QVariant::Int; - else - *type = valueTypeMetaObject->property(valueTypeIndex).userType(); - } else { - if (targetProperty->isEnum()) { - *type = QVariant::Int; - } else { - // Copy type flags - *propertyFlags |= targetProperty->getFlags() & QQmlPropertyData::PropTypeFlagMask; - - if (targetProperty->isVarProperty()) - *propertyFlags |= QQmlPropertyData::IsQVariant; - } - } - } - - if (!(alias->flags & QV4::CompiledData::Property::IsReadOnly) && writable) - *propertyFlags |= QQmlPropertyData::IsWritable; - else - *propertyFlags &= ~QQmlPropertyData::IsWritable; - - if (resettable) - *propertyFlags |= QQmlPropertyData::IsResettable; - else - *propertyFlags &= ~QQmlPropertyData::IsResettable; -} - -void QQmlComponentAndAliasResolver::addAliasesToPropertyCache(int objectIndex) -{ - const QmlIR::Object * const obj = qmlObjects->at(objectIndex); - QQmlPropertyCache * const propertyCache = propertyCaches.at(objectIndex); - Q_ASSERT(propertyCache); - int effectiveSignalIndex = propertyCache->signalHandlerIndexCacheStart + propertyCache->propertyIndexCache.count(); - int effectivePropertyIndex = propertyCache->propertyIndexCacheStart + propertyCache->propertyIndexCache.count(); - - int aliasIndex = 0; - for (QmlIR::Alias *alias = obj->firstAlias(); alias; alias = alias->next, ++aliasIndex) { - int type = 0; - quint32 propertyFlags = 0; - propertyDataForAlias(alias, &type, &propertyFlags); - - QString propertyName = stringAt(alias->nameIndex); - - if (obj->defaultPropertyIsAlias && aliasIndex == obj->indexOfDefaultPropertyOrAlias) - propertyCache->_defaultPropertyName = propertyName; - - propertyCache->appendProperty(propertyName, propertyFlags, effectivePropertyIndex++, - type, effectiveSignalIndex++); - } -} - QQmlDeferredAndCustomParserBindingScanner::QQmlDeferredAndCustomParserBindingScanner(QQmlTypeCompiler *typeCompiler) : QQmlCompilePass(typeCompiler) , qmlObjects(typeCompiler->qmlObjects()) diff --git a/src/qml/compiler/qqmltypecompiler_p.h b/src/qml/compiler/qqmltypecompiler_p.h index 0b078fd642..9f1a09b35c 100644 --- a/src/qml/compiler/qqmltypecompiler_p.h +++ b/src/qml/compiler/qqmltypecompiler_p.h @@ -265,7 +265,7 @@ public: protected: void findAndRegisterImplicitComponents(const QmlIR::Object *obj, QQmlPropertyCache *propertyCache); bool collectIdsAndAliases(int objectIndex); - bool resolveAliases(); + bool resolveAliases(int componentIndex); void propertyDataForAlias(QmlIR::Alias *alias, int *type, quint32 *propertyFlags); enum AliasResolutionResult { @@ -275,7 +275,6 @@ protected: }; AliasResolutionResult resolveAliasesInObject(int objectIndex, QQmlCompileError *error); - void addAliasesToPropertyCache(int objectIndex); QQmlEnginePrivate *enginePrivate; QQmlJS::MemoryPool *pool; @@ -286,7 +285,6 @@ protected: // indices of the objects that are actually Component {} QVector<quint32> componentRoots; - int _componentIndex; QHash<int, int> _idToObjectIndex; QVector<int> _objectsWithAliases; diff --git a/src/qml/compiler/qv4compileddata_p.h b/src/qml/compiler/qv4compileddata_p.h index f1cf365b25..fc7cf4ebf1 100644 --- a/src/qml/compiler/qv4compileddata_p.h +++ b/src/qml/compiler/qv4compileddata_p.h @@ -565,6 +565,8 @@ struct Object typedef TableIterator<Signal, Object, &Object::signalAt> SignalIterator; SignalIterator signalsBegin() const { return SignalIterator(this, 0); } SignalIterator signalsEnd() const { return SignalIterator(this, nSignals); } + + int namedObjectsInComponentCount() const { return nNamedObjectsInComponent; } // --- }; |