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>
This commit is contained in:
parent
515efdb8a6
commit
f27d058c11
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
|
|
Loading…
Reference in New Issue