diff options
author | Simon Hausmann <simon.hausmann@theqtcompany.com> | 2015-04-09 10:23:17 +0200 |
---|---|---|
committer | Simon Hausmann <simon.hausmann@theqtcompany.com> | 2015-04-21 06:36:47 +0000 |
commit | 3db3c38b1055cc8b41a9aa951c33f5621babb5d0 (patch) | |
tree | 8ba17669737ab0bd06cae7ac8366c5709614c5a0 /src | |
parent | a41dc6147436f3c1c977ff8c04379ff4bde3f0a6 (diff) |
Speed up property binding initialization on object creation
Avoid repeated string hashing and lookups in the property cache in order to
retrieve the property details when initializing literal and script bindings.
Instead we now cache the property data at type validation time, similar to how
the property data was encoded in the VME instructions in the old engine.
Change-Id: I3957c7c4c3e26dfa97c4880b23940a3755ee90e4
Reviewed-by: Lars Knoll <lars.knoll@digia.com>
Diffstat (limited to 'src')
-rw-r--r-- | src/qml/compiler/qqmltypecompiler.cpp | 48 | ||||
-rw-r--r-- | src/qml/compiler/qqmltypecompiler_p.h | 2 | ||||
-rw-r--r-- | src/qml/compiler/qv4compileddata.cpp | 10 | ||||
-rw-r--r-- | src/qml/compiler/qv4compileddata_p.h | 20 | ||||
-rw-r--r-- | src/qml/qml/qqmlobjectcreator.cpp | 76 | ||||
-rw-r--r-- | src/qml/qml/qqmlobjectcreator_p.h | 9 |
6 files changed, 93 insertions, 72 deletions
diff --git a/src/qml/compiler/qqmltypecompiler.cpp b/src/qml/compiler/qqmltypecompiler.cpp index b249d9ad9e..25282df2e3 100644 --- a/src/qml/compiler/qqmltypecompiler.cpp +++ b/src/qml/compiler/qqmltypecompiler.cpp @@ -392,6 +392,11 @@ void QQmlTypeCompiler::setDeferredBindingsPerObject(const QHash<int, QBitArray> compiledData->deferredBindingsPerObject = deferredBindingsPerObject; } +void QQmlTypeCompiler::setBindingPropertyDataPerObject(const QVector<QV4::CompiledData::BindingPropertyData> &propertyData) +{ + compiledData->compilationUnit->bindingPropertyDataPerObject = propertyData; +} + QString QQmlTypeCompiler::bindingAsString(const QmlIR::Object *object, int scriptIndex) const { return object->bindingAsString(document, scriptIndex); @@ -1712,9 +1717,11 @@ QQmlPropertyValidator::QQmlPropertyValidator(QQmlTypeCompiler *typeCompiler) bool QQmlPropertyValidator::validate() { + _bindingPropertyDataPerObject.resize(qmlUnit->nObjects); if (!validateObject(qmlUnit->indexOfRootObject, /*instantiatingBinding*/0)) return false; compiler->setDeferredBindingsPerObject(_deferredBindingsPerObject); + compiler->setBindingPropertyDataPerObject(_bindingPropertyDataPerObject); return true; } @@ -1818,6 +1825,8 @@ bool QQmlPropertyValidator::validateObject(int objectIndex, const QV4::CompiledD defaultProperty = propertyCache->defaultProperty(); } + QV4::CompiledData::BindingPropertyData collectedBindingPropertyData(obj->nBindings); + binding = obj->bindingTable(); for (quint32 i = 0; i < obj->nBindings; ++i, ++binding) { QString name = stringAt(binding->propertyNameIndex); @@ -1837,22 +1846,6 @@ bool QQmlPropertyValidator::validateObject(int objectIndex, const QV4::CompiledD } } - // Signal handlers were resolved and checked earlier in the signal handler conversion pass. - if (binding->flags & QV4::CompiledData::Binding::IsSignalHandlerExpression - || binding->flags & QV4::CompiledData::Binding::IsSignalHandlerObject) - continue; - - if (name.constData()->isUpper() && !binding->isAttachedProperty()) { - QQmlType *type = 0; - QQmlImportNamespace *typeNamespace = 0; - compiler->imports()->resolveType(stringAt(binding->propertyNameIndex), &type, 0, 0, &typeNamespace); - if (typeNamespace) - recordError(binding->location, tr("Invalid use of namespace")); - else - recordError(binding->location, tr("Invalid attached object assignment")); - return false; - } - bool bindingToDefaultProperty = false; bool notInRevision = false; @@ -1882,9 +1875,23 @@ bool QQmlPropertyValidator::validateObject(int objectIndex, const QV4::CompiledD bindingToDefaultProperty = true; } + if (pd) + collectedBindingPropertyData[i] = pd; + + if (name.constData()->isUpper() && !binding->isAttachedProperty()) { + QQmlType *type = 0; + QQmlImportNamespace *typeNamespace = 0; + compiler->imports()->resolveType(stringAt(binding->propertyNameIndex), &type, 0, 0, &typeNamespace); + if (typeNamespace) + recordError(binding->location, tr("Invalid use of namespace")); + else + recordError(binding->location, tr("Invalid attached object assignment")); + return false; + } + bool seenSubObjectWithId = false; - if (binding->type >= QV4::CompiledData::Binding::Type_Object && !customParser) { + if (binding->type >= QV4::CompiledData::Binding::Type_Object && (!customParser || binding->type == QV4::CompiledData::Binding::Type_AttachedProperty)) { qSwap(_seenObjectWithId, seenSubObjectWithId); const bool subObjectValid = validateObject(binding->value.objectIndex, binding, pd && QQmlValueTypeFactory::metaObjectForMetaType(pd->propType)); qSwap(_seenObjectWithId, seenSubObjectWithId); @@ -1902,6 +1909,11 @@ bool QQmlPropertyValidator::validateObject(int objectIndex, const QV4::CompiledD deferredBindings.setBit(i); } + // Signal handlers were resolved and checked earlier in the signal handler conversion pass. + if (binding->flags & QV4::CompiledData::Binding::IsSignalHandlerExpression + || binding->flags & QV4::CompiledData::Binding::IsSignalHandlerObject) + continue; + if (binding->type == QV4::CompiledData::Binding::Type_AttachedProperty) { if (instantiatingBinding && (instantiatingBinding->isAttachedProperty() || instantiatingBinding->isGroupProperty())) { recordError(binding->location, tr("Attached properties cannot be used here")); @@ -2009,6 +2021,8 @@ 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 0982058e14..75987af656 100644 --- a/src/qml/compiler/qqmltypecompiler_p.h +++ b/src/qml/compiler/qqmltypecompiler_p.h @@ -93,6 +93,7 @@ public: 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; } @@ -295,6 +296,7 @@ private: // collected state variables, essentially write-only mutable QHash<int, QBitArray> _deferredBindingsPerObject; mutable bool _seenObjectWithId; + mutable QVector<QV4::CompiledData::BindingPropertyData> _bindingPropertyDataPerObject; }; // ### merge with QtQml::JSCodeGen and operate directly on object->functionsAndExpressions once old compiler is gone. diff --git a/src/qml/compiler/qv4compileddata.cpp b/src/qml/compiler/qv4compileddata.cpp index 653416783e..5d954eb4fc 100644 --- a/src/qml/compiler/qv4compileddata.cpp +++ b/src/qml/compiler/qv4compileddata.cpp @@ -40,6 +40,7 @@ #include <private/qv4objectproto_p.h> #include <private/qv4lookup_p.h> #include <private/qv4regexpobject_p.h> +#include <private/qqmlpropertycache_p.h> #endif #include <private/qqmlirbuilder_p.h> #include <QCoreApplication> @@ -53,6 +54,15 @@ namespace QV4 { namespace CompiledData { #ifndef V4_BOOTSTRAP +CompilationUnit::CompilationUnit() + : data(0) + , engine(0) + , runtimeStrings(0) + , runtimeLookups(0) + , runtimeRegularExpressions(0) + , runtimeClasses(0) +{} + CompilationUnit::~CompilationUnit() { unlink(); diff --git a/src/qml/compiler/qv4compileddata_p.h b/src/qml/compiler/qv4compileddata_p.h index 7b40fa849a..f46e27fe98 100644 --- a/src/qml/compiler/qv4compileddata_p.h +++ b/src/qml/compiler/qv4compileddata_p.h @@ -46,6 +46,9 @@ QT_BEGIN_NAMESPACE +class QQmlPropertyCache; +class QQmlPropertyData; + namespace QmlIR { struct Document; } @@ -556,6 +559,9 @@ struct TypeReferenceMap : QHash<int, TypeReference> } }; +// index is per-object binding index +typedef QVector<QQmlPropertyData*> BindingPropertyData; + // This is how this hooks into the existing structures: //VM::Function @@ -570,14 +576,7 @@ struct Q_QML_PRIVATE_EXPORT CompilationUnit : public QQmlRefCount {} virtual ~CompilationUnit() {} #else - CompilationUnit() - : data(0) - , engine(0) - , runtimeStrings(0) - , runtimeLookups(0) - , runtimeRegularExpressions(0) - , runtimeClasses(0) - {} + CompilationUnit(); virtual ~CompilationUnit(); #endif @@ -598,6 +597,11 @@ struct Q_QML_PRIVATE_EXPORT CompilationUnit : public QQmlRefCount QVector<QV4::Function *> runtimeFunctions; mutable QQmlNullableValue<QUrl> m_url; + // index is object index. This allows fast access to the + // property data when initializing bindings, avoiding expensive + // lookups by string (property name). + QVector<BindingPropertyData> bindingPropertyDataPerObject; + QV4::Function *linkToEngine(QV4::ExecutionEngine *engine); void unlink(); diff --git a/src/qml/qml/qqmlobjectcreator.cpp b/src/qml/qml/qqmlobjectcreator.cpp index 4c86e6a307..f4f42f706b 100644 --- a/src/qml/qml/qqmlobjectcreator.cpp +++ b/src/qml/qml/qqmlobjectcreator.cpp @@ -124,6 +124,7 @@ void QQmlObjectCreator::init(QQmlContextData *providedParentContext) _scopeObject = 0; _valueTypeProperty = 0; _compiledObject = 0; + _compiledObjectIndex = -1; _ddata = 0; _propertyCache = 0; _vmeMetaObject = 0; @@ -233,9 +234,7 @@ bool QQmlObjectCreator::populateDeferredProperties(QObject *instance) QQmlData *declarativeData = QQmlData::get(instance); context = declarativeData->deferredData->context; sharedState->rootContext = context; - const int objectIndex = declarativeData->deferredData->deferredIdx; - const QV4::CompiledData::Object *obj = qmlUnit->objectAt(objectIndex); QObject *bindingTarget = instance; QQmlRefPointer<QQmlPropertyCache> cache = declarativeData->propertyCache; @@ -256,12 +255,18 @@ bool QQmlObjectCreator::populateDeferredProperties(QObject *instance) qSwap(_propertyCache, cache); qSwap(_qobject, instance); + + int objectIndex = declarativeData->deferredData->deferredIdx; + qSwap(_compiledObjectIndex, objectIndex); + + const QV4::CompiledData::Object *obj = qmlUnit->objectAt(_compiledObjectIndex); qSwap(_compiledObject, obj); + qSwap(_ddata, declarativeData); qSwap(_bindingTarget, bindingTarget); qSwap(_vmeMetaObject, vmeMetaObject); - QBitArray bindingSkipList = compiledData->deferredBindingsPerObject.value(objectIndex); + QBitArray bindingSkipList = compiledData->deferredBindingsPerObject.value(_compiledObjectIndex); for (int i = 0; i < bindingSkipList.count(); ++i) bindingSkipList.setBit(i, !bindingSkipList.testBit(i)); @@ -271,6 +276,7 @@ bool QQmlObjectCreator::populateDeferredProperties(QObject *instance) qSwap(_bindingTarget, bindingTarget); qSwap(_ddata, declarativeData); qSwap(_compiledObject, obj); + qSwap(_compiledObjectIndex, objectIndex); qSwap(_qobject, instance); qSwap(_propertyCache, cache); @@ -282,7 +288,7 @@ bool QQmlObjectCreator::populateDeferredProperties(QObject *instance) return errors.isEmpty(); } -void QQmlObjectCreator::setPropertyValue(QQmlPropertyData *property, const QV4::CompiledData::Binding *binding) +void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const QV4::CompiledData::Binding *binding) { QQmlPropertyPrivate::WriteFlags propertyWriteFlags = QQmlPropertyPrivate::BypassInterceptor | QQmlPropertyPrivate::RemoveBindingOnAliasWrite; @@ -636,8 +642,6 @@ void QQmlObjectCreator::setupBindings(const QBitArray &bindingsToSkip) QQmlListProperty<void> savedList; qSwap(_currentList, savedList); - QQmlPropertyData *defaultProperty = _compiledObject->indexOfDefaultProperty != -1 ? _propertyCache->parent()->defaultProperty() : _propertyCache->defaultProperty(); - if (_compiledObject->idIndex) { QQmlPropertyData *idProperty = _propertyCache->property(QStringLiteral("id"), _qobject, context); if (idProperty && idProperty->isWritable() && idProperty->propType == QMetaType::QString) { @@ -666,6 +670,8 @@ void QQmlObjectCreator::setupBindings(const QBitArray &bindingsToSkip) if (qmlTypeForObject(_bindingTarget)) { quint32 bindingSkipList = 0; + QQmlPropertyData *defaultProperty = _compiledObject->indexOfDefaultProperty != -1 ? _propertyCache->parent()->defaultProperty() : _propertyCache->defaultProperty(); + const QV4::CompiledData::Binding *binding = _compiledObject->bindingTable(); for (quint32 i = 0; i < _compiledObject->nBindings; ++i, ++binding) { QQmlPropertyData *property = binding->propertyNameIndex != 0 ? _propertyCache->property(stringAt(binding->propertyNameIndex), _qobject, context) : defaultProperty; @@ -678,38 +684,21 @@ void QQmlObjectCreator::setupBindings(const QBitArray &bindingsToSkip) } } - QQmlPropertyData *property = 0; + const QV4::CompiledData::BindingPropertyData &propertyData = compiledData->compilationUnit->bindingPropertyDataPerObject.at(_compiledObjectIndex); + const QV4::CompiledData::Binding *binding = _compiledObject->bindingTable(); for (quint32 i = 0; i < _compiledObject->nBindings; ++i, ++binding) { - - QString name = stringAt(binding->propertyNameIndex); - if (name.isEmpty()) - property = 0; - - if (!property - || (i > 0 && ((binding - 1)->propertyNameIndex != binding->propertyNameIndex - || (binding - 1)->flags != binding->flags)) - ) { - if (!name.isEmpty()) { - if (binding->flags & QV4::CompiledData::Binding::IsSignalHandlerExpression - || binding->flags & QV4::CompiledData::Binding::IsSignalHandlerObject) - property = QmlIR::PropertyResolver(_propertyCache).signal(name, /*notInRevision*/0, _qobject, context); - else - property = _propertyCache->property(name, _qobject, context); - } else - property = defaultProperty; - - if (property && property->isQList()) { - void *argv[1] = { (void*)&_currentList }; - QMetaObject::metacall(_qobject, QMetaObject::ReadProperty, property->coreIndex, argv); - } else if (_currentList.object) - _currentList = QQmlListProperty<void>(); - - } - if (static_cast<int>(i) < bindingsToSkip.size() && bindingsToSkip.testBit(i)) continue; + const QQmlPropertyData *property = propertyData.at(i); + + if (property && property->isQList()) { + void *argv[1] = { (void*)&_currentList }; + QMetaObject::metacall(_qobject, QMetaObject::ReadProperty, property->coreIndex, argv); + } else if (_currentList.object) + _currentList = QQmlListProperty<void>(); + if (!setPropertyBinding(property, binding)) return; } @@ -717,7 +706,7 @@ void QQmlObjectCreator::setupBindings(const QBitArray &bindingsToSkip) qSwap(_currentList, savedList); } -bool QQmlObjectCreator::setPropertyBinding(QQmlPropertyData *property, const QV4::CompiledData::Binding *binding) +bool QQmlObjectCreator::setPropertyBinding(const QQmlPropertyData *property, const QV4::CompiledData::Binding *binding) { if (binding->type == QV4::CompiledData::Binding::Type_AttachedProperty) { Q_ASSERT(stringAt(qmlUnit->objectAt(binding->value.objectIndex)->inheritedTypeNameIndex).isEmpty()); @@ -765,7 +754,7 @@ bool QQmlObjectCreator::setPropertyBinding(QQmlPropertyData *property, const QV4 QObject *groupObject = 0; QQmlValueType *valueType = 0; - QQmlPropertyData *valueTypeProperty = 0; + const QQmlPropertyData *valueTypeProperty = 0; QObject *bindingTarget = _bindingTarget; if (QQmlValueTypeFactory::isValueType(property->propType)) { @@ -1263,14 +1252,14 @@ void QQmlObjectCreator::clear() phase = Done; } -bool QQmlObjectCreator::populateInstance(int index, QObject *instance, QObject *bindingTarget, QQmlPropertyData *valueTypeProperty, const QBitArray &bindingsToSkip) +bool QQmlObjectCreator::populateInstance(int index, QObject *instance, QObject *bindingTarget, const QQmlPropertyData *valueTypeProperty, const QBitArray &bindingsToSkip) { - const QV4::CompiledData::Object *obj = qmlUnit->objectAt(index); - QQmlData *declarativeData = QQmlData::get(instance, /*create*/true); qSwap(_qobject, instance); qSwap(_valueTypeProperty, valueTypeProperty); + qSwap(_compiledObjectIndex, index); + const QV4::CompiledData::Object *obj = qmlUnit->objectAt(_compiledObjectIndex); qSwap(_compiledObject, obj); qSwap(_ddata, declarativeData); qSwap(_bindingTarget, bindingTarget); @@ -1278,10 +1267,10 @@ bool QQmlObjectCreator::populateInstance(int index, QObject *instance, QObject * QV4::Scope valueScope(v4); QV4::ScopedValue scopeObjectProtector(valueScope); - QQmlRefPointer<QQmlPropertyCache> cache = propertyCaches.at(index); + QQmlRefPointer<QQmlPropertyCache> cache = propertyCaches.at(_compiledObjectIndex); QQmlVMEMetaObject *vmeMetaObject = 0; - const QByteArray data = vmeMetaObjectData.value(index); + const QByteArray data = vmeMetaObjectData.value(_compiledObjectIndex); if (!data.isEmpty()) { Q_ASSERT(!cache.isNull()); // install on _object @@ -1295,14 +1284,14 @@ bool QQmlObjectCreator::populateInstance(int index, QObject *instance, QObject * vmeMetaObject = QQmlVMEMetaObject::get(_qobject); } - registerObjectWithContextById(index, _qobject); + registerObjectWithContextById(_compiledObjectIndex, _qobject); qSwap(_propertyCache, cache); qSwap(_vmeMetaObject, vmeMetaObject); QBitArray bindingSkipList = bindingsToSkip; { - QHash<int, QBitArray>::ConstIterator deferredBindings = compiledData->deferredBindingsPerObject.find(index); + QHash<int, QBitArray>::ConstIterator deferredBindings = compiledData->deferredBindingsPerObject.find(_compiledObjectIndex); if (deferredBindings != compiledData->deferredBindingsPerObject.constEnd()) { if (bindingSkipList.isEmpty()) bindingSkipList.resize(deferredBindings->count()); @@ -1311,7 +1300,7 @@ bool QQmlObjectCreator::populateInstance(int index, QObject *instance, QObject * if (deferredBindings->testBit(i)) bindingSkipList.setBit(i); QQmlData::DeferredData *deferData = new QQmlData::DeferredData; - deferData->deferredIdx = index; + deferData->deferredIdx = _compiledObjectIndex; deferData->compiledData = compiledData; deferData->compiledData->addref(); deferData->context = context; @@ -1327,6 +1316,7 @@ bool QQmlObjectCreator::populateInstance(int index, QObject *instance, QObject * qSwap(_bindingTarget, bindingTarget); qSwap(_ddata, declarativeData); qSwap(_compiledObject, obj); + qSwap(_compiledObjectIndex, index); qSwap(_valueTypeProperty, valueTypeProperty); qSwap(_qobject, instance); qSwap(_propertyCache, cache); diff --git a/src/qml/qml/qqmlobjectcreator_p.h b/src/qml/qml/qqmlobjectcreator_p.h index fcf247be5a..60fefe494f 100644 --- a/src/qml/qml/qqmlobjectcreator_p.h +++ b/src/qml/qml/qqmlobjectcreator_p.h @@ -94,12 +94,12 @@ private: QObject *createInstance(int index, QObject *parent = 0, bool isContextObject = false); bool populateInstance(int index, QObject *instance, - QObject *bindingTarget, QQmlPropertyData *valueTypeProperty, + QObject *bindingTarget, const QQmlPropertyData *valueTypeProperty, const QBitArray &bindingsToSkip = QBitArray()); void setupBindings(const QBitArray &bindingsToSkip); - bool setPropertyBinding(QQmlPropertyData *property, const QV4::CompiledData::Binding *binding); - void setPropertyValue(QQmlPropertyData *property, const QV4::CompiledData::Binding *binding); + bool setPropertyBinding(const QQmlPropertyData *property, const QV4::CompiledData::Binding *binding); + void setPropertyValue(const QQmlPropertyData *property, const QV4::CompiledData::Binding *binding); void setupFunctions(); QString stringAt(int idx) const { return qmlUnit->stringAt(idx); } @@ -136,7 +136,8 @@ private: QObject *_scopeObject; QObject *_bindingTarget; - QQmlPropertyData *_valueTypeProperty; // belongs to _qobjectForBindings's property cache + const QQmlPropertyData *_valueTypeProperty; // belongs to _qobjectForBindings's property cache + int _compiledObjectIndex; const QV4::CompiledData::Object *_compiledObject; QQmlData *_ddata; QQmlRefPointer<QQmlPropertyCache> _propertyCache; |