aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSimon Hausmann <simon.hausmann@digia.com>2014-02-03 10:29:04 +0100
committerThe Qt Project <gerrit-noreply@qt-project.org>2014-02-04 18:28:34 +0100
commitb9fce6c9d1c6905edbd2e5629cc3fd166a88428a (patch)
tree418810219f87ea645a8dce29b978aaae1cf3b970
parente5bd40742ab8d0b4ffc9307eb46bc41456fe394a (diff)
[new compiler] Fix binding initialization order
Since commit 3d958cec8d53094a1bbab895377e451b07716e1f (loong time ago!) property bindings are stored in a linked list and newly encounted bindings at parse time are prepended to the list, causing the binding processing to happen in reverse order. There are however exception to the rule. For example list bindings are processed in declaration order and assignments to the default property are sorted by location in the file. In addition various tests rely on value properties being installed first, then followed by signal handlers and group/attached properties. Change-Id: I3bcae29faec5b2420fbba362cd81b8ba960ed19f Reviewed-by: Lars Knoll <lars.knoll@digia.com>
-rw-r--r--src/qml/compiler/qqmlcodegenerator.cpp35
-rw-r--r--src/qml/compiler/qqmlcodegenerator_p.h37
-rw-r--r--src/qml/compiler/qv4compileddata_p.h48
-rw-r--r--src/qml/qml/qqmlobjectcreator.cpp5
4 files changed, 116 insertions, 9 deletions
diff --git a/src/qml/compiler/qqmlcodegenerator.cpp b/src/qml/compiler/qqmlcodegenerator.cpp
index ccf7e47e26..04db46667e 100644
--- a/src/qml/compiler/qqmlcodegenerator.cpp
+++ b/src/qml/compiler/qqmlcodegenerator.cpp
@@ -169,7 +169,14 @@ QString QmlObject::appendBinding(Binding *b, bool isListBinding)
return tr("Property value set multiple times");
bindingNames.insert(b->propertyNameIndex);
}
- bindings->append(b);
+ if (isListBinding) {
+ bindings->append(b);
+ } else if (bindingToDefaultProperty) {
+ Binding *insertionPoint = bindings->findSortedInsertionPoint<QV4::CompiledData::Location, QV4::CompiledData::Binding, &QV4::CompiledData::Binding::location>(b);
+ bindings->insertAfter(insertionPoint, b);
+ } else {
+ bindings->prepend(b);
+ }
return QString(); // no error
}
@@ -1273,13 +1280,11 @@ QV4::CompiledData::QmlUnit *QmlUnitGenerator::generate(ParsedQML &output, const
}
char *bindingPtr = objectPtr + objectToWrite->offsetToBindings;
- for (const Binding *b = o->firstBinding(); b; b = b->next) {
- QV4::CompiledData::Binding *bindingToWrite = reinterpret_cast<QV4::CompiledData::Binding*>(bindingPtr);
- *bindingToWrite = *b;
- if (b->type == QV4::CompiledData::Binding::Type_Script)
- bindingToWrite->value.compiledScriptIndex = runtimeFunctionIndices[b->value.compiledScriptIndex];
- bindingPtr += sizeof(QV4::CompiledData::Binding);
- }
+ bindingPtr = writeBindings(bindingPtr, o, runtimeFunctionIndices, &QV4::CompiledData::Binding::isValueBinding);
+ bindingPtr = writeBindings(bindingPtr, o, runtimeFunctionIndices, &QV4::CompiledData::Binding::isSignalHandler);
+ bindingPtr = writeBindings(bindingPtr, o, runtimeFunctionIndices, &QV4::CompiledData::Binding::isAttachedProperty);
+ bindingPtr = writeBindings(bindingPtr, o, runtimeFunctionIndices, &QV4::CompiledData::Binding::isGroupProperty);
+ Q_ASSERT((bindingPtr - objectToWrite->offsetToBindings - objectPtr) / sizeof(QV4::CompiledData::Binding) == unsigned(o->bindingCount()));
quint32 *signalOffsetTable = reinterpret_cast<quint32*>(objectPtr + objectToWrite->offsetToSignals);
quint32 signalTableSize = 0;
@@ -1316,6 +1321,20 @@ QV4::CompiledData::QmlUnit *QmlUnitGenerator::generate(ParsedQML &output, const
return qmlUnit;
}
+char *QmlUnitGenerator::writeBindings(char *bindingPtr, QmlObject *o, const QVector<int> &runtimeFunctionIndices, BindingFilter filter) const
+{
+ for (const Binding *b = o->firstBinding(); b; b = b->next) {
+ if (!(b->*(filter))())
+ continue;
+ QV4::CompiledData::Binding *bindingToWrite = reinterpret_cast<QV4::CompiledData::Binding*>(bindingPtr);
+ *bindingToWrite = *b;
+ if (b->type == QV4::CompiledData::Binding::Type_Script)
+ bindingToWrite->value.compiledScriptIndex = runtimeFunctionIndices[b->value.compiledScriptIndex];
+ bindingPtr += sizeof(QV4::CompiledData::Binding);
+ }
+ return bindingPtr;
+}
+
int QmlUnitGenerator::getStringId(const QString &str) const
{
return jsUnitGenerator->getStringId(str);
diff --git a/src/qml/compiler/qqmlcodegenerator_p.h b/src/qml/compiler/qqmlcodegenerator_p.h
index ed94a99726..7c09b8bfa2 100644
--- a/src/qml/compiler/qqmlcodegenerator_p.h
+++ b/src/qml/compiler/qqmlcodegenerator_p.h
@@ -102,6 +102,40 @@ struct PoolList
last = item;
return count++;
}
+
+ void prepend(T *item) {
+ item->next = first;
+ first = item;
+ if (!last)
+ last = first;
+ ++count;
+ }
+
+ template <typename Sortable, typename Base, Sortable Base::*sortMember>
+ T *findSortedInsertionPoint(T *item) const
+ {
+ T *insertPos = 0;
+
+ for (T *it = first; it; it = it->next) {
+ if (!(it->*sortMember < item->*sortMember))
+ break;
+ insertPos = it;
+ }
+
+ return insertPos;
+ }
+
+ void insertAfter(T *insertionPoint, T *item) {
+ if (!insertionPoint) {
+ prepend(item);
+ } else if (insertionPoint == last) {
+ append(item);
+ } else {
+ item->next = insertionPoint->next;
+ insertionPoint->next = item;
+ ++count;
+ }
+ }
};
struct QmlObject;
@@ -342,6 +376,9 @@ struct Q_QML_EXPORT QmlUnitGenerator
QV4::CompiledData::QmlUnit *generate(ParsedQML &output, const QVector<int> &runtimeFunctionIndices);
private:
+ typedef bool (Binding::*BindingFilter)() const;
+ char *writeBindings(char *bindingPtr, QmlObject *o, const QVector<int> &runtimeFunctionIndices, BindingFilter filter) const;
+
int getStringId(const QString &str) const;
QV4::Compiler::JSUnitGenerator *jsUnitGenerator;
diff --git a/src/qml/compiler/qv4compileddata_p.h b/src/qml/compiler/qv4compileddata_p.h
index 77044ecdd8..edb1737648 100644
--- a/src/qml/compiler/qv4compileddata_p.h
+++ b/src/qml/compiler/qv4compileddata_p.h
@@ -72,6 +72,10 @@ struct Location
{
qint32 line;
qint32 column;
+ inline bool operator<(const Location &other) const {
+ return line < other.line ||
+ (line == other.line && column < other.column);
+ }
};
struct TypeReference
@@ -314,6 +318,50 @@ struct Q_QML_EXPORT Binding
Location location;
Location valueLocation;
+ bool isValueBinding() const
+ {
+ if (type == Type_AttachedProperty
+ || type == Type_GroupProperty)
+ return false;
+ if (flags & IsSignalHandlerExpression
+ || flags & IsSignalHandlerObject)
+ return false;
+ return true;
+ }
+
+ bool isSignalHandler() const
+ {
+ if (flags & IsSignalHandlerExpression || flags & IsSignalHandlerObject) {
+ Q_ASSERT(!isValueBinding());
+ Q_ASSERT(!isAttachedProperty());
+ Q_ASSERT(!isGroupProperty());
+ return true;
+ }
+ return false;
+ }
+
+ bool isAttachedProperty() const
+ {
+ if (type == Type_AttachedProperty) {
+ Q_ASSERT(!isValueBinding());
+ Q_ASSERT(!isSignalHandler());
+ Q_ASSERT(!isGroupProperty());
+ return true;
+ }
+ return false;
+ }
+
+ bool isGroupProperty() const
+ {
+ if (type == Type_GroupProperty) {
+ Q_ASSERT(!isValueBinding());
+ Q_ASSERT(!isSignalHandler());
+ Q_ASSERT(!isAttachedProperty());
+ return true;
+ }
+ return false;
+ }
+
QString valueAsString(const Unit *unit) const;
QString valueAsScriptString(const Unit *unit) const;
double valueAsNumber() const
diff --git a/src/qml/qml/qqmlobjectcreator.cpp b/src/qml/qml/qqmlobjectcreator.cpp
index ea4270b848..5bb210b28b 100644
--- a/src/qml/qml/qqmlobjectcreator.cpp
+++ b/src/qml/qml/qqmlobjectcreator.cpp
@@ -536,7 +536,10 @@ void QmlObjectCreator::setupBindings()
if (name.isEmpty())
property = 0;
- if (!property || (i > 0 && (binding - 1)->propertyNameIndex != binding->propertyNameIndex)) {
+ 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)