summaryrefslogtreecommitdiffstats
path: root/src/declarative
diff options
context:
space:
mode:
authorAaron Kennedy <aaron.kennedy@nokia.com>2009-08-10 05:37:19 (GMT)
committerAaron Kennedy <aaron.kennedy@nokia.com>2009-08-10 08:01:37 (GMT)
commit8c3405bbf65826f0ab0be0bd090d723f8efaa3af (patch)
treef6886a2b8a86f567b98728bba9cdc3d1be780dcf /src/declarative
parent12ffa33ddc725cd94662a383af6e1793049c807c (diff)
downloadQt-8c3405bbf65826f0ab0be0bd090d723f8efaa3af.zip
Qt-8c3405bbf65826f0ab0be0bd090d723f8efaa3af.tar.gz
Qt-8c3405bbf65826f0ab0be0bd090d723f8efaa3af.tar.bz2
Abstract expression and binding APIs
By splitting the interface through which the system interacts with bindings away from a specific implementation, we can introduce highly specialized implementations for specific optimizations. This commit also includes a sample optimization for object properties being assigned directly from a local id.
Diffstat (limited to 'src/declarative')
-rw-r--r--src/declarative/qml/qml.pri6
-rw-r--r--src/declarative/qml/qmlbasicscript.cpp17
-rw-r--r--src/declarative/qml/qmlbasicscript_p.h3
-rw-r--r--src/declarative/qml/qmlbinding.cpp82
-rw-r--r--src/declarative/qml/qmlbinding.h36
-rw-r--r--src/declarative/qml/qmlbinding_p.h3
-rw-r--r--src/declarative/qml/qmlbindingoptimizations.cpp109
-rw-r--r--src/declarative/qml/qmlbindingoptimizations_p.h91
-rw-r--r--src/declarative/qml/qmlcompiler.cpp19
-rw-r--r--src/declarative/qml/qmlcompiler_p.h2
-rw-r--r--src/declarative/qml/qmlcomponent.cpp4
-rw-r--r--src/declarative/qml/qmlcomponent_p.h2
-rw-r--r--src/declarative/qml/qmlcontext.cpp14
-rw-r--r--src/declarative/qml/qmlcontext_p.h6
-rw-r--r--src/declarative/qml/qmldeclarativedata_p.h4
-rw-r--r--src/declarative/qml/qmlengine.cpp19
-rw-r--r--src/declarative/qml/qmlengine_p.h5
-rw-r--r--src/declarative/qml/qmlenginedebug.cpp2
-rw-r--r--src/declarative/qml/qmlexpression.cpp92
-rw-r--r--src/declarative/qml/qmlexpression_p.h25
-rw-r--r--src/declarative/qml/qmlinstruction_p.h5
-rw-r--r--src/declarative/qml/qmlmetaproperty.cpp63
-rw-r--r--src/declarative/qml/qmlmetaproperty.h6
-rw-r--r--src/declarative/qml/qmlvme.cpp19
-rw-r--r--src/declarative/util/qmlsetproperties.cpp5
-rw-r--r--src/declarative/util/qmlstate.h4
-rw-r--r--src/declarative/util/qmlstate_p.h2
-rw-r--r--src/declarative/util/qmltransitionmanager.cpp2
28 files changed, 505 insertions, 142 deletions
diff --git a/src/declarative/qml/qml.pri b/src/declarative/qml/qml.pri
index 75e5692..575876f 100644
--- a/src/declarative/qml/qml.pri
+++ b/src/declarative/qml/qml.pri
@@ -29,7 +29,8 @@ SOURCES += qml/qmlparser.cpp \
qml/qmlenginedebug.cpp \
qml/qmlrewrite.cpp \
qml/qmlbasicscript.cpp \
- qml/qmlvaluetype.cpp
+ qml/qmlvaluetype.cpp \
+ qml/qmlbindingoptimizations.cpp
HEADERS += qml/qmlparser_p.h \
qml/qmlinstruction_p.h \
@@ -75,7 +76,8 @@ HEADERS += qml/qmlparser_p.h \
qml/qmlenginedebug_p.h \
qml/qmlrewrite_p.h \
qml/qpodvector_p.h \
- qml/qmlvaluetype_p.h
+ qml/qmlvaluetype_p.h \
+ qml/qmlbindingoptimizations_p.h
# for qtscript debugger
contains(QT_CONFIG, scripttools):QT += scripttools
diff --git a/src/declarative/qml/qmlbasicscript.cpp b/src/declarative/qml/qmlbasicscript.cpp
index 21860a5..8993845 100644
--- a/src/declarative/qml/qmlbasicscript.cpp
+++ b/src/declarative/qml/qmlbasicscript.cpp
@@ -697,6 +697,23 @@ QVariant QmlBasicScript::run(QmlContext *context, QObject *me)
return stack.top();
}
+bool QmlBasicScript::isSingleIdFetch() const
+{
+ if (!isValid())
+ return false;
+
+ return d->instructionCount == 1 &&
+ d->instructions()[0].type == ScriptInstruction::LoadIdObject;
+}
+
+int QmlBasicScript::singleIdFetchIndex() const
+{
+ if (!isSingleIdFetch())
+ return -1;
+
+ return d->instructions()[0].fetch.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 92d58f9..d096746 100644
--- a/src/declarative/qml/qmlbasicscript_p.h
+++ b/src/declarative/qml/qmlbasicscript_p.h
@@ -98,6 +98,9 @@ public:
QVariant run(QmlContext *, QObject *);
+ bool isSingleIdFetch() const;
+ int singleIdFetchIndex() const;
+
private:
int flags;
QmlBasicScriptPrivate *d;
diff --git a/src/declarative/qml/qmlbinding.cpp b/src/declarative/qml/qmlbinding.cpp
index 41cef49..7c5b366 100644
--- a/src/declarative/qml/qmlbinding.cpp
+++ b/src/declarative/qml/qmlbinding.cpp
@@ -47,6 +47,8 @@
#include <QVariant>
#include <private/qfxperf_p.h>
#include <QtCore/qdebug.h>
+#include <private/qmlcontext_p.h>
+#include <private/qmldeclarativedata_p.h>
Q_DECLARE_METATYPE(QList<QObject *>);
@@ -55,7 +57,7 @@ QT_BEGIN_NAMESPACE
QML_DEFINE_NOCREATE_TYPE(QmlBinding);
QmlBindingPrivate::QmlBindingPrivate()
-: inited(false), updating(false), enabled(true), mePtr(0)
+: updating(false), enabled(false), mePtr(0)
{
}
@@ -92,25 +94,6 @@ QmlMetaProperty QmlBinding::property() const
return d->property;
}
-void QmlBinding::init()
-{
- Q_D(QmlBinding);
-
- if (d->inited)
- return;
- d->inited = true;
- update();
-}
-
-void QmlBinding::forceUpdate()
-{
- Q_D(QmlBinding);
- if (!d->inited)
- init();
- else
- update();
-}
-
void QmlBinding::update()
{
Q_D(QmlBinding);
@@ -118,7 +101,7 @@ void QmlBinding::update()
#ifdef Q_ENABLE_PERFORMANCE_LOG
QFxPerfTimer<QFxPerf::BindableValueUpdate> bu;
#endif
- if (!d->inited || !d->enabled)
+ if (!d->enabled)
return;
if (!d->updating) {
@@ -168,6 +151,20 @@ void QmlBinding::setEnabled(bool e)
Q_D(QmlBinding);
d->enabled = e;
setTrackChange(e);
+
+ if (e) {
+ d->mePtr = 0;
+ addToObject(d->property.object());
+ update();
+ } else {
+ removeFromObject();
+ }
+}
+
+int QmlBinding::propertyIndex()
+{
+ Q_D(QmlBinding);
+ return d->property.coreIndex();
}
bool QmlBinding::enabled() const
@@ -177,4 +174,47 @@ bool QmlBinding::enabled() const
return d->enabled;
}
+QString QmlBinding::expression() const
+{
+ return QmlExpression::expression();
+}
+
+QmlAbstractBinding::QmlAbstractBinding()
+: m_prevBinding(0), m_nextBinding(0)
+{
+}
+
+QmlAbstractBinding::~QmlAbstractBinding()
+{
+ removeFromObject();
+}
+
+void QmlAbstractBinding::addToObject(QObject *object)
+{
+ removeFromObject();
+
+ if (object) {
+ QmlDeclarativeData *data = QmlDeclarativeData::get(object, true);
+ m_nextBinding = data->bindings;
+ if (m_nextBinding) m_nextBinding->m_prevBinding = &m_nextBinding;
+ m_prevBinding = &data->bindings;
+ data->bindings = this;
+ }
+}
+
+void QmlAbstractBinding::removeFromObject()
+{
+ if (m_prevBinding) {
+ *m_prevBinding = m_nextBinding;
+ if (m_nextBinding) m_nextBinding->m_prevBinding = m_prevBinding;
+ m_prevBinding = 0;
+ m_nextBinding = 0;
+ }
+}
+
+QString QmlAbstractBinding::expression() const
+{
+ return QLatin1String("<Unknown>");
+}
+
QT_END_NAMESPACE
diff --git a/src/declarative/qml/qmlbinding.h b/src/declarative/qml/qmlbinding.h
index c2182d5..ad25c16 100644
--- a/src/declarative/qml/qmlbinding.h
+++ b/src/declarative/qml/qmlbinding.h
@@ -54,9 +54,34 @@ QT_BEGIN_NAMESPACE
QT_MODULE(Declarative)
+class QmlAbstractBinding
+{
+public:
+ QmlAbstractBinding();
+ virtual ~QmlAbstractBinding();
+
+ virtual QString expression() const;
+
+ virtual void setEnabled(bool) = 0;
+ virtual int propertyIndex() = 0;
+
+ virtual void update() = 0;
+
+ void addToObject(QObject *);
+ void removeFromObject();
+
+private:
+ friend class QmlDeclarativeData;
+ friend class QmlMetaProperty;
+
+ QmlAbstractBinding **m_prevBinding;
+ QmlAbstractBinding *m_nextBinding;
+};
+
class QmlContext;
class QmlBindingPrivate;
-class Q_DECLARATIVE_EXPORT QmlBinding : public QmlExpression
+class Q_DECLARATIVE_EXPORT QmlBinding : public QmlExpression,
+ public QmlAbstractBinding
{
Q_OBJECT
public:
@@ -67,12 +92,13 @@ public:
void setTarget(const QmlMetaProperty &);
QmlMetaProperty property() const;
- void init();
- void forceUpdate();
-
- void setEnabled(bool);
bool enabled() const;
+ // Inherited from QmlAbstractBinding
+ virtual void setEnabled(bool);
+ virtual int propertyIndex();
+ virtual QString expression() const;
+
public Q_SLOTS:
void update();
diff --git a/src/declarative/qml/qmlbinding_p.h b/src/declarative/qml/qmlbinding_p.h
index ec1a04a..767e6af 100644
--- a/src/declarative/qml/qmlbinding_p.h
+++ b/src/declarative/qml/qmlbinding_p.h
@@ -65,13 +65,12 @@ class QmlBindingPrivate : public QmlExpressionPrivate
public:
QmlBindingPrivate();
- bool inited:1;
bool updating:1;
bool enabled:1;
QmlMetaProperty property;
- QmlBinding **mePtr;
+ QmlAbstractBinding **mePtr;
};
QT_END_NAMESPACE
diff --git a/src/declarative/qml/qmlbindingoptimizations.cpp b/src/declarative/qml/qmlbindingoptimizations.cpp
new file mode 100644
index 0000000..235c034
--- /dev/null
+++ b/src/declarative/qml/qmlbindingoptimizations.cpp
@@ -0,0 +1,109 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qmlbindingoptimizations_p.h"
+#include <private/qmlcontext_p.h>
+
+QT_BEGIN_NAMESPACE
+
+
+QmlBindingIdOptimization::QmlBindingIdOptimization(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)
+{
+ if (e) {
+ addToObject(m_object);
+ update();
+ } else {
+ removeFromObject();
+ }
+}
+
+int QmlBindingIdOptimization::propertyIndex()
+{
+ return m_propertyIdx;
+}
+
+void QmlBindingIdOptimization::update()
+{
+ QmlContextPrivate *ctxtPriv =
+ static_cast<QmlContextPrivate *>(QObjectPrivate::get(context()));
+
+ if (ctxtPriv) {
+
+ if (!m_prev) {
+ m_next = ctxtPriv->idValues[m_id].bindings;
+ if (m_next) m_next->m_prev = &m_next;
+
+ m_prev = &ctxtPriv->idValues[m_id].bindings;
+ ctxtPriv->idValues[m_id].bindings = this;
+ }
+
+ QObject *o = ctxtPriv->idValues[m_id].data();
+ void *a[] = { &o, 0 };
+ QMetaObject::metacall(m_object, QMetaObject::WriteProperty,
+ m_propertyIdx, a);
+ }
+}
+
+void QmlBindingIdOptimization::reset()
+{
+ if (m_prev) {
+ *m_prev = m_next;
+ if (m_next) m_next->m_prev = m_prev;
+ m_next = 0;
+ m_prev = 0;
+ }
+
+ QObject *o = 0;
+ void *a[] = { &o, 0 };
+ QMetaObject::metacall(m_object, QMetaObject::WriteProperty,
+ m_propertyIdx, a);
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/qml/qmlbindingoptimizations_p.h b/src/declarative/qml/qmlbindingoptimizations_p.h
new file mode 100644
index 0000000..f50972d
--- /dev/null
+++ b/src/declarative/qml/qmlbindingoptimizations_p.h
@@ -0,0 +1,91 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QMLBINDINGOPTIMIZATIONS_P_H
+#define QMLBINDINGOPTIMIZATIONS_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <private/qmlexpression_p.h>
+#include <QtDeclarative/qmlbinding.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+class QmlBindingIdOptimization : public QmlAbstractExpression,
+ public QmlAbstractBinding
+{
+public:
+ QmlBindingIdOptimization(QObject *object, int propertyIdx,
+ QmlContext *context, int id);
+
+ // Inherited from QmlAbstractBinding
+ virtual void setEnabled(bool);
+ virtual int propertyIndex();
+ virtual void update();
+
+ void reset();
+
+private:
+ QmlBindingIdOptimization **m_prev;
+ QmlBindingIdOptimization *m_next;
+
+ QObject *m_object;
+ int m_propertyIdx;
+ int m_id;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QMLBINDINGOPTIMIZATIONS_P_H
+
diff --git a/src/declarative/qml/qmlcompiler.cpp b/src/declarative/qml/qmlcompiler.cpp
index 1c535d4..7c0964b 100644
--- a/src/declarative/qml/qmlcompiler.cpp
+++ b/src/declarative/qml/qmlcompiler.cpp
@@ -1394,6 +1394,7 @@ void QmlCompiler::addId(const QString &id, QmlParser::Object *obj)
Q_ASSERT(obj->id == id);
obj->idIndex = compileState.ids.count();
compileState.ids.insert(id, obj);
+ compileState.idIndexes.insert(obj->idIndex, obj);
}
void QmlCompiler::addBindingReference(const BindingReference &ref)
@@ -2064,6 +2065,22 @@ void QmlCompiler::genBindingAssignment(QmlParser::Value *binding,
const BindingReference &ref = compileState.bindings.value(binding);
QmlInstruction store;
+
+ 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);
+ if (canCoerce(prop->type, idObj)) {
+ store.type = QmlInstruction::StoreIdOptBinding;
+ store.assignIdOptBinding.id = idIndex;
+ store.assignIdOptBinding.property = prop->index;
+ output->bytecode << store;
+ return;
+ }
+ }
+
store.type = QmlInstruction::StoreCompiledBinding;
store.assignBinding.value = output->indexForByteArray(ref.compiledData);
store.assignBinding.context = ref.bindingContext.stack;
@@ -2109,6 +2126,7 @@ bool QmlCompiler::completeComponentBuild()
binding.compiledData =
QByteArray(bs.compileData(), bs.compileDataSize());
type = QmlExpressionPrivate::BasicScriptEngineData;
+ binding.isBasicScript = true;
} else {
type = QmlExpressionPrivate::PreTransformedQtScriptData;
@@ -2122,6 +2140,7 @@ bool QmlCompiler::completeComponentBuild()
QByteArray((const char *)&length, sizeof(quint32)) +
QByteArray((const char *)expression.constData(),
expression.length() * sizeof(QChar));
+ binding.isBasicScript = false;
}
binding.compiledData.prepend(QByteArray((const char *)&type,
sizeof(quint32)));
diff --git a/src/declarative/qml/qmlcompiler_p.h b/src/declarative/qml/qmlcompiler_p.h
index 094c05a..3d79e32 100644
--- a/src/declarative/qml/qmlcompiler_p.h
+++ b/src/declarative/qml/qmlcompiler_p.h
@@ -236,6 +236,7 @@ private:
QmlParser::Variant expression;
QmlParser::Property *property;
QmlParser::Value *value;
+ bool isBasicScript;
QByteArray compiledData;
BindingContext bindingContext;
};
@@ -247,6 +248,7 @@ private:
: parserStatusCount(0), savedObjects(0),
pushedProperties(0), root(0) {}
QHash<QString, QmlParser::Object *> ids;
+ QHash<int, QmlParser::Object *> idIndexes;
int parserStatusCount;
int savedObjects;
int pushedProperties;
diff --git a/src/declarative/qml/qmlcomponent.cpp b/src/declarative/qml/qmlcomponent.cpp
index d4e383d..c30efca 100644
--- a/src/declarative/qml/qmlcomponent.cpp
+++ b/src/declarative/qml/qmlcomponent.cpp
@@ -533,11 +533,11 @@ void QmlComponent::completeCreate()
QFxPerfTimer<QFxPerf::BindInit> bi;
#endif
for (int ii = 0; ii < d->bindValues.count(); ++ii) {
- QmlEnginePrivate::SimpleList<QmlBinding> bv =
+ QmlEnginePrivate::SimpleList<QmlAbstractBinding> bv =
d->bindValues.at(ii);
for (int jj = 0; jj < bv.count; ++jj) {
if(bv.at(jj))
- bv.at(jj)->init();
+ bv.at(jj)->setEnabled(true);
}
QmlEnginePrivate::clear(bv);
}
diff --git a/src/declarative/qml/qmlcomponent_p.h b/src/declarative/qml/qmlcomponent_p.h
index a7a3230..4b459c2 100644
--- a/src/declarative/qml/qmlcomponent_p.h
+++ b/src/declarative/qml/qmlcomponent_p.h
@@ -88,7 +88,7 @@ public:
int count;
QmlCompiledData *cc;
- QList<QmlEnginePrivate::SimpleList<QmlBinding> > bindValues;
+ QList<QmlEnginePrivate::SimpleList<QmlAbstractBinding> > bindValues;
QList<QmlEnginePrivate::SimpleList<QmlParserStatus> > parserStatus;
bool completePending;
diff --git a/src/declarative/qml/qmlcontext.cpp b/src/declarative/qml/qmlcontext.cpp
index 18ba906..451dbcc 100644
--- a/src/declarative/qml/qmlcontext.cpp
+++ b/src/declarative/qml/qmlcontext.cpp
@@ -47,6 +47,7 @@
#include <qscriptengine.h>
#include <QtCore/qvarlengtharray.h>
#include <QtCore/qdebug.h>
+#include <private/qmlbindingoptimizations_p.h>
// 6-bits
#define MAXIMUM_DEFAULT_OBJECTS 63
@@ -82,6 +83,9 @@ void QmlContextPrivate::destroyed(ContextGuard *guard)
if (parent && QObjectPrivate::get(parent)->wasDeleted)
return;
+ while(guard->bindings)
+ guard->bindings->reset();
+
for (int ii = 0; ii < idValueCount; ++ii) {
if (&idValues[ii] == guard) {
QMetaObject::activate(q, ii + notifyIndex, 0);
@@ -276,13 +280,13 @@ QmlContext::~QmlContext()
(*iter)->d_func()->parent = 0;
}
- QmlExpressionPrivate *expression = d->expressions;
+ QmlAbstractExpression *expression = d->expressions;
while (expression) {
- QmlExpressionPrivate *nextExpression = expression->nextExpression;
+ QmlAbstractExpression *nextExpression = expression->m_nextExpression;
- expression->ctxt = 0;
- expression->prevExpression = 0;
- expression->nextExpression = 0;
+ expression->m_context = 0;
+ expression->m_prevExpression = 0;
+ expression->m_nextExpression = 0;
expression = nextExpression;
}
diff --git a/src/declarative/qml/qmlcontext_p.h b/src/declarative/qml/qmlcontext_p.h
index 0424a85..b5479d9 100644
--- a/src/declarative/qml/qmlcontext_p.h
+++ b/src/declarative/qml/qmlcontext_p.h
@@ -68,6 +68,8 @@ class QmlExpression;
class QmlEngine;
class QmlExpression;
class QmlExpressionPrivate;
+class QmlAbstractExpression;
+class QmlBindingIdOptimization;
class QmlContextPrivate : public QObjectPrivate
{
@@ -104,13 +106,15 @@ public:
void invalidateEngines();
QSet<QmlContext *> childContexts;
- QmlExpressionPrivate *expressions;
+ QmlAbstractExpression *expressions;
QObjectList contextObjects;
struct ContextGuard : public QGuard<QObject>
{
+ ContextGuard() : priv(0), bindings(0) {}
QmlContextPrivate *priv;
+ QmlBindingIdOptimization *bindings;
ContextGuard &operator=(QObject *obj) {
(QGuard<QObject>&)*this = obj; return *this;
}
diff --git a/src/declarative/qml/qmldeclarativedata_p.h b/src/declarative/qml/qmldeclarativedata_p.h
index 8d30bcc..5a51eb7 100644
--- a/src/declarative/qml/qmldeclarativedata_p.h
+++ b/src/declarative/qml/qmldeclarativedata_p.h
@@ -58,7 +58,7 @@
QT_BEGIN_NAMESPACE
class QmlCompiledData;
-class QmlBinding;
+class QmlAbstractBinding;
class QmlDeclarativeData : public QDeclarativeData
{
public:
@@ -67,7 +67,7 @@ public:
virtual void destroyed(QObject *);
QmlContext *context;
- QmlBinding *bindings;
+ QmlAbstractBinding *bindings;
QmlCompiledData *deferredComponent; // Can't this be found from the context?
unsigned int deferredIdx;
diff --git a/src/declarative/qml/qmlengine.cpp b/src/declarative/qml/qmlengine.cpp
index 09539bc..bdbf2e7 100644
--- a/src/declarative/qml/qmlengine.cpp
+++ b/src/declarative/qml/qmlengine.cpp
@@ -121,16 +121,8 @@ QmlEnginePrivate::~QmlEnginePrivate()
clear(parserStatus[ii]);
}
-void QmlEnginePrivate::clear(SimpleList<QmlBinding> &bvs)
+void QmlEnginePrivate::clear(SimpleList<QmlAbstractBinding> &bvs)
{
- for (int ii = 0; ii < bvs.count; ++ii) {
- QmlBinding *bv = bvs.at(ii);
- if(bv) {
- QmlBindingPrivate *p =
- static_cast<QmlBindingPrivate *>(QObjectPrivate::get(bv));
- p->mePtr = 0;
- }
- }
bvs.clear();
}
@@ -522,6 +514,15 @@ void QmlDeclarativeData::destroyed(QObject *object)
if (context)
static_cast<QmlContextPrivate *>(QObjectPrivate::get(context))->contextObjects.removeAll(object);
+ QmlAbstractBinding *binding = bindings;
+ while (binding) {
+ QmlAbstractBinding *next = binding->m_nextBinding;
+ binding->m_prevBinding = 0;
+ binding->m_nextBinding = 0;
+ delete binding;
+ binding = next;
+ }
+
delete this;
}
diff --git a/src/declarative/qml/qmlengine_p.h b/src/declarative/qml/qmlengine_p.h
index 602321d..d2e3ef4 100644
--- a/src/declarative/qml/qmlengine_p.h
+++ b/src/declarative/qml/qmlengine_p.h
@@ -86,6 +86,7 @@ class QmlValueTypeScriptClass;
class QScriptEngineDebugger;
class QNetworkReply;
class QNetworkAccessManager;
+class QmlAbstractBinding;
class QmlEnginePrivate : public QObjectPrivate
{
@@ -160,10 +161,10 @@ public:
}
};
- static void clear(SimpleList<QmlBinding> &);
+ static void clear(SimpleList<QmlAbstractBinding> &);
static void clear(SimpleList<QmlParserStatus> &);
- QList<SimpleList<QmlBinding> > bindValues;
+ QList<SimpleList<QmlAbstractBinding> > bindValues;
QList<SimpleList<QmlParserStatus> > parserStatus;
QmlComponent *rootComponent;
diff --git a/src/declarative/qml/qmlenginedebug.cpp b/src/declarative/qml/qmlenginedebug.cpp
index c26f3b7..0e78cad 100644
--- a/src/declarative/qml/qmlenginedebug.cpp
+++ b/src/declarative/qml/qmlenginedebug.cpp
@@ -97,7 +97,7 @@ QmlEngineDebugServer::propertyData(QObject *obj, int propIdx)
rv.type = QmlObjectProperty::Unknown;
rv.name = prop.name();
- QmlBinding *binding = QmlMetaProperty(obj, rv.name).binding();
+ QmlAbstractBinding *binding = QmlMetaProperty(obj, rv.name).binding();
if (binding)
rv.binding = binding->expression();
diff --git a/src/declarative/qml/qmlexpression.cpp b/src/declarative/qml/qmlexpression.cpp
index 6e9a7a1..f8e78d7 100644
--- a/src/declarative/qml/qmlexpression.cpp
+++ b/src/declarative/qml/qmlexpression.cpp
@@ -51,33 +51,23 @@ Q_DECLARE_METATYPE(QList<QObject *>);
QT_BEGIN_NAMESPACE
QmlExpressionPrivate::QmlExpressionPrivate()
-: nextExpression(0), prevExpression(0), ctxt(0), expressionFunctionValid(false), expressionRewritten(false), me(0), trackChange(true), line(-1), guardList(0), guardListLength(0)
+: expressionFunctionValid(false), expressionRewritten(false), me(0),
+ trackChange(true), line(-1), guardList(0), guardListLength(0)
{
}
void QmlExpressionPrivate::init(QmlContext *ctxt, const QString &expr,
QObject *me)
{
- Q_Q(QmlExpression);
-
expression = expr;
- this->ctxt = ctxt;
- if (ctxt) {
- QmlContextPrivate *cp = ctxt->d_func();
- nextExpression = cp->expressions;
- if (nextExpression) nextExpression->prevExpression = &nextExpression;
- prevExpression = &cp->expressions;
- cp->expressions = this;
- }
+ QmlAbstractExpression::setContext(ctxt);
this->me = me;
}
void QmlExpressionPrivate::init(QmlContext *ctxt, void *expr, QmlRefCount *rc,
QObject *me)
{
- Q_Q(QmlExpression);
-
quint32 *data = (quint32 *)expr;
Q_ASSERT(*data == BasicScriptEngineData ||
*data == PreTransformedQtScriptData);
@@ -88,14 +78,7 @@ void QmlExpressionPrivate::init(QmlContext *ctxt, void *expr, QmlRefCount *rc,
expressionRewritten = true;
}
- this->ctxt = ctxt;
- if (ctxt) {
- QmlContextPrivate *cp = ctxt->d_func();
- nextExpression = cp->expressions;
- if (nextExpression) nextExpression->prevExpression = &nextExpression;
- prevExpression = &cp->expressions;
- cp->expressions = this;
- }
+ QmlAbstractExpression::setContext(ctxt);
this->me = me;
}
@@ -159,12 +142,6 @@ QmlExpression::QmlExpression(QmlContext *ctxt, const QString &expression,
*/
QmlExpression::~QmlExpression()
{
- Q_D(QmlExpression);
- if (d->prevExpression) {
- *(d->prevExpression) = d->nextExpression;
- if (d->nextExpression)
- d->nextExpression->prevExpression = d->prevExpression;
- }
}
/*!
@@ -174,7 +151,7 @@ QmlExpression::~QmlExpression()
QmlEngine *QmlExpression::engine() const
{
Q_D(const QmlExpression);
- return d->ctxt?d->ctxt->engine():0;
+ return d->context()?d->context()->engine():0;
}
/*!
@@ -184,7 +161,7 @@ QmlEngine *QmlExpression::engine() const
QmlContext *QmlExpression::context() const
{
Q_D(const QmlExpression);
- return d->ctxt;
+ return d->context();
}
/*!
@@ -230,9 +207,7 @@ QVariant QmlExpressionPrivate::evalSSE()
QFxPerfTimer<QFxPerf::BindValueSSE> perfsse;
#endif
- QmlContextPrivate *ctxtPriv = ctxt->d_func();
-
- QVariant rv = sse.run(ctxt, me);
+ QVariant rv = sse.run(context(), me);
return rv;
}
@@ -243,8 +218,8 @@ QVariant QmlExpressionPrivate::evalQtScript()
QFxPerfTimer<QFxPerf::BindValueQt> perfqt;
#endif
- QmlContextPrivate *ctxtPriv = ctxt->d_func();
- QmlEngine *engine = ctxt->engine();
+ QmlContextPrivate *ctxtPriv = context()->d_func();
+ QmlEngine *engine = context()->engine();
if (me)
ctxtPriv->defaultObjects.insert(ctxtPriv->highPriorityCount, me);
@@ -347,7 +322,7 @@ QVariant QmlExpression::value()
Q_D(QmlExpression);
QVariant rv;
- if (!d->ctxt || !engine() || (!d->sse.isValid() && d->expression.isEmpty()))
+ if (!d->context() || (!d->sse.isValid() && d->expression.isEmpty()))
return rv;
#ifdef Q_ENABLE_PERFORMANCE_LOG
@@ -574,5 +549,52 @@ void QmlExpressionPrivate::updateGuards(const QPODVector<QmlEnginePrivate::Captu
calling QmlExpression::value()) before this signal will be emitted.
*/
+QmlAbstractExpression::QmlAbstractExpression()
+: m_context(0), m_prevExpression(0), m_nextExpression(0)
+{
+}
+
+QmlAbstractExpression::~QmlAbstractExpression()
+{
+ if (m_prevExpression) {
+ *m_prevExpression = m_nextExpression;
+ if (m_nextExpression)
+ m_nextExpression->m_prevExpression = m_prevExpression;
+ }
+}
+
+QmlContext *QmlAbstractExpression::context() const
+{
+ return m_context;
+}
+
+void QmlAbstractExpression::setContext(QmlContext *context)
+{
+ if (m_prevExpression) {
+ *m_prevExpression = m_nextExpression;
+ if (m_nextExpression)
+ m_nextExpression->m_prevExpression = m_prevExpression;
+ m_prevExpression = 0;
+ m_nextExpression = 0;
+ }
+
+ m_context = context;
+
+ if (m_context) {
+ QmlContextPrivate *cp =
+ static_cast<QmlContextPrivate *>(QObjectPrivate::get(m_context));
+ m_nextExpression = cp->expressions;
+ if (m_nextExpression)
+ m_nextExpression->m_prevExpression = &m_nextExpression;
+ m_prevExpression = &cp->expressions;
+ cp->expressions = this;
+ }
+}
+
+bool QmlAbstractExpression::isValid() const
+{
+ return m_context != 0;
+}
+
QT_END_NAMESPACE
diff --git a/src/declarative/qml/qmlexpression_p.h b/src/declarative/qml/qmlexpression_p.h
index bf95c0e0..997bf8d 100644
--- a/src/declarative/qml/qmlexpression_p.h
+++ b/src/declarative/qml/qmlexpression_p.h
@@ -61,19 +61,33 @@
QT_BEGIN_NAMESPACE
+class QmlAbstractExpression
+{
+public:
+ QmlAbstractExpression();
+ virtual ~QmlAbstractExpression();
+
+ bool isValid() const;
+
+ QmlContext *context() const;
+ void setContext(QmlContext *);
+
+private:
+ friend class QmlContext;
+ QmlContext *m_context;
+ QmlAbstractExpression **m_prevExpression;
+ QmlAbstractExpression *m_nextExpression;
+};
+
class QmlExpression;
class QString;
-class QmlExpressionPrivate : public QObjectPrivate
+class QmlExpressionPrivate : public QObjectPrivate, public QmlAbstractExpression
{
Q_DECLARE_PUBLIC(QmlExpression)
public:
QmlExpressionPrivate();
~QmlExpressionPrivate();
- // Forms the QmlContext "expressions" linked list
- QmlExpressionPrivate *nextExpression;
- QmlExpressionPrivate **prevExpression;
-
enum CompiledDataType {
BasicScriptEngineData = 1,
PreTransformedQtScriptData = 2
@@ -82,7 +96,6 @@ public:
void init(QmlContext *, const QString &, QObject *);
void init(QmlContext *, void *, QmlRefCount *, QObject *);
- QmlContext *ctxt;
QString expression;
bool expressionFunctionValid:1;
bool expressionRewritten:1;
diff --git a/src/declarative/qml/qmlinstruction_p.h b/src/declarative/qml/qmlinstruction_p.h
index e6b8de6..16bc8cf 100644
--- a/src/declarative/qml/qmlinstruction_p.h
+++ b/src/declarative/qml/qmlinstruction_p.h
@@ -125,6 +125,7 @@ public:
AssignCustomType, /* assignCustomType */
StoreCompiledBinding, /* assignBinding */
+ StoreIdOptBinding, /* assignIdOptBinding */
StoreValueSource, /* assignValueSource */
BeginObject, /* begin */
@@ -189,6 +190,10 @@ public:
} assignBinding;
struct {
int property;
+ int id;
+ } assignIdOptBinding;
+ struct {
+ int property;
} fetch;
struct {
int property;
diff --git a/src/declarative/qml/qmlmetaproperty.cpp b/src/declarative/qml/qmlmetaproperty.cpp
index 64dd9cd..d986077 100644
--- a/src/declarative/qml/qmlmetaproperty.cpp
+++ b/src/declarative/qml/qmlmetaproperty.cpp
@@ -51,6 +51,7 @@
#include <QtCore/qdebug.h>
#include <QtDeclarative/qmlengine.h>
#include <private/qmlengine_p.h>
+#include <private/qmldeclarativedata_p.h>
Q_DECLARE_METATYPE(QList<QObject *>);
@@ -509,20 +510,21 @@ QMetaProperty QmlMetaProperty::property() const
Returns the binding associated with this property, or 0 if no binding
exists.
*/
-QmlBinding *QmlMetaProperty::binding() const
+QmlAbstractBinding *QmlMetaProperty::binding() const
{
if (!isProperty() || (type() & Attached) || !d->object)
return 0;
- const QObjectList &children = object()->children();
- for (QObjectList::ConstIterator iter = children.begin();
- iter != children.end(); ++iter) {
- QObject *child = *iter;
- if (child->metaObject() == &QmlBinding::staticMetaObject) {
- QmlBinding *v = static_cast<QmlBinding *>(child);
- if (v->property() == *this && v->enabled())
- return v;
- }
+ QmlDeclarativeData *data = QmlDeclarativeData::get(d->object);
+ if (!data)
+ return 0;
+
+ QmlAbstractBinding *binding = data->bindings;
+ while (binding) {
+ // ### This wont work for value types
+ if (binding->propertyIndex() == d->coreIdx)
+ return binding;
+ binding = binding->m_nextBinding;
}
return 0;
}
@@ -534,41 +536,32 @@ QmlBinding *QmlMetaProperty::binding() const
\a binding will be enabled, and the returned binding (if any) will be
disabled.
*/
-QmlBinding *QmlMetaProperty::setBinding(QmlBinding *binding) const
+QmlAbstractBinding *
+QmlMetaProperty::setBinding(QmlAbstractBinding *newBinding) const
{
if (!isProperty() || (type() & Attached) || !d->object)
return 0;
- const QObjectList &children = object()->children();
- for (QObjectList::ConstIterator iter = children.begin();
- iter != children.end(); ++iter) {
- QObject *child = *iter;
- if (child->metaObject() == &QmlBinding::staticMetaObject) {
- QmlBinding *v = static_cast<QmlBinding *>(child);
- if (v->property() == *this && v->enabled()) {
-
- v->setEnabled(false);
-
- if (binding) {
- binding->setParent(object());
- binding->setTarget(*this);
- binding->setEnabled(true);
- binding->forceUpdate();
- }
+ QmlDeclarativeData *data = QmlDeclarativeData::get(d->object, true);
- return v;
+ QmlAbstractBinding *binding = data->bindings;
+ while (binding) {
+ // ### This wont work for value types
+ if (binding->propertyIndex() == d->coreIdx) {
+ binding->setEnabled(false);
- }
+ if (newBinding)
+ newBinding->setEnabled(true);
+
+ return binding; // ### QmlAbstractBinding;
}
- }
- if (binding) {
- binding->setParent(object());
- binding->setTarget(*this);
- binding->setEnabled(true);
- binding->forceUpdate();
+ binding = binding->m_nextBinding;
}
+ if (newBinding)
+ newBinding->setEnabled(true);
+
return 0;
}
diff --git a/src/declarative/qml/qmlmetaproperty.h b/src/declarative/qml/qmlmetaproperty.h
index 434ff55..7b9ff47 100644
--- a/src/declarative/qml/qmlmetaproperty.h
+++ b/src/declarative/qml/qmlmetaproperty.h
@@ -52,7 +52,7 @@ QT_BEGIN_NAMESPACE
QT_MODULE(Declarative)
class QObject;
-class QmlBinding;
+class QmlAbstractBinding;
class QStringList;
class QVariant;
struct QMetaObject;
@@ -122,8 +122,8 @@ public:
QMetaProperty property() const;
- QmlBinding *binding() const;
- QmlBinding *setBinding(QmlBinding *) const;
+ QmlAbstractBinding *binding() const;
+ QmlAbstractBinding *setBinding(QmlAbstractBinding *) const;
static QmlMetaProperty createProperty(QObject *, const QString &);
diff --git a/src/declarative/qml/qmlvme.cpp b/src/declarative/qml/qmlvme.cpp
index ffe8591..dccf5c4 100644
--- a/src/declarative/qml/qmlvme.cpp
+++ b/src/declarative/qml/qmlvme.cpp
@@ -65,6 +65,7 @@
#include <QtCore/qvarlengtharray.h>
#include <private/qmlbinding_p.h>
#include <private/qmlcontext_p.h>
+#include <private/qmlbindingoptimizations_p.h>
QT_BEGIN_NAMESPACE
@@ -138,7 +139,7 @@ QObject *QmlVME::run(QStack<QObject *> &stack, QmlContext *ctxt, QmlCompiledData
const QList<float> &floatData = comp->floatData;
- QmlEnginePrivate::SimpleList<QmlBinding> bindValues;
+ QmlEnginePrivate::SimpleList<QmlAbstractBinding> bindValues;
QmlEnginePrivate::SimpleList<QmlParserStatus> parserStatus;
QStack<ListInstance> qliststack;
@@ -154,7 +155,7 @@ QObject *QmlVME::run(QStack<QObject *> &stack, QmlContext *ctxt, QmlCompiledData
case QmlInstruction::Init:
{
if (instr.init.bindingsSize)
- bindValues = QmlEnginePrivate::SimpleList<QmlBinding>(instr.init.bindingsSize);
+ bindValues = QmlEnginePrivate::SimpleList<QmlAbstractBinding>(instr.init.bindingsSize);
if (instr.init.parserStatusSize)
parserStatus = QmlEnginePrivate::SimpleList<QmlParserStatus>(instr.init.parserStatusSize);
@@ -543,12 +544,24 @@ QObject *QmlVME::run(QStack<QObject *> &stack, QmlContext *ctxt, QmlCompiledData
QmlBindingPrivate *p =
static_cast<QmlBindingPrivate *>(QObjectPrivate::get(bind));
p->mePtr = &bindValues.values[bindValues.count - 1];
- QFx_setParent_noEvent(bind, target);
+ bind->addToObject(target);
bind->setTarget(mp);
}
break;
+ case QmlInstruction::StoreIdOptBinding:
+ {
+ QObject *target = stack.top();
+
+ QmlBindingIdOptimization *bind =
+ new QmlBindingIdOptimization(target, instr.assignIdOptBinding.property, ctxt, instr.assignIdOptBinding.id);
+ bindValues.append(bind);
+ // ### Need a mePtr
+ bind->addToObject(target);
+ }
+ break;
+
case QmlInstruction::StoreValueSource:
{
QmlPropertyValueSource *vs =
diff --git a/src/declarative/util/qmlsetproperties.cpp b/src/declarative/util/qmlsetproperties.cpp
index 1cd4a79..482405c 100644
--- a/src/declarative/util/qmlsetproperties.cpp
+++ b/src/declarative/util/qmlsetproperties.cpp
@@ -334,9 +334,10 @@ QmlSetProperties::ActionList QmlSetProperties::actions()
if (d->isExplicit) {
a.toValue = d->expressions.at(ii).second->value();
} else {
- a.toBinding = new QmlBinding(d->expressions.at(ii).second->expression(), object(), qmlContext(this));
+ QmlBinding *newBinding = new QmlBinding(d->expressions.at(ii).second->expression(), object(), qmlContext(this));
+ newBinding->setTarget(prop);
+ a.toBinding = newBinding;
a.deletableToBinding = true;
- a.toBinding->setTarget(prop);
}
list << a;
diff --git a/src/declarative/util/qmlstate.h b/src/declarative/util/qmlstate.h
index 9eb7aee..46659c6 100644
--- a/src/declarative/util/qmlstate.h
+++ b/src/declarative/util/qmlstate.h
@@ -70,8 +70,8 @@ public:
QVariant fromValue;
QVariant toValue;
- QmlBinding *fromBinding;
- QmlBinding *toBinding;
+ QmlAbstractBinding *fromBinding;
+ QmlAbstractBinding *toBinding;
ActionEvent *event;
//strictly for matching
diff --git a/src/declarative/util/qmlstate_p.h b/src/declarative/util/qmlstate_p.h
index b601b57..63fc6da 100644
--- a/src/declarative/util/qmlstate_p.h
+++ b/src/declarative/util/qmlstate_p.h
@@ -83,7 +83,7 @@ public:
QmlMetaProperty property;
QVariant value;
- QmlBinding *binding;
+ QmlAbstractBinding *binding;
QObject *specifiedObject;
QString specifiedProperty;
ActionEvent *event;
diff --git a/src/declarative/util/qmltransitionmanager.cpp b/src/declarative/util/qmltransitionmanager.cpp
index f04a821..3e2e05f 100644
--- a/src/declarative/util/qmltransitionmanager.cpp
+++ b/src/declarative/util/qmltransitionmanager.cpp
@@ -94,7 +94,6 @@ void QmlTransitionManagerPrivate::applyBindings()
foreach(const Action &action, bindingsList) {
if (action.toBinding) {
action.property.setBinding(action.toBinding);
- action.toBinding->forceUpdate();
} else if (action.event) {
if (action.reverseEvent)
action.event->reverse();
@@ -146,7 +145,6 @@ void QmlTransitionManager::transition(const QList<Action> &list,
const Action &action = applyList.at(ii);
if (action.toBinding) {
action.property.setBinding(action.toBinding);
- action.toBinding->forceUpdate();
} else if (!action.event) {
action.property.write(action.toValue);
} else if (action.event->isReversable()) {