summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAaron Kennedy <aaron.kennedy@nokia.com>2009-08-11 03:59:56 (GMT)
committerAaron Kennedy <aaron.kennedy@nokia.com>2009-08-11 03:59:56 (GMT)
commita57bcdde329ef4c9a71aa6ba714f5e30ffd5dc6d (patch)
tree64cde5908b51e852a3c761031b809f3f056cec16
parent712b8ecad2407645ef80fef94181782d2227b002 (diff)
downloadQt-a57bcdde329ef4c9a71aa6ba714f5e30ffd5dc6d.zip
Qt-a57bcdde329ef4c9a71aa6ba714f5e30ffd5dc6d.tar.gz
Qt-a57bcdde329ef4c9a71aa6ba714f5e30ffd5dc6d.tar.bz2
Object property binding optimization
Add a binding optimization that hits anchors.fill: parent
-rw-r--r--src/declarative/qml/qmlbasicscript.cpp17
-rw-r--r--src/declarative/qml/qmlbasicscript_p.h2
-rw-r--r--src/declarative/qml/qmlbindingoptimizations.cpp92
-rw-r--r--src/declarative/qml/qmlbindingoptimizations_p.h35
-rw-r--r--src/declarative/qml/qmlcompiler.cpp40
-rw-r--r--src/declarative/qml/qmlcompiler_p.h1
-rw-r--r--src/declarative/qml/qmlcontext_p.h4
-rw-r--r--src/declarative/qml/qmlinstruction.cpp2
-rw-r--r--src/declarative/qml/qmlinstruction_p.h11
-rw-r--r--src/declarative/qml/qmlvme.cpp22
10 files changed, 202 insertions, 24 deletions
diff --git a/src/declarative/qml/qmlbasicscript.cpp b/src/declarative/qml/qmlbasicscript.cpp
index 8993845..f3f9289 100644
--- a/src/declarative/qml/qmlbasicscript.cpp
+++ b/src/declarative/qml/qmlbasicscript.cpp
@@ -714,6 +714,23 @@ int QmlBasicScript::singleIdFetchIndex() const
return d->instructions()[0].fetch.idx;
}
+bool QmlBasicScript::isSingleContextProperty() const
+{
+ if (!isValid())
+ return false;
+
+ return d->instructionCount == 1 &&
+ d->instructions()[0].type == ScriptInstruction::FetchContextConstant;
+}
+
+int QmlBasicScript::singleContextPropertyIndex() const
+{
+ if (!isSingleContextProperty())
+ return -1;
+
+ return d->instructions()[0].constant.idx;
+}
+
/*!
Return a pointer to the script's compile data, or null if there is no data.
*/
diff --git a/src/declarative/qml/qmlbasicscript_p.h b/src/declarative/qml/qmlbasicscript_p.h
index d096746..5ad7735 100644
--- a/src/declarative/qml/qmlbasicscript_p.h
+++ b/src/declarative/qml/qmlbasicscript_p.h
@@ -101,6 +101,8 @@ public:
bool isSingleIdFetch() const;
int singleIdFetchIndex() const;
+ bool isSingleContextProperty() const;
+ int singleContextPropertyIndex() const;
private:
int flags;
QmlBasicScriptPrivate *d;
diff --git a/src/declarative/qml/qmlbindingoptimizations.cpp b/src/declarative/qml/qmlbindingoptimizations.cpp
index 235c034..a10b1e3 100644
--- a/src/declarative/qml/qmlbindingoptimizations.cpp
+++ b/src/declarative/qml/qmlbindingoptimizations.cpp
@@ -44,17 +44,27 @@
QT_BEGIN_NAMESPACE
+/*
+ The QmlBinding_Id optimization handles expressions of the type:
-QmlBindingIdOptimization::QmlBindingIdOptimization(QObject *object,
- int propertyIdx,
- QmlContext *context,
- int id)
+ property: id
+
+ where id is a local context id, and property is an object property.
+ Coercian between id and property must be checked outside the QmlBinding_Id -
+ it assumes that they coerce successfully.
+
+ The QmlBinding_Id class avoids any signal slot connections, through the
+ special "bindings" linked list maintained in the
+ QmlContextPrivate::ContextGuard instance for each id object.
+*/
+QmlBinding_Id::QmlBinding_Id(QObject *object, int propertyIdx,
+ QmlContext *context, int id)
: m_prev(0), m_next(0), m_object(object), m_propertyIdx(propertyIdx), m_id(id)
{
QmlAbstractExpression::setContext(context);
}
-void QmlBindingIdOptimization::setEnabled(bool e)
+void QmlBinding_Id::setEnabled(bool e)
{
if (e) {
addToObject(m_object);
@@ -64,12 +74,12 @@ void QmlBindingIdOptimization::setEnabled(bool e)
}
}
-int QmlBindingIdOptimization::propertyIndex()
+int QmlBinding_Id::propertyIndex()
{
return m_propertyIdx;
}
-void QmlBindingIdOptimization::update()
+void QmlBinding_Id::update()
{
QmlContextPrivate *ctxtPriv =
static_cast<QmlContextPrivate *>(QObjectPrivate::get(context()));
@@ -91,7 +101,7 @@ void QmlBindingIdOptimization::update()
}
}
-void QmlBindingIdOptimization::reset()
+void QmlBinding_Id::reset()
{
if (m_prev) {
*m_prev = m_next;
@@ -106,4 +116,70 @@ void QmlBindingIdOptimization::reset()
m_propertyIdx, a);
}
+/*
+ The QmlBinding_ObjectProperty optimization handles expressions of the type:
+
+ property: objectProperty
+
+ where both property and objectProperty are object properties on the target
+ object. Coercian between the two must be checked outside the
+ QmlBinding_ObjectProperty - it assumes that they coerce successfully.
+
+ Due to dot properties, property does not have to be on the same object as
+ objectProperty. For example:
+
+ anchors.fill: parent
+*/
+QmlBinding_ObjProperty::QmlBinding_ObjProperty(QObject *object, int propertyIdx,
+ QObject *context, int contextIdx,
+ int notifyIdx)
+: m_enabled(false), m_object(object), m_propertyIdx(propertyIdx),
+ m_context(context), m_contextIdx(contextIdx), m_notifyIdx(notifyIdx)
+{
+}
+
+void QmlBinding_ObjProperty::setEnabled(bool e)
+{
+ m_enabled = e;
+ if (e) {
+ addToObject(m_object);
+ update();
+ } else {
+ removeFromObject();
+ }
+}
+
+int QmlBinding_ObjProperty::propertyIndex()
+{
+ return m_propertyIdx;
+}
+
+void QmlBinding_ObjProperty::update()
+{
+ if (!m_enabled)
+ return;
+
+ QObject *value = 0;
+ void *a[] = { &value, 0 };
+
+ // Read
+ QMetaObject::metacall(m_context, QMetaObject::ReadProperty,
+ m_contextIdx, a);
+
+ // Write
+ QMetaObject::metacall(m_object, QMetaObject::WriteProperty,
+ m_propertyIdx, a);
+
+ // Connect notify if needed. Only need to connect once, so we set
+ // m_notifyIdx back to -1 afterwards
+ static int slotIdx = -1;
+ if (m_notifyIdx != -1) {
+ if (slotIdx == -1)
+ slotIdx = QmlBinding_ObjProperty::staticMetaObject.indexOfMethod("update()");
+
+ QMetaObject::connect(m_context, m_notifyIdx, this, slotIdx);
+ m_notifyIdx = -1;
+ }
+}
+
QT_END_NAMESPACE
diff --git a/src/declarative/qml/qmlbindingoptimizations_p.h b/src/declarative/qml/qmlbindingoptimizations_p.h
index f50972d..2d2ffec 100644
--- a/src/declarative/qml/qmlbindingoptimizations_p.h
+++ b/src/declarative/qml/qmlbindingoptimizations_p.h
@@ -60,11 +60,11 @@ QT_BEGIN_HEADER
QT_BEGIN_NAMESPACE
-class QmlBindingIdOptimization : public QmlAbstractExpression,
- public QmlAbstractBinding
+class QmlBinding_Id : public QmlAbstractExpression,
+ public QmlAbstractBinding
{
public:
- QmlBindingIdOptimization(QObject *object, int propertyIdx,
+ QmlBinding_Id(QObject *object, int propertyIdx,
QmlContext *context, int id);
// Inherited from QmlAbstractBinding
@@ -75,14 +75,39 @@ public:
void reset();
private:
- QmlBindingIdOptimization **m_prev;
- QmlBindingIdOptimization *m_next;
+ QmlBinding_Id **m_prev;
+ QmlBinding_Id *m_next;
QObject *m_object;
int m_propertyIdx;
int m_id;
};
+class QmlBinding_ObjProperty : public QObject,
+ public QmlAbstractExpression,
+ public QmlAbstractBinding
+{
+ Q_OBJECT
+public:
+ QmlBinding_ObjProperty(QObject *object, int propertyIdx,
+ QObject *context, int contextIdx, int notifyIdx);
+
+ // Inherited from QmlAbstractBinding
+ virtual void setEnabled(bool);
+ virtual int propertyIndex();
+
+private slots:
+ virtual void update();
+
+private:
+ bool m_enabled;
+ QObject *m_object;
+ int m_propertyIdx;
+ QObject *m_context;
+ int m_contextIdx;
+ int m_notifyIdx;
+};
+
QT_END_NAMESPACE
QT_END_HEADER
diff --git a/src/declarative/qml/qmlcompiler.cpp b/src/declarative/qml/qmlcompiler.cpp
index 7c0964b..75ed94b 100644
--- a/src/declarative/qml/qmlcompiler.cpp
+++ b/src/declarative/qml/qmlcompiler.cpp
@@ -2069,6 +2069,7 @@ void QmlCompiler::genBindingAssignment(QmlParser::Value *binding,
QmlBasicScript bs;
if (ref.isBasicScript)
bs.load(ref.compiledData.constData() + sizeof(quint32));
+
if (bs.isSingleIdFetch()) {
int idIndex = bs.singleIdFetchIndex();
QmlParser::Object *idObj = compileState.idIndexes.value(idIndex);
@@ -2079,9 +2080,26 @@ void QmlCompiler::genBindingAssignment(QmlParser::Value *binding,
output->bytecode << store;
return;
}
+ } else if (bs.isSingleContextProperty()) {
+ int propIndex = bs.singleContextPropertyIndex();
+
+ QMetaProperty p =
+ ref.bindingContext.object->metaObject()->property(propIndex);
+ if ((p.notifySignalIndex() != -1 || p.isConstant()) &&
+ canCoerce(prop->type, p.userType())) {
+
+ store.type = QmlInstruction::StoreObjPropBinding;
+ store.assignObjPropBinding.property = prop->index;
+ store.assignObjPropBinding.contextIdx = propIndex;
+ store.assignObjPropBinding.context = ref.bindingContext.stack;
+ store.assignObjPropBinding.notifyIdx = p.notifySignalIndex();
+
+ output->bytecode << store;
+ return;
+ }
}
- store.type = QmlInstruction::StoreCompiledBinding;
+ store.type = QmlInstruction::StoreBinding;
store.assignBinding.value = output->indexForByteArray(ref.compiledData);
store.assignBinding.context = ref.bindingContext.stack;
store.assignBinding.owner = ref.bindingContext.owner;
@@ -2157,8 +2175,7 @@ bool QmlCompiler::completeComponentBuild()
*/
bool QmlCompiler::canCoerce(int to, QmlParser::Object *from)
{
- const QMetaObject *toMo =
- QmlMetaType::rawMetaObjectForType(to);
+ const QMetaObject *toMo = QmlMetaType::rawMetaObjectForType(to);
const QMetaObject *fromMo = from->metaObject();
while (fromMo) {
@@ -2169,6 +2186,23 @@ bool QmlCompiler::canCoerce(int to, QmlParser::Object *from)
return false;
}
+/*!
+ Returns true if from can be assigned to a (QObject) property of type
+ to.
+*/
+bool QmlCompiler::canCoerce(int to, int from)
+{
+ const QMetaObject *toMo = QmlMetaType::rawMetaObjectForType(to);
+ const QMetaObject *fromMo = QmlMetaType::rawMetaObjectForType(from);
+
+ while (fromMo) {
+ if (fromMo == toMo)
+ return true;
+ fromMo = fromMo->superClass();
+ }
+ return false;
+}
+
QmlType *QmlCompiler::toQmlType(QmlParser::Object *from)
{
// ### Optimize
diff --git a/src/declarative/qml/qmlcompiler_p.h b/src/declarative/qml/qmlcompiler_p.h
index 3d79e32..4f56169 100644
--- a/src/declarative/qml/qmlcompiler_p.h
+++ b/src/declarative/qml/qmlcompiler_p.h
@@ -226,6 +226,7 @@ private:
static int findSignalByName(const QMetaObject *, const QByteArray &name);
static bool canCoerce(int to, QmlParser::Object *from);
+ static bool canCoerce(int to, int from);
static QmlType *toQmlType(QmlParser::Object *from);
QStringList deferredProperties(QmlParser::Object *);
diff --git a/src/declarative/qml/qmlcontext_p.h b/src/declarative/qml/qmlcontext_p.h
index b5479d9..84d990c 100644
--- a/src/declarative/qml/qmlcontext_p.h
+++ b/src/declarative/qml/qmlcontext_p.h
@@ -69,7 +69,7 @@ class QmlEngine;
class QmlExpression;
class QmlExpressionPrivate;
class QmlAbstractExpression;
-class QmlBindingIdOptimization;
+class QmlBinding_Id;
class QmlContextPrivate : public QObjectPrivate
{
@@ -114,7 +114,7 @@ public:
{
ContextGuard() : priv(0), bindings(0) {}
QmlContextPrivate *priv;
- QmlBindingIdOptimization *bindings;
+ QmlBinding_Id *bindings;
ContextGuard &operator=(QObject *obj) {
(QGuard<QObject>&)*this = obj; return *this;
}
diff --git a/src/declarative/qml/qmlinstruction.cpp b/src/declarative/qml/qmlinstruction.cpp
index 889a057..fd912ac 100644
--- a/src/declarative/qml/qmlinstruction.cpp
+++ b/src/declarative/qml/qmlinstruction.cpp
@@ -140,7 +140,7 @@ void QmlCompiledData::dump(QmlInstruction *instr, int idx)
case QmlInstruction::AssignCustomType:
qWarning() << idx << "\t" << line << "\t" << "ASSIGN_CUSTOMTYPE\t\t" << instr->assignCustomType.propertyIndex << "\t" << instr->assignCustomType.valueIndex;
break;
- case QmlInstruction::StoreCompiledBinding:
+ case QmlInstruction::StoreBinding:
qWarning() << idx << "\t" << line << "\t" << "STORE_COMPILED_BINDING\t" << instr->assignBinding.property << "\t" << instr->assignBinding.value << "\t\t" << instr->assignBinding.context;
break;
case QmlInstruction::StoreValueSource:
diff --git a/src/declarative/qml/qmlinstruction_p.h b/src/declarative/qml/qmlinstruction_p.h
index 16bc8cf..7f3498f 100644
--- a/src/declarative/qml/qmlinstruction_p.h
+++ b/src/declarative/qml/qmlinstruction_p.h
@@ -122,10 +122,11 @@ public:
// Unresolved single assignment
//
AssignSignalObject, /* assignSignalObject */
- AssignCustomType, /* assignCustomType */
+ AssignCustomType, /* assignCustomType */
- StoreCompiledBinding, /* assignBinding */
+ StoreBinding, /* assignBinding */
StoreIdOptBinding, /* assignIdOptBinding */
+ StoreObjPropBinding, /* assignObjPropBinding */
StoreValueSource, /* assignValueSource */
BeginObject, /* begin */
@@ -194,6 +195,12 @@ public:
} assignIdOptBinding;
struct {
int property;
+ int contextIdx;
+ short context;
+ short notifyIdx;
+ } assignObjPropBinding;
+ struct {
+ int property;
} fetch;
struct {
int property;
diff --git a/src/declarative/qml/qmlvme.cpp b/src/declarative/qml/qmlvme.cpp
index dccf5c4..fdfeddc 100644
--- a/src/declarative/qml/qmlvme.cpp
+++ b/src/declarative/qml/qmlvme.cpp
@@ -529,7 +529,7 @@ QObject *QmlVME::run(QStack<QObject *> &stack, QmlContext *ctxt, QmlCompiledData
}
break;
- case QmlInstruction::StoreCompiledBinding:
+ case QmlInstruction::StoreBinding:
{
QObject *target =
stack.at(stack.count() - 1 - instr.assignBinding.owner);
@@ -554,14 +554,30 @@ QObject *QmlVME::run(QStack<QObject *> &stack, QmlContext *ctxt, QmlCompiledData
{
QObject *target = stack.top();
- QmlBindingIdOptimization *bind =
- new QmlBindingIdOptimization(target, instr.assignIdOptBinding.property, ctxt, instr.assignIdOptBinding.id);
+ QmlBinding_Id *bind =
+ new QmlBinding_Id(target, instr.assignIdOptBinding.property,
+ ctxt, instr.assignIdOptBinding.id);
bindValues.append(bind);
// ### Need a mePtr
bind->addToObject(target);
}
break;
+ case QmlInstruction::StoreObjPropBinding:
+ {
+ QObject *target = stack.top();
+ QObject *context =
+ stack.at(stack.count() - 1 - instr.assignObjPropBinding.context);
+
+ QmlBinding_ObjProperty *bind =
+ new QmlBinding_ObjProperty(target, instr.assignObjPropBinding.property, context, instr.assignObjPropBinding.contextIdx, instr.assignObjPropBinding.notifyIdx);
+
+ bindValues.append(bind);
+ // ### Need a mePtr
+ bind->addToObject(target);
+ }
+ break;
+
case QmlInstruction::StoreValueSource:
{
QmlPropertyValueSource *vs =