diff options
author | Simon Hausmann <simon.hausmann@qt.io> | 2016-05-26 16:26:33 +0200 |
---|---|---|
committer | Simon Hausmann <simon.hausmann@qt.io> | 2016-05-30 07:16:17 +0000 |
commit | f27d058c11b54b3c5f72d41c25cb00657b49a37b (patch) | |
tree | 9210b7c5f9af1016c495086470582b69fadc9e85 /src | |
parent | 515efdb8a65dc8ba22a56a02ee6d7056f39619cb (diff) |
Centralize deferred binding bit information in CompiledData::Binding
Ultimately the decision which bindings to initialize in a deferred way depends
on the data in the meta-object (deferred property names entry). The hash in
QQmlCompiledData is just caching this information. We are better off storing
this single bit right in the binding itself instead of in a parallel data
structure.
Change-Id: Ib66d3550210af1f882b98b0ba9089391813d69ad
Reviewed-by: Lars Knoll <lars.knoll@theqtcompany.com>
Diffstat (limited to 'src')
-rw-r--r-- | src/qml/compiler/qqmltypecompiler.cpp | 130 | ||||
-rw-r--r-- | src/qml/compiler/qqmltypecompiler_p.h | 19 | ||||
-rw-r--r-- | src/qml/compiler/qv4compileddata_p.h | 6 | ||||
-rw-r--r-- | src/qml/qml/qqmlcompiler_p.h | 1 | ||||
-rw-r--r-- | src/qml/qml/qqmlobjectcreator.cpp | 42 | ||||
-rw-r--r-- | src/qml/qml/qqmlobjectcreator_p.h | 2 |
6 files changed, 142 insertions, 58 deletions
diff --git a/src/qml/compiler/qqmltypecompiler.cpp b/src/qml/compiler/qqmltypecompiler.cpp index 124541b63b..937ace2722 100644 --- a/src/qml/compiler/qqmltypecompiler.cpp +++ b/src/qml/compiler/qqmltypecompiler.cpp @@ -202,6 +202,12 @@ bool QQmlTypeCompiler::compile() return false; } + { + QQmlDeferredBindingScanner deferredBindingScanner(this); + if (!deferredBindingScanner.scanObject()) + return false; + } + // Compile JS binding expressions and signal handlers if (!document->javaScriptCompilationUnit) { { @@ -366,11 +372,6 @@ const QV4::Compiler::StringTableGenerator *QQmlTypeCompiler::stringPool() const return &document->jsGenerator.stringTable; } -void QQmlTypeCompiler::setDeferredBindingsPerObject(const QHash<int, QBitArray> &deferredBindingsPerObject) -{ - compiledData->deferredBindingsPerObject = deferredBindingsPerObject; -} - void QQmlTypeCompiler::setBindingPropertyDataPerObject(const QVector<QV4::CompiledData::BindingPropertyData> &propertyData) { compiledData->compilationUnit->bindingPropertyDataPerObject = propertyData; @@ -1661,6 +1662,103 @@ bool QQmlComponentAndAliasResolver::resolveAliases() return true; } +QQmlDeferredBindingScanner::QQmlDeferredBindingScanner(QQmlTypeCompiler *typeCompiler) + : QQmlCompilePass(typeCompiler) + , qmlObjects(typeCompiler->qmlObjects()) + , propertyCaches(typeCompiler->propertyCaches()) + , _seenObjectWithId(false) +{ +} + +bool QQmlDeferredBindingScanner::scanObject() +{ + return scanObject(compiler->rootObjectIndex()); +} + +bool QQmlDeferredBindingScanner::scanObject(int objectIndex) +{ + QmlIR::Object *obj = qmlObjects->at(objectIndex); + if (obj->idNameIndex != 0) + _seenObjectWithId = true; + + if (obj->flags & QV4::CompiledData::Object::IsComponent) { + Q_ASSERT(obj->bindingCount() == 1); + const QV4::CompiledData::Binding *componentBinding = obj->firstBinding(); + Q_ASSERT(componentBinding->type == QV4::CompiledData::Binding::Type_Object); + return scanObject(componentBinding->value.objectIndex); + } + + QQmlPropertyCache *propertyCache = propertyCaches.at(objectIndex).data(); + if (!propertyCache) + return true; + + QString defaultPropertyName; + QQmlPropertyData *defaultProperty = 0; + if (obj->indexOfDefaultPropertyOrAlias != -1) { + QQmlPropertyCache *cache = propertyCache->parent(); + defaultPropertyName = cache->defaultPropertyName(); + defaultProperty = cache->defaultProperty(); + } else { + defaultPropertyName = propertyCache->defaultPropertyName(); + defaultProperty = propertyCache->defaultProperty(); + } + + QmlIR::PropertyResolver propertyResolver(propertyCache); + + QStringList deferredPropertyNames; + { + const QMetaObject *mo = propertyCache->firstCppMetaObject(); + const int namesIndex = mo->indexOfClassInfo("DeferredPropertyNames"); + if (namesIndex != -1) { + QMetaClassInfo classInfo = mo->classInfo(namesIndex); + deferredPropertyNames = QString::fromUtf8(classInfo.value()).split(QLatin1Char(',')); + } + } + + for (QmlIR::Binding *binding = obj->firstBinding(); binding; binding = binding->next) { + if (binding->flags & QV4::CompiledData::Binding::IsSignalHandlerExpression + || binding->flags & QV4::CompiledData::Binding::IsSignalHandlerObject) + continue; + + QQmlPropertyData *pd = 0; + QString name = stringAt(binding->propertyNameIndex); + if (name.isEmpty()) { + pd = defaultProperty; + name = defaultPropertyName; + } else { + if (name.constData()->isUpper()) + continue; + + bool notInRevision = false; + pd = propertyResolver.property(name, ¬InRevision, QmlIR::PropertyResolver::CheckRevision); + } + + if (!pd) + continue; + + bool seenSubObjectWithId = false; + + if (binding->type >= QV4::CompiledData::Binding::Type_Object && (pd || binding->isAttachedProperty())) { + qSwap(_seenObjectWithId, seenSubObjectWithId); + const bool subObjectValid = scanObject(binding->value.objectIndex); + qSwap(_seenObjectWithId, seenSubObjectWithId); + if (!subObjectValid) + return false; + _seenObjectWithId |= seenSubObjectWithId; + } + + if (!seenSubObjectWithId + && !deferredPropertyNames.isEmpty() && deferredPropertyNames.contains(name)) { + + binding->flags |= QV4::CompiledData::Binding::IsDeferredBinding; + obj->flags |= QV4::CompiledData::Object::HasDeferredBindings; + } + } + + return true; +} + + QQmlPropertyValidator::QQmlPropertyValidator(QQmlTypeCompiler *typeCompiler) : QQmlCompilePass(typeCompiler) , enginePrivate(typeCompiler->enginePrivate()) @@ -1669,7 +1767,6 @@ QQmlPropertyValidator::QQmlPropertyValidator(QQmlTypeCompiler *typeCompiler) , customParsers(typeCompiler->customParserCache()) , propertyCaches(typeCompiler->propertyCaches()) , customParserBindingsPerObject(typeCompiler->customParserBindings()) - , _seenObjectWithId(false) { } @@ -1678,7 +1775,6 @@ bool QQmlPropertyValidator::validate() _bindingPropertyDataPerObject.resize(qmlUnit->nObjects); if (!validateObject(qmlUnit->indexOfRootObject, /*instantiatingBinding*/0)) return false; - compiler->setDeferredBindingsPerObject(_deferredBindingsPerObject); compiler->setBindingPropertyDataPerObject(_bindingPropertyDataPerObject); return true; } @@ -1709,8 +1805,6 @@ struct BindingFinder bool QQmlPropertyValidator::validateObject(int objectIndex, const QV4::CompiledData::Binding *instantiatingBinding, bool populatingValueTypeGroupProperty) const { const QV4::CompiledData::Object *obj = qmlUnit->objectAt(objectIndex); - if (obj->idNameIndex != 0) - _seenObjectWithId = true; if (obj->flags & QV4::CompiledData::Object::IsComponent) { Q_ASSERT(obj->nBindings == 1); @@ -1757,7 +1851,6 @@ bool QQmlPropertyValidator::validateObject(int objectIndex, const QV4::CompiledD } QBitArray customParserBindings(obj->nBindings); - QBitArray deferredBindings; QmlIR::PropertyResolver propertyResolver(propertyCache); @@ -1837,24 +1930,10 @@ bool QQmlPropertyValidator::validateObject(int objectIndex, const QV4::CompiledD return false; } - bool seenSubObjectWithId = false; - if (binding->type >= QV4::CompiledData::Binding::Type_Object && (pd || binding->isAttachedProperty())) { - qSwap(_seenObjectWithId, seenSubObjectWithId); const bool subObjectValid = validateObject(binding->value.objectIndex, binding, pd && QQmlValueTypeFactory::metaObjectForMetaType(pd->propType)); - qSwap(_seenObjectWithId, seenSubObjectWithId); if (!subObjectValid) return false; - _seenObjectWithId |= seenSubObjectWithId; - } - - if (!seenSubObjectWithId - && !deferredPropertyNames.isEmpty() && deferredPropertyNames.contains(name)) { - - if (deferredBindings.isEmpty()) - deferredBindings.resize(obj->nBindings); - - deferredBindings.setBit(i); } // Signal handlers were resolved and checked earlier in the signal handler conversion pass. @@ -1973,9 +2052,6 @@ bool QQmlPropertyValidator::validateObject(int objectIndex, const QV4::CompiledD } } - if (!deferredBindings.isEmpty()) - _deferredBindingsPerObject.insert(objectIndex, deferredBindings); - _bindingPropertyDataPerObject[objectIndex] = collectedBindingPropertyData; return true; diff --git a/src/qml/compiler/qqmltypecompiler_p.h b/src/qml/compiler/qqmltypecompiler_p.h index 5fbc1d370a..9cdac03896 100644 --- a/src/qml/compiler/qqmltypecompiler_p.h +++ b/src/qml/compiler/qqmltypecompiler_p.h @@ -107,7 +107,6 @@ public: QQmlJS::MemoryPool *memoryPool(); QStringRef newStringRef(const QString &string); const QV4::Compiler::StringTableGenerator *stringPool() const; - void setDeferredBindingsPerObject(const QHash<int, QBitArray> &deferredBindingsPerObject); void setBindingPropertyDataPerObject(const QVector<QV4::CompiledData::BindingPropertyData> &propertyData); const QHash<int, QQmlCustomParser*> &customParserCache() const { return customParsers; } @@ -281,6 +280,22 @@ protected: QQmlPropertyCacheVector propertyCaches; }; +class QQmlDeferredBindingScanner : public QQmlCompilePass +{ +public: + QQmlDeferredBindingScanner(QQmlTypeCompiler *typeCompiler); + + bool scanObject(); + +private: + bool scanObject(int objectIndex); + + QList<QmlIR::Object*> *qmlObjects; + QQmlPropertyCacheVector propertyCaches; + + bool _seenObjectWithId; +}; + class QQmlPropertyValidator : public QQmlCompilePass { Q_DECLARE_TR_FUNCTIONS(QQmlPropertyValidator) @@ -307,8 +322,6 @@ private: QHash<int, QBitArray> *customParserBindingsPerObject; // collected state variables, essentially write-only - mutable QHash<int, QBitArray> _deferredBindingsPerObject; - mutable bool _seenObjectWithId; mutable QVector<QV4::CompiledData::BindingPropertyData> _bindingPropertyDataPerObject; }; diff --git a/src/qml/compiler/qv4compileddata_p.h b/src/qml/compiler/qv4compileddata_p.h index 863708d23e..08c4c65a1f 100644 --- a/src/qml/compiler/qv4compileddata_p.h +++ b/src/qml/compiler/qv4compileddata_p.h @@ -235,7 +235,8 @@ struct Q_QML_PRIVATE_EXPORT Binding InitializerForReadOnlyDeclaration = 0x8, IsResolvedEnum = 0x10, IsListItem = 0x20, - IsBindingToAlias = 0x40 + IsBindingToAlias = 0x40, + IsDeferredBinding = 0x80 }; quint32 flags : 16; @@ -394,7 +395,8 @@ struct Object { enum Flags { NoFlag = 0x0, - IsComponent = 0x1 // object was identified to be an explicit or implicit component boundary + IsComponent = 0x1, // object was identified to be an explicit or implicit component boundary + HasDeferredBindings = 0x2 // any of the bindings are deferred }; // Depending on the use, this may be the type name to instantiate before instantiating this diff --git a/src/qml/qml/qqmlcompiler_p.h b/src/qml/qml/qqmlcompiler_p.h index cd2c533150..c4883a6279 100644 --- a/src/qml/qml/qqmlcompiler_p.h +++ b/src/qml/qml/qqmlcompiler_p.h @@ -133,7 +133,6 @@ public: QQmlRefPointer<QV4::CompiledData::CompilationUnit> compilationUnit; // hash key is object index, value is indicies of bindings covered by custom parser QHash<int, QBitArray> customParserBindings; - QHash<int, QBitArray> deferredBindingsPerObject; // index is object index int totalBindingsCount; // Number of bindings used in this type int totalParserStatusCount; // Number of instantiated types that are QQmlParserStatus subclasses int totalObjectCount; // Number of objects explicitly instantiated diff --git a/src/qml/qml/qqmlobjectcreator.cpp b/src/qml/qml/qqmlobjectcreator.cpp index 9dba7f30d8..0607e02173 100644 --- a/src/qml/qml/qqmlobjectcreator.cpp +++ b/src/qml/qml/qqmlobjectcreator.cpp @@ -255,11 +255,7 @@ bool QQmlObjectCreator::populateDeferredProperties(QObject *instance) qSwap(_bindingTarget, bindingTarget); qSwap(_vmeMetaObject, vmeMetaObject); - QBitArray bindingSkipList = compiledData->deferredBindingsPerObject.value(_compiledObjectIndex); - for (int i = 0; i < bindingSkipList.count(); ++i) - bindingSkipList.setBit(i, !bindingSkipList.testBit(i)); - - setupBindings(bindingSkipList); + setupBindings(/*binding skip list*/QBitArray(), /*applyDeferredBindings=*/true); qSwap(_vmeMetaObject, vmeMetaObject); qSwap(_bindingTarget, bindingTarget); @@ -626,7 +622,7 @@ static QQmlType *qmlTypeForObject(QObject *object) return type; } -void QQmlObjectCreator::setupBindings(const QBitArray &bindingsToSkip) +void QQmlObjectCreator::setupBindings(const QBitArray &bindingsToSkip, bool applyDeferredBindings) { QQmlListProperty<void> savedList; qSwap(_currentList, savedList); @@ -680,6 +676,14 @@ void QQmlObjectCreator::setupBindings(const QBitArray &bindingsToSkip) if (static_cast<int>(i) < bindingsToSkip.size() && bindingsToSkip.testBit(i)) continue; + if (binding->flags & QV4::CompiledData::Binding::IsDeferredBinding) { + if (!applyDeferredBindings) + continue; + } else { + if (applyDeferredBindings) + continue; + } + const QQmlPropertyData *property = propertyData.at(i); if (property && property->isQList()) { @@ -1299,28 +1303,18 @@ bool QQmlObjectCreator::populateInstance(int index, QObject *instance, QObject * qSwap(_propertyCache, cache); qSwap(_vmeMetaObject, vmeMetaObject); - QBitArray bindingSkipList = bindingsToSkip; - { - QHash<int, QBitArray>::ConstIterator deferredBindings = compiledData->deferredBindingsPerObject.constFind(_compiledObjectIndex); - if (deferredBindings != compiledData->deferredBindingsPerObject.constEnd()) { - if (bindingSkipList.isEmpty()) - bindingSkipList.resize(deferredBindings->count()); - - for (int i = 0; i < deferredBindings->count(); ++i) - if (deferredBindings->testBit(i)) - bindingSkipList.setBit(i); - QQmlData::DeferredData *deferData = new QQmlData::DeferredData; - deferData->deferredIdx = _compiledObjectIndex; - deferData->compiledData = compiledData; - deferData->compiledData->addref(); - deferData->context = context; - _ddata->deferredData = deferData; - } + if (_compiledObject->flags & QV4::CompiledData::Object::HasDeferredBindings) { + QQmlData::DeferredData *deferData = new QQmlData::DeferredData; + deferData->deferredIdx = _compiledObjectIndex; + deferData->compiledData = compiledData; + deferData->compiledData->addref(); + deferData->context = context; + _ddata->deferredData = deferData; } if (_compiledObject->nFunctions > 0) setupFunctions(); - setupBindings(bindingSkipList); + setupBindings(bindingsToSkip); qSwap(_vmeMetaObject, vmeMetaObject); qSwap(_bindingTarget, bindingTarget); diff --git a/src/qml/qml/qqmlobjectcreator_p.h b/src/qml/qml/qqmlobjectcreator_p.h index 730237acfe..d0ed38334d 100644 --- a/src/qml/qml/qqmlobjectcreator_p.h +++ b/src/qml/qml/qqmlobjectcreator_p.h @@ -114,7 +114,7 @@ private: QObject *bindingTarget, const QQmlPropertyData *valueTypeProperty, const QBitArray &bindingsToSkip = QBitArray()); - void setupBindings(const QBitArray &bindingsToSkip); + void setupBindings(const QBitArray &bindingsToSkip, bool applyDeferredBindings = false); bool setPropertyBinding(const QQmlPropertyData *property, const QV4::CompiledData::Binding *binding); void setPropertyValue(const QQmlPropertyData *property, const QV4::CompiledData::Binding *binding); void setupFunctions(); |