diff options
author | Michael Brasser <michael.brasser@nokia.com> | 2011-06-08 13:18:35 +1000 |
---|---|---|
committer | Michael Brasser <michael.brasser@nokia.com> | 2011-06-09 10:10:09 +1000 |
commit | ccf706d0bb2d9f70f5a8c18e4aab8ee7e6369817 (patch) | |
tree | 7019d21c843ad3c4e02fdff38d81615b56f56ee0 | |
parent | b8154d2b6b1a6c0145a099554c9166b4d35630fe (diff) |
Optimized QDeclarativeScriptString constructor for QDeclarativeExpression.
When the compiler sees a script string, it will attempt to rewrite it
and store the id for the rewrite in the script string. We can then
create a QDeclarativeExpression using the id, which saves us a rewrite
at runtime.
Reviewed-by: Aaron Kennedy
-rw-r--r-- | doc/src/declarative/whatsnew.qdoc | 3 | ||||
-rw-r--r-- | src/declarative/qml/qdeclarativecompiler.cpp | 6 | ||||
-rw-r--r-- | src/declarative/qml/qdeclarativeexpression.cpp | 53 | ||||
-rw-r--r-- | src/declarative/qml/qdeclarativeexpression.h | 2 | ||||
-rw-r--r-- | src/declarative/qml/qdeclarativeinstruction.cpp | 2 | ||||
-rw-r--r-- | src/declarative/qml/qdeclarativeinstruction_p.h | 2 | ||||
-rw-r--r-- | src/declarative/qml/qdeclarativescriptstring.cpp | 15 | ||||
-rw-r--r-- | src/declarative/qml/qdeclarativescriptstring.h | 3 | ||||
-rw-r--r-- | src/declarative/qml/qdeclarativescriptstring_p.h | 63 | ||||
-rw-r--r-- | src/declarative/qml/qdeclarativevme.cpp | 3 | ||||
-rw-r--r-- | src/declarative/qml/qml.pri | 1 | ||||
-rw-r--r-- | tests/auto/declarative/qdeclarativeexpression/data/scriptString.qml | 9 | ||||
-rw-r--r-- | tests/auto/declarative/qdeclarativeexpression/qdeclarativeexpression.pro | 17 | ||||
-rw-r--r-- | tests/auto/declarative/qdeclarativeexpression/tst_qdeclarativeexpression.cpp | 115 |
14 files changed, 279 insertions, 15 deletions
diff --git a/doc/src/declarative/whatsnew.qdoc b/doc/src/declarative/whatsnew.qdoc index bcf27e1a40..2ce16eea40 100644 --- a/doc/src/declarative/whatsnew.qdoc +++ b/doc/src/declarative/whatsnew.qdoc @@ -40,6 +40,9 @@ You can still ignore these events in the handler to let them pass through. The Binding element now restores any previously set binding when its \e when clause becomes false. +QDeclarativeExpression can now be directly (and more efficiently) constructed from a +QDeclarativeScriptString. + \section1 Qt 4.7.4 includes QtQuick 1.1 QtQuick 1.1 is a minor feature update. \e {import QtQuick 1.1} to use the new diff --git a/src/declarative/qml/qdeclarativecompiler.cpp b/src/declarative/qml/qdeclarativecompiler.cpp index e66a3fe792..72010c0ef2 100644 --- a/src/declarative/qml/qdeclarativecompiler.cpp +++ b/src/declarative/qml/qdeclarativecompiler.cpp @@ -1012,12 +1012,14 @@ void QDeclarativeCompiler::genObjectBody(QDeclarativeParser::Object *obj) { typedef QPair<Property *, int> PropPair; foreach(const PropPair &prop, obj->scriptStringProperties) { + const QString &script = prop.first->values.at(0)->value.asScript(); QDeclarativeInstruction ss; ss.setType(QDeclarativeInstruction::StoreScriptString); ss.storeScriptString.propertyIndex = prop.first->index; - ss.storeScriptString.value = - output->indexForString(prop.first->values.at(0)->value.asScript()); + ss.storeScriptString.value = output->indexForString(script); ss.storeScriptString.scope = prop.second; + ss.storeScriptString.bindingId = rewriteBinding(script, prop.first->name); + ss.storeScriptString.line = prop.first->location.start.line; output->addInstruction(ss); } diff --git a/src/declarative/qml/qdeclarativeexpression.cpp b/src/declarative/qml/qdeclarativeexpression.cpp index 247bde9a6c..8079cf3eea 100644 --- a/src/declarative/qml/qdeclarativeexpression.cpp +++ b/src/declarative/qml/qdeclarativeexpression.cpp @@ -45,6 +45,7 @@ #include "private/qdeclarativeengine_p.h" #include "private/qdeclarativecontext_p.h" #include "private/qdeclarativerewrite_p.h" +#include "private/qdeclarativescriptstring_p.h" #include "private/qdeclarativecompiler_p.h" #include "private/qdeclarativeglobalscriptclass_p.h" @@ -271,6 +272,58 @@ QDeclarativeExpression::QDeclarativeExpression(QDeclarativeContextData *ctxt, vo /*! Create a QDeclarativeExpression object that is a child of \a parent. + The \script provides the expression to be evaluated, the context to evaluate it in, + and the scope object to evaluate it with. + + This constructor is functionally equivalent to the following, but in most cases + is more efficient. + \code + QDeclarativeExpression expression(script.context(), script.scopeObject(), script.script(), parent); + \endcode + + \sa QDeclarativeScriptString +*/ +QDeclarativeExpression::QDeclarativeExpression(const QDeclarativeScriptString &script, QObject *parent) +: QObject(*new QDeclarativeExpressionPrivate, parent) +{ + Q_D(QDeclarativeExpression); + bool defaultConstruction = false; + + int id = script.d.data()->bindingId; + if (id < 0) { + defaultConstruction = true; + } else { + QDeclarativeContextData *ctxtdata = QDeclarativeContextData::get(script.context()); + + QDeclarativeEnginePrivate *engine = QDeclarativeEnginePrivate::get(qmlEngine(script.scopeObject())); + QDeclarativeCompiledData *cdata = 0; + QDeclarativeTypeData *typeData = 0; + if (engine && ctxtdata && !ctxtdata->url.isEmpty()) { + typeData = engine->typeLoader.get(ctxtdata->url); + cdata = typeData->compiledData(); + } + + if (cdata) + d->init(ctxtdata, (void*)cdata->datas.at(id).constData(), cdata, script.scopeObject(), + cdata->name, script.d.data()->lineNumber); + else + defaultConstruction = true; + + if (typeData) + typeData->release(); + } + + if (defaultConstruction) + d->init(QDeclarativeContextData::get(script.context()), script.script(), script.scopeObject()); + + if (QDeclarativeExpression_notifyIdx == -1) + QDeclarativeExpression_notifyIdx = QDeclarativeExpression::staticMetaObject.indexOfMethod("_q_notify()"); + d->setNotifyObject(this, QDeclarativeExpression_notifyIdx); +} + +/*! + Create a QDeclarativeExpression object that is a child of \a parent. + The \a expression JavaScript will be executed in the \a ctxt QDeclarativeContext. If specified, the \a scope object's properties will also be in scope during the expression's execution. diff --git a/src/declarative/qml/qdeclarativeexpression.h b/src/declarative/qml/qdeclarativeexpression.h index fef97de2b2..b76205c82e 100644 --- a/src/declarative/qml/qdeclarativeexpression.h +++ b/src/declarative/qml/qdeclarativeexpression.h @@ -43,6 +43,7 @@ #define QDECLARATIVEEXPRESSION_H #include <QtDeclarative/qdeclarativeerror.h> +#include <QtDeclarative/qdeclarativescriptstring.h> #include <QtCore/qobject.h> #include <QtCore/qvariant.h> @@ -66,6 +67,7 @@ class Q_DECLARATIVE_EXPORT QDeclarativeExpression : public QObject public: QDeclarativeExpression(); QDeclarativeExpression(QDeclarativeContext *, QObject *, const QString &, QObject * = 0); + explicit QDeclarativeExpression(const QDeclarativeScriptString &, QObject * = 0); virtual ~QDeclarativeExpression(); QDeclarativeEngine *engine() const; diff --git a/src/declarative/qml/qdeclarativeinstruction.cpp b/src/declarative/qml/qdeclarativeinstruction.cpp index fa0d8ea6f4..79a2a1cc34 100644 --- a/src/declarative/qml/qdeclarativeinstruction.cpp +++ b/src/declarative/qml/qdeclarativeinstruction.cpp @@ -160,7 +160,7 @@ void QDeclarativeCompiledData::dump(QDeclarativeInstruction *instr, int idx) qWarning().nospace() << idx << "\t\t" << "STORE_IMPORTED_SCRIPT\t" << instr->storeScript.value; break; case QDeclarativeInstruction::StoreScriptString: - qWarning().nospace() << idx << "\t\t" << "STORE_SCRIPT_STRING\t" << instr->storeScriptString.propertyIndex << "\t" << instr->storeScriptString.value << "\t" << instr->storeScriptString.scope; + qWarning().nospace() << idx << "\t\t" << "STORE_SCRIPT_STRING\t" << instr->storeScriptString.propertyIndex << "\t" << instr->storeScriptString.value << "\t" << instr->storeScriptString.scope << "\t" << instr->storeScriptString.bindingId; break; case QDeclarativeInstruction::AssignSignalObject: qWarning().nospace() << idx << "\t\t" << "ASSIGN_SIGNAL_OBJECT\t" << instr->assignSignalObject.signal << "\t\t\t" << datas.at(instr->assignSignalObject.signal); diff --git a/src/declarative/qml/qdeclarativeinstruction_p.h b/src/declarative/qml/qdeclarativeinstruction_p.h index d040967882..3db55a66d3 100644 --- a/src/declarative/qml/qdeclarativeinstruction_p.h +++ b/src/declarative/qml/qdeclarativeinstruction_p.h @@ -245,6 +245,8 @@ union QDeclarativeInstruction int propertyIndex; int value; int scope; + int bindingId; + ushort line; }; struct instr_storeScript { QML_INSTR_HEADER diff --git a/src/declarative/qml/qdeclarativescriptstring.cpp b/src/declarative/qml/qdeclarativescriptstring.cpp index f544393b9b..02d6e5603e 100644 --- a/src/declarative/qml/qdeclarativescriptstring.cpp +++ b/src/declarative/qml/qdeclarativescriptstring.cpp @@ -40,19 +40,10 @@ ****************************************************************************/ #include "qdeclarativescriptstring.h" +#include "qdeclarativescriptstring_p.h" QT_BEGIN_NAMESPACE -class QDeclarativeScriptStringPrivate : public QSharedData -{ -public: - QDeclarativeScriptStringPrivate() : context(0), scope(0) {} - - QDeclarativeContext *context; - QObject *scope; - QString script; -}; - /*! \class QDeclarativeScriptString \since 4.7 @@ -75,8 +66,8 @@ and the class could choose how to handle it. Typically, the class will evaluate the script at some later time using a QDeclarativeExpression. \code -QDeclarativeExpression expr(scriptString.context(), scriptString.script(), scriptStr.scopeObject()); -expr.value(); +QDeclarativeExpression expr(scriptString); +expr.evaluate(); \endcode \sa QDeclarativeExpression diff --git a/src/declarative/qml/qdeclarativescriptstring.h b/src/declarative/qml/qdeclarativescriptstring.h index 5408dd404d..5f3a2fe73f 100644 --- a/src/declarative/qml/qdeclarativescriptstring.h +++ b/src/declarative/qml/qdeclarativescriptstring.h @@ -75,6 +75,9 @@ public: private: QSharedDataPointer<QDeclarativeScriptStringPrivate> d; + + friend class QDeclarativeVME; + friend class QDeclarativeExpression; }; QT_END_NAMESPACE diff --git a/src/declarative/qml/qdeclarativescriptstring_p.h b/src/declarative/qml/qdeclarativescriptstring_p.h new file mode 100644 index 0000000000..cd0cc43995 --- /dev/null +++ b/src/declarative/qml/qdeclarativescriptstring_p.h @@ -0,0 +1,63 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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.1, 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. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QDECLARATIVESCRIPTSTRING_P_H +#define QDECLARATIVESCRIPTSTRING_P_H + +#include <QtDeclarative/qdeclarativecontext.h> + +QT_BEGIN_NAMESPACE + +class QDeclarativeScriptStringPrivate : public QSharedData +{ +public: + QDeclarativeScriptStringPrivate() : context(0), scope(0), bindingId(-1), lineNumber(-1) {} + + QDeclarativeContext *context; + QObject *scope; + QString script; + int bindingId; + int lineNumber; +}; + +QT_END_NAMESPACE + +#endif // QDECLARATIVESCRIPTSTRING_P_H diff --git a/src/declarative/qml/qdeclarativevme.cpp b/src/declarative/qml/qdeclarativevme.cpp index dd080a85e9..a9b303c94f 100644 --- a/src/declarative/qml/qdeclarativevme.cpp +++ b/src/declarative/qml/qdeclarativevme.cpp @@ -61,6 +61,7 @@ #include "private/qdeclarativeglobal_p.h" #include "private/qdeclarativeglobalscriptclass_p.h" #include "qdeclarativescriptstring.h" +#include "qdeclarativescriptstring_p.h" #include <QStack> #include <QWidget> @@ -640,6 +641,8 @@ QObject *QDeclarativeVME::run(QDeclarativeVMEStack<QObject *> &stack, ss.setContext(ctxt->asQDeclarativeContext()); ss.setScopeObject(scope); ss.setScript(primitives.at(instr.value)); + ss.d.data()->bindingId = instr.bindingId; + ss.d.data()->lineNumber = instr.line; void *a[] = { &ss, 0, &status, &flags }; QMetaObject::metacall(target, QMetaObject::WriteProperty, diff --git a/src/declarative/qml/qml.pri b/src/declarative/qml/qml.pri index 233359079d..5d56b300ba 100644 --- a/src/declarative/qml/qml.pri +++ b/src/declarative/qml/qml.pri @@ -129,6 +129,7 @@ HEADERS += \ $$PWD/qdeclarativeimport_p.h \ $$PWD/qdeclarativeextensionplugin.h \ $$PWD/qintrusivelist_p.h \ + $$PWD/qdeclarativescriptstring_p.h QT += sql include(parser/parser.pri) diff --git a/tests/auto/declarative/qdeclarativeexpression/data/scriptString.qml b/tests/auto/declarative/qdeclarativeexpression/data/scriptString.qml new file mode 100644 index 0000000000..edd4048cc1 --- /dev/null +++ b/tests/auto/declarative/qdeclarativeexpression/data/scriptString.qml @@ -0,0 +1,9 @@ +import QtQuick 1.0 +import Test 1.0 + +TestObject { + property int value1: 10 + property int value2: 5 + scriptString: value1 + value2 + scriptStringError: value3 * 5 +} diff --git a/tests/auto/declarative/qdeclarativeexpression/qdeclarativeexpression.pro b/tests/auto/declarative/qdeclarativeexpression/qdeclarativeexpression.pro new file mode 100644 index 0000000000..8c73a7cb87 --- /dev/null +++ b/tests/auto/declarative/qdeclarativeexpression/qdeclarativeexpression.pro @@ -0,0 +1,17 @@ +load(qttest_p4) +contains(QT_CONFIG,declarative): QT += declarative gui +macx:CONFIG -= app_bundle + +SOURCES += tst_qdeclarativeexpression.cpp + +symbian: { + importFiles.files = data + importFiles.path = . + DEPLOYMENT += importFiles +} else { + DEFINES += SRCDIR=\\\"$$PWD\\\" +} + +CONFIG += parallel_test + +QT += core-private gui-private declarative-private diff --git a/tests/auto/declarative/qdeclarativeexpression/tst_qdeclarativeexpression.cpp b/tests/auto/declarative/qdeclarativeexpression/tst_qdeclarativeexpression.cpp new file mode 100644 index 0000000000..aa8c12e332 --- /dev/null +++ b/tests/auto/declarative/qdeclarativeexpression/tst_qdeclarativeexpression.cpp @@ -0,0 +1,115 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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.1, 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. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <qtest.h> +#include <QtDeclarative/qdeclarativeengine.h> +#include <QtDeclarative/qdeclarativecomponent.h> +#include <QtDeclarative/qdeclarativeexpression.h> +#include <QtDeclarative/qdeclarativescriptstring.h> + +#ifdef Q_OS_SYMBIAN +// In Symbian OS test data is located in applications private dir +#define SRCDIR "." +#endif + +class tst_qdeclarativeexpression : public QObject +{ + Q_OBJECT +public: + tst_qdeclarativeexpression() {} + +private slots: + void scriptString(); +}; + +class TestObject : public QObject +{ + Q_OBJECT + Q_PROPERTY(QDeclarativeScriptString scriptString READ scriptString WRITE setScriptString) + Q_PROPERTY(QDeclarativeScriptString scriptStringError READ scriptStringError WRITE setScriptStringError) +public: + TestObject(QObject *parent = 0) : QObject(parent) {} + + QDeclarativeScriptString scriptString() const { return m_scriptString; } + void setScriptString(QDeclarativeScriptString scriptString) { m_scriptString = scriptString; } + + QDeclarativeScriptString scriptStringError() const { return m_scriptStringError; } + void setScriptStringError(QDeclarativeScriptString scriptString) { m_scriptStringError = scriptString; } + +private: + QDeclarativeScriptString m_scriptString; + QDeclarativeScriptString m_scriptStringError; +}; + +QML_DECLARE_TYPE(TestObject) + +void tst_qdeclarativeexpression::scriptString() +{ + qmlRegisterType<TestObject>("Test", 1, 0, "TestObject"); + + QDeclarativeEngine engine; + QDeclarativeComponent c(&engine, QUrl::fromLocalFile(SRCDIR "/data/scriptString.qml")); + TestObject *testObj = qobject_cast<TestObject*>(c.create()); + QVERIFY(testObj != 0); + + QDeclarativeScriptString script = testObj->scriptString(); + QCOMPARE(script.script(), QLatin1String("value1 + value2")); + + QDeclarativeExpression expression(script); + QVariant value = expression.evaluate(); + QCOMPARE(value.toInt(), 15); + + QDeclarativeScriptString scriptError = testObj->scriptStringError(); + QCOMPARE(scriptError.script(), QLatin1String("value3 * 5")); + + //verify that the expression has the correct error location information + QDeclarativeExpression expressionError(scriptError); + QVariant valueError = expressionError.evaluate(); + QVERIFY(!valueError.isValid()); + QVERIFY(expressionError.hasError()); + QDeclarativeError error = expressionError.error(); + QCOMPARE(error.url(), c.url()); + QCOMPARE(error.line(), 8); +} + +QTEST_MAIN(tst_qdeclarativeexpression) + +#include "tst_qdeclarativeexpression.moc" |