aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorSimon Hausmann <simon.hausmann@theqtcompany.com>2015-04-09 10:23:17 +0200
committerSimon Hausmann <simon.hausmann@theqtcompany.com>2015-04-21 06:36:47 +0000
commit3db3c38b1055cc8b41a9aa951c33f5621babb5d0 (patch)
tree8ba17669737ab0bd06cae7ac8366c5709614c5a0 /src
parenta41dc6147436f3c1c977ff8c04379ff4bde3f0a6 (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.cpp48
-rw-r--r--src/qml/compiler/qqmltypecompiler_p.h2
-rw-r--r--src/qml/compiler/qv4compileddata.cpp10
-rw-r--r--src/qml/compiler/qv4compileddata_p.h20
-rw-r--r--src/qml/qml/qqmlobjectcreator.cpp76
-rw-r--r--src/qml/qml/qqmlobjectcreator_p.h9
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;