aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorSimon Hausmann <simon.hausmann@qt.io>2016-05-26 16:26:33 +0200
committerSimon Hausmann <simon.hausmann@qt.io>2016-05-30 07:16:17 +0000
commitf27d058c11b54b3c5f72d41c25cb00657b49a37b (patch)
tree9210b7c5f9af1016c495086470582b69fadc9e85 /src
parent515efdb8a65dc8ba22a56a02ee6d7056f39619cb (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.cpp130
-rw-r--r--src/qml/compiler/qqmltypecompiler_p.h19
-rw-r--r--src/qml/compiler/qv4compileddata_p.h6
-rw-r--r--src/qml/qml/qqmlcompiler_p.h1
-rw-r--r--src/qml/qml/qqmlobjectcreator.cpp42
-rw-r--r--src/qml/qml/qqmlobjectcreator_p.h2
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, &notInRevision, 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();