diff options
author | Michael Brasser <michael.brasser@nokia.com> | 2010-12-15 02:08:13 (GMT) |
---|---|---|
committer | Michael Brasser <michael.brasser@nokia.com> | 2010-12-17 06:35:17 (GMT) |
commit | 488e616b50707e5b37162e6d0cfc71a1ffdf9bef (patch) | |
tree | 86b02b1665e7dcc29aed479c9ed2ce7d6f5ba214 | |
parent | 139ecc0e74af2795faa55cfd532aeb10c631049e (diff) | |
download | Qt-488e616b50707e5b37162e6d0cfc71a1ffdf9bef.zip Qt-488e616b50707e5b37162e6d0cfc71a1ffdf9bef.tar.gz Qt-488e616b50707e5b37162e6d0cfc71a1ffdf9bef.tar.bz2 |
Rewrite/cache bindings created by PropertyChanges.
This provides a significant optimization for initial evaluation of
bindings specified in a PropertyChanges.
Reviewed-by: Aaron Kennedy
-rw-r--r-- | src/declarative/qml/qdeclarativebinding.cpp | 14 | ||||
-rw-r--r-- | src/declarative/qml/qdeclarativebinding_p.h | 3 | ||||
-rw-r--r-- | src/declarative/qml/qdeclarativecompiler.cpp | 29 | ||||
-rw-r--r-- | src/declarative/qml/qdeclarativecompiler_p.h | 1 | ||||
-rw-r--r-- | src/declarative/qml/qdeclarativecontext_p.h | 1 | ||||
-rw-r--r-- | src/declarative/qml/qdeclarativecustomparser.cpp | 9 | ||||
-rw-r--r-- | src/declarative/qml/qdeclarativecustomparser_p.h | 3 | ||||
-rw-r--r-- | src/declarative/util/qdeclarativepropertychanges.cpp | 26 |
8 files changed, 82 insertions, 4 deletions
diff --git a/src/declarative/qml/qdeclarativebinding.cpp b/src/declarative/qml/qdeclarativebinding.cpp index 309d372..1ead6ce 100644 --- a/src/declarative/qml/qdeclarativebinding.cpp +++ b/src/declarative/qml/qdeclarativebinding.cpp @@ -46,6 +46,7 @@ #include "qdeclarativecontext.h" #include "qdeclarativeinfo.h" #include "private/qdeclarativecontext_p.h" +#include "private/qdeclarativecompiler_p.h" #include "private/qdeclarativedata_p.h" #include "private/qdeclarativestringconverters_p.h" #include "private/qdeclarativestate_p_p.h" @@ -233,6 +234,19 @@ QDeclarativeBinding::QDeclarativeBinding(void *data, QDeclarativeRefCount *rc, Q setNotifyOnValueChanged(true); } +QDeclarativeBinding * +QDeclarativeBinding::createBinding(Identifier id, QObject *obj, QDeclarativeContext *ctxt, + const QString &url, int lineNumber, QObject *parent) +{ + QDeclarativeContextData *ctxtdata = QDeclarativeContextData::get(ctxt); + + QDeclarativeEnginePrivate *engine = QDeclarativeEnginePrivate::get(qmlEngine(obj)); + QDeclarativeCompiledData *cdata = 0; + if (engine && ctxtdata && !ctxtdata->url.isEmpty()) + cdata = engine->typeLoader.get(ctxtdata->url)->compiledData(); + return cdata ? new QDeclarativeBinding((void*)cdata->datas.at(id).constData(), cdata, obj, ctxtdata, url, lineNumber, parent) : 0; +} + QDeclarativeBinding::QDeclarativeBinding(const QString &str, QObject *obj, QDeclarativeContext *ctxt, QObject *parent) : QDeclarativeExpression(QDeclarativeContextData::get(ctxt), obj, str, *new QDeclarativeBindingPrivate) diff --git a/src/declarative/qml/qdeclarativebinding_p.h b/src/declarative/qml/qdeclarativebinding_p.h index 7823a3d..787a3b9 100644 --- a/src/declarative/qml/qdeclarativebinding_p.h +++ b/src/declarative/qml/qdeclarativebinding_p.h @@ -162,6 +162,9 @@ public: virtual void update(QDeclarativePropertyPrivate::WriteFlags flags); virtual QString expression() const; + typedef int Identifier; + static QDeclarativeBinding *createBinding(Identifier, QObject *, QDeclarativeContext *, const QString &, int, QObject *parent=0); + public Q_SLOTS: void update() { update(QDeclarativePropertyPrivate::DontRemoveBinding); } diff --git a/src/declarative/qml/qdeclarativecompiler.cpp b/src/declarative/qml/qdeclarativecompiler.cpp index 4749bf8..4f4ad3f 100644 --- a/src/declarative/qml/qdeclarativecompiler.cpp +++ b/src/declarative/qml/qdeclarativecompiler.cpp @@ -2262,6 +2262,35 @@ const QMetaObject *QDeclarativeCompiler::resolveType(const QByteArray& name) con return qmltype->metaObject(); } +// similar to logic of completeComponentBuild, but also sticks data +// into datas at the end +int QDeclarativeCompiler::rewriteBinding(const QString& expression, const QByteArray& name) +{ + QDeclarativeRewrite::RewriteBinding rewriteBinding; + rewriteBinding.setName('$' + name); + bool isSharable = false; + QString rewrite = rewriteBinding(expression, 0, &isSharable); + + quint32 length = rewrite.length(); + quint32 pc; + + if (isSharable) { + pc = output->cachedClosures.count(); + pc |= 0x80000000; + output->cachedClosures.append(0); + } else { + pc = output->cachedPrograms.length(); + output->cachedPrograms.append(0); + } + + QByteArray compiledData = + QByteArray((const char *)&pc, sizeof(quint32)) + + QByteArray((const char *)&length, sizeof(quint32)) + + QByteArray((const char *)rewrite.constData(), + rewrite.length() * sizeof(QChar)); + + return output->indexForByteArray(compiledData); +} // Ensures that the dynamic meta specification on obj is valid bool QDeclarativeCompiler::checkDynamicMeta(QDeclarativeParser::Object *obj) diff --git a/src/declarative/qml/qdeclarativecompiler_p.h b/src/declarative/qml/qdeclarativecompiler_p.h index 7d76ad9..bface8f 100644 --- a/src/declarative/qml/qdeclarativecompiler_p.h +++ b/src/declarative/qml/qdeclarativecompiler_p.h @@ -161,6 +161,7 @@ public: int evaluateEnum(const QByteArray& script) const; // for QDeclarativeCustomParser::evaluateEnum const QMetaObject *resolveType(const QByteArray& name) const; // for QDeclarativeCustomParser::resolveType + int rewriteBinding(const QString& expression, const QByteArray& name); // for QDeclarativeCustomParser::rewriteBinding private: static void reset(QDeclarativeCompiledData *); diff --git a/src/declarative/qml/qdeclarativecontext_p.h b/src/declarative/qml/qdeclarativecontext_p.h index 6c14feb..6b71381 100644 --- a/src/declarative/qml/qdeclarativecontext_p.h +++ b/src/declarative/qml/qdeclarativecontext_p.h @@ -77,7 +77,6 @@ class QDeclarativeEngine; class QDeclarativeExpression; class QDeclarativeExpressionPrivate; class QDeclarativeAbstractExpression; -class QDeclarativeBinding_Id; class QDeclarativeCompiledBindings; class QDeclarativeContextData; diff --git a/src/declarative/qml/qdeclarativecustomparser.cpp b/src/declarative/qml/qdeclarativecustomparser.cpp index 97a6a00..58ffc56 100644 --- a/src/declarative/qml/qdeclarativecustomparser.cpp +++ b/src/declarative/qml/qdeclarativecustomparser.cpp @@ -304,5 +304,14 @@ const QMetaObject *QDeclarativeCustomParser::resolveType(const QByteArray& name) return compiler->resolveType(name); } +/*! + Rewrites \a expression and returns an identifier that can be + used to construct the binding later. \a name + is used as the name of the rewritten function. +*/ +QDeclarativeBinding::Identifier QDeclarativeCustomParser::rewriteBinding(const QString& expression, const QByteArray& name) +{ + return compiler->rewriteBinding(expression, name); +} QT_END_NAMESPACE diff --git a/src/declarative/qml/qdeclarativecustomparser_p.h b/src/declarative/qml/qdeclarativecustomparser_p.h index c3f9dd2..9b419c2 100644 --- a/src/declarative/qml/qdeclarativecustomparser_p.h +++ b/src/declarative/qml/qdeclarativecustomparser_p.h @@ -56,6 +56,7 @@ #include "private/qdeclarativemetatype_p.h" #include "qdeclarativeerror.h" #include "private/qdeclarativeparser_p.h" +#include "private/qdeclarativebinding_p.h" #include <QtCore/qbytearray.h> #include <QtCore/qxmlstream.h> @@ -140,6 +141,8 @@ protected: const QMetaObject *resolveType(const QByteArray&) const; + QDeclarativeBinding::Identifier rewriteBinding(const QString&, const QByteArray&); + private: QList<QDeclarativeError> exceptions; QDeclarativeCompiler *compiler; diff --git a/src/declarative/util/qdeclarativepropertychanges.cpp b/src/declarative/util/qdeclarativepropertychanges.cpp index 8d01b80..400803e 100644 --- a/src/declarative/util/qdeclarativepropertychanges.cpp +++ b/src/declarative/util/qdeclarativepropertychanges.cpp @@ -42,6 +42,9 @@ #include "private/qdeclarativepropertychanges_p.h" #include "private/qdeclarativeopenmetaobject_p.h" +#include "private/qdeclarativerewrite_p.h" +#include "private/qdeclarativeengine_p.h" +#include "private/qdeclarativecompiler_p.h" #include <qdeclarativeinfo.h> #include <qdeclarativecustomparser_p.h> @@ -219,6 +222,7 @@ public: QList<QPair<QByteArray, QVariant> > properties; QList<QPair<QByteArray, QDeclarativeExpression *> > expressions; + QList<QDeclarativeBinding::Identifier> ids; QList<QDeclarativeReplaceSignalHandler*> signalReplacements; QDeclarativeProperty property(const QByteArray &); @@ -267,6 +271,7 @@ QDeclarativePropertyChangesParser::compile(const QList<QDeclarativeCustomParserP QDeclarativeParser::Variant v = qvariant_cast<QDeclarativeParser::Variant>(data.at(ii).second); QVariant var; bool isScript = v.isScript(); + QDeclarativeBinding::Identifier id; switch(v.type()) { case QDeclarativeParser::Variant::Boolean: var = QVariant(v.asBoolean()); @@ -280,10 +285,17 @@ QDeclarativePropertyChangesParser::compile(const QList<QDeclarativeCustomParserP case QDeclarativeParser::Variant::Invalid: case QDeclarativeParser::Variant::Script: var = QVariant(v.asScript()); + { + // Pre-rewrite the expression + QString expression = v.asScript(); + id = rewriteBinding(expression, data.at(ii).first); //### recreates the AST, which is slow + } break; } ds << data.at(ii).first << isScript << var; + if (isScript) + ds << id; } return rv; @@ -303,9 +315,12 @@ void QDeclarativePropertyChangesPrivate::decode() QByteArray name; bool isScript; QVariant data; + QDeclarativeBinding::Identifier id; ds >> name; ds >> isScript; ds >> data; + if (isScript) + ds >> id; QDeclarativeProperty prop = property(name); //### better way to check for signal property? if (prop.type() & QDeclarativeProperty::SignalProperty) { @@ -323,6 +338,7 @@ void QDeclarativePropertyChangesPrivate::decode() if (ddata && ddata->outerContext && !ddata->outerContext->url.isEmpty()) expression->setSourceLocation(ddata->outerContext->url.toString(), ddata->lineNumber); expressions << qMakePair(name, expression); + ids << id; } else { properties << qMakePair(name, data); } @@ -452,10 +468,14 @@ QDeclarativePropertyChanges::ActionList QDeclarativePropertyChanges::actions() a.toValue = d->expressions.at(ii).second->evaluate(); } else { QDeclarativeExpression *e = d->expressions.at(ii).second; - QDeclarativeBinding *newBinding = - new QDeclarativeBinding(e->expression(), object(), qmlContext(this)); + + QDeclarativeBinding::Identifier id = d->ids.at(ii); + QDeclarativeBinding *newBinding = QDeclarativeBinding::createBinding(id, object(), qmlContext(this), e->sourceFile(), e->lineNumber()); + if (!newBinding) { + newBinding = new QDeclarativeBinding(e->expression(), object(), qmlContext(this)); + newBinding->setSourceLocation(e->sourceFile(), e->lineNumber()); + } newBinding->setTarget(prop); - newBinding->setSourceLocation(e->sourceFile(), e->lineNumber()); a.toBinding = newBinding; a.deletableToBinding = true; } |