From 8c3405bbf65826f0ab0be0bd090d723f8efaa3af Mon Sep 17 00:00:00 2001 From: Aaron Kennedy Date: Mon, 10 Aug 2009 15:37:19 +1000 Subject: 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. --- src/declarative/qml/qml.pri | 6 +- src/declarative/qml/qmlbasicscript.cpp | 17 ++++ src/declarative/qml/qmlbasicscript_p.h | 3 + src/declarative/qml/qmlbinding.cpp | 82 +++++++++++++----- src/declarative/qml/qmlbinding.h | 36 ++++++-- src/declarative/qml/qmlbinding_p.h | 3 +- src/declarative/qml/qmlbindingoptimizations.cpp | 109 ++++++++++++++++++++++++ src/declarative/qml/qmlbindingoptimizations_p.h | 91 ++++++++++++++++++++ src/declarative/qml/qmlcompiler.cpp | 19 +++++ src/declarative/qml/qmlcompiler_p.h | 2 + src/declarative/qml/qmlcomponent.cpp | 4 +- src/declarative/qml/qmlcomponent_p.h | 2 +- src/declarative/qml/qmlcontext.cpp | 14 +-- src/declarative/qml/qmlcontext_p.h | 6 +- src/declarative/qml/qmldeclarativedata_p.h | 4 +- src/declarative/qml/qmlengine.cpp | 19 +++-- src/declarative/qml/qmlengine_p.h | 5 +- src/declarative/qml/qmlenginedebug.cpp | 2 +- src/declarative/qml/qmlexpression.cpp | 92 ++++++++++++-------- src/declarative/qml/qmlexpression_p.h | 25 ++++-- src/declarative/qml/qmlinstruction_p.h | 5 ++ src/declarative/qml/qmlmetaproperty.cpp | 63 ++++++-------- src/declarative/qml/qmlmetaproperty.h | 6 +- src/declarative/qml/qmlvme.cpp | 19 ++++- src/declarative/util/qmlsetproperties.cpp | 5 +- src/declarative/util/qmlstate.h | 4 +- src/declarative/util/qmlstate_p.h | 2 +- src/declarative/util/qmltransitionmanager.cpp | 2 - 28 files changed, 505 insertions(+), 142 deletions(-) create mode 100644 src/declarative/qml/qmlbindingoptimizations.cpp create mode 100644 src/declarative/qml/qmlbindingoptimizations_p.h 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 #include #include +#include +#include Q_DECLARE_METATYPE(QList); @@ -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 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(""); +} + 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 + +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(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 +#include + +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 ids; + QHash 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 bi; #endif for (int ii = 0; ii < d->bindValues.count(); ++ii) { - QmlEnginePrivate::SimpleList bv = + QmlEnginePrivate::SimpleList 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 > bindValues; + QList > bindValues; QList > 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 #include #include +#include // 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 childContexts; - QmlExpressionPrivate *expressions; + QmlAbstractExpression *expressions; QObjectList contextObjects; struct ContextGuard : public QGuard { + ContextGuard() : priv(0), bindings(0) {} QmlContextPrivate *priv; + QmlBindingIdOptimization *bindings; ContextGuard &operator=(QObject *obj) { (QGuard&)*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 &bvs) +void QmlEnginePrivate::clear(SimpleList &bvs) { - for (int ii = 0; ii < bvs.count; ++ii) { - QmlBinding *bv = bvs.at(ii); - if(bv) { - QmlBindingPrivate *p = - static_cast(QObjectPrivate::get(bv)); - p->mePtr = 0; - } - } bvs.clear(); } @@ -522,6 +514,15 @@ void QmlDeclarativeData::destroyed(QObject *object) if (context) static_cast(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 &); + static void clear(SimpleList &); static void clear(SimpleList &); - QList > bindValues; + QList > bindValues; QList > 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); 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 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 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 QPODVectorm_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(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 #include #include +#include Q_DECLARE_METATYPE(QList); @@ -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(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(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 #include #include +#include QT_BEGIN_NAMESPACE @@ -138,7 +139,7 @@ QObject *QmlVME::run(QStack &stack, QmlContext *ctxt, QmlCompiledData const QList &floatData = comp->floatData; - QmlEnginePrivate::SimpleList bindValues; + QmlEnginePrivate::SimpleList bindValues; QmlEnginePrivate::SimpleList parserStatus; QStack qliststack; @@ -154,7 +155,7 @@ QObject *QmlVME::run(QStack &stack, QmlContext *ctxt, QmlCompiledData case QmlInstruction::Init: { if (instr.init.bindingsSize) - bindValues = QmlEnginePrivate::SimpleList(instr.init.bindingsSize); + bindValues = QmlEnginePrivate::SimpleList(instr.init.bindingsSize); if (instr.init.parserStatusSize) parserStatus = QmlEnginePrivate::SimpleList(instr.init.parserStatusSize); @@ -543,12 +544,24 @@ QObject *QmlVME::run(QStack &stack, QmlContext *ctxt, QmlCompiledData QmlBindingPrivate *p = static_cast(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 &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()) { -- cgit v0.12