diff options
author | Aaron Kennedy <aaron.kennedy@nokia.com> | 2010-01-27 01:26:12 (GMT) |
---|---|---|
committer | Aaron Kennedy <aaron.kennedy@nokia.com> | 2010-01-27 01:27:21 (GMT) |
commit | 6f1d4e8bdd9a11a4d35c8386e0c7e236bcfebd95 (patch) | |
tree | d14e4129940b5c584993ad9929b4d55500cf9a8c /src/declarative | |
parent | 167cbed98b5d9fadbe5d6f506e3937a25e7189b1 (diff) | |
download | Qt-6f1d4e8bdd9a11a4d35c8386e0c7e236bcfebd95.zip Qt-6f1d4e8bdd9a11a4d35c8386e0c7e236bcfebd95.tar.gz Qt-6f1d4e8bdd9a11a4d35c8386e0c7e236bcfebd95.tar.bz2 |
Harden binding optimizer
Diffstat (limited to 'src/declarative')
-rw-r--r-- | src/declarative/qml/qml.pri | 2 | ||||
-rw-r--r-- | src/declarative/qml/qmlbasicscript.cpp | 760 | ||||
-rw-r--r-- | src/declarative/qml/qmlbasicscript_p.h | 117 | ||||
-rw-r--r-- | src/declarative/qml/qmlbindingoptimizations.cpp | 87 | ||||
-rw-r--r-- | src/declarative/qml/qmlbindingoptimizations_p.h | 27 | ||||
-rw-r--r-- | src/declarative/qml/qmlbindingvme.cpp | 92 | ||||
-rw-r--r-- | src/declarative/qml/qmlbindingvme_p.h | 73 | ||||
-rw-r--r-- | src/declarative/qml/qmlcompiler.cpp | 92 | ||||
-rw-r--r-- | src/declarative/qml/qmlcompiler_p.h | 2 | ||||
-rw-r--r-- | src/declarative/qml/qmlcontext.cpp | 6 | ||||
-rw-r--r-- | src/declarative/qml/qmlcontext.h | 1 | ||||
-rw-r--r-- | src/declarative/qml/qmlcontext_p.h | 3 | ||||
-rw-r--r-- | src/declarative/qml/qmlengine.cpp | 1 | ||||
-rw-r--r-- | src/declarative/qml/qmlexpression.cpp | 86 | ||||
-rw-r--r-- | src/declarative/qml/qmlexpression.h | 1 | ||||
-rw-r--r-- | src/declarative/qml/qmlexpression_p.h | 8 | ||||
-rw-r--r-- | src/declarative/qml/qmlinstruction.cpp | 3 | ||||
-rw-r--r-- | src/declarative/qml/qmlinstruction_p.h | 1 | ||||
-rw-r--r-- | src/declarative/qml/qmlvme.cpp | 17 |
19 files changed, 213 insertions, 1166 deletions
diff --git a/src/declarative/qml/qml.pri b/src/declarative/qml/qml.pri index b3a3905..9268545 100644 --- a/src/declarative/qml/qml.pri +++ b/src/declarative/qml/qml.pri @@ -32,7 +32,6 @@ SOURCES += \ $$PWD/qmlscriptparser.cpp \ $$PWD/qmlenginedebug.cpp \ $$PWD/qmlrewrite.cpp \ - $$PWD/qmlbasicscript.cpp \ $$PWD/qmlbindingvme.cpp \ $$PWD/qmlvaluetype.cpp \ $$PWD/qmlbindingoptimizations.cpp \ @@ -96,7 +95,6 @@ HEADERS += \ $$PWD/qmldeclarativedata_p.h \ $$PWD/qmlerror.h \ $$PWD/qmlscriptparser_p.h \ - $$PWD/qmlbasicscript_p.h \ $$PWD/qmlbindingvme_p.h \ $$PWD/qmlenginedebug_p.h \ $$PWD/qmlrewrite_p.h \ diff --git a/src/declarative/qml/qmlbasicscript.cpp b/src/declarative/qml/qmlbasicscript.cpp deleted file mode 100644 index 3d566c7..0000000 --- a/src/declarative/qml/qmlbasicscript.cpp +++ /dev/null @@ -1,760 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2009 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$ -** 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 Technology Preview License Agreement accompanying -** this package. -** -** 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.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -** -** -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qmlbasicscript_p.h" - -#include "qmlengine_p.h" -#include "qmlcontext_p.h" -#include "qmlrefcount_p.h" -#include "qmlglobal_p.h" - -#include <qfxperf_p_p.h> -#include <qmljsast_p.h> -#include <qmljsengine_p.h> - -#include <QColor> -#include <QDebug> -#include <QStack> - -QT_BEGIN_NAMESPACE - -DEFINE_BOOL_CONFIG_OPTION(qmlBasicScriptDump, QML_BASICSCRIPT_DUMP); - -using namespace QmlJS; - -struct ScriptInstruction { - enum { - LoadIdObject, // fetch - FetchConstant, // constant - FetchContextConstant, // constant - FetchRootConstant, // constant - - Equals, // NA - - Int, // integer - Bool, // boolean - } type; - - union { - struct { - int idx; - } fetch; - struct { - int value; - } integer; - struct { - bool value; - } boolean; - struct { - short idx; - short notify; - int type; - } constant; - }; -}; - -class QmlBasicScriptPrivate -{ -public: - enum Flags { OwnData = 0x00000001 }; - - int size; - int stateSize; - int instructionCount; - int exprLen; - - ScriptInstruction *instructions() const { return (ScriptInstruction *)((char *)this + sizeof(QmlBasicScriptPrivate)); } - - const char *expr() const - { - return (const char *)(instructions() + instructionCount); - } - - const char *data() const - { - return (const char *)(instructions() + instructionCount) + exprLen + 1; - } - - static unsigned int alignRound(int s) - { - if (s % 4) - s += 4 - (s % 4); - return s; - } -}; - -// anchors.left: (nop convert)(qobject)parent.(anchorline)right - -/* - Property chains: a.b.c.d - if else value selection statements: if(a) b else if(c) d else e - trinary selection: a?b:c - addition: a + b - negation: a - a - equality: == -*/ -static QVariant fetch_value(QObject *o, int idx, int type) -{ - if (!o) - return QVariant(); - - switch(type) { - case QVariant::String: - { - QString val; - void *args[] = { &val, 0 }; - QMetaObject::metacall(o, QMetaObject::ReadProperty, idx, args); - return QVariant(val); - } - break; - case QVariant::UInt: - { - uint val; - void *args[] = { &val, 0 }; - QMetaObject::metacall(o, QMetaObject::ReadProperty, idx, args); - return QVariant(val); - } - break; - case QVariant::Int: - { - int val; - void *args[] = { &val, 0 }; - QMetaObject::metacall(o, QMetaObject::ReadProperty, idx, args); - return QVariant(val); - } - break; - case QMetaType::Float: - { - float val; - void *args[] = { &val, 0 }; - QMetaObject::metacall(o, QMetaObject::ReadProperty, idx, args); - return QVariant(val); - } - break; - case QVariant::Double: - { - double val; - void *args[] = { &val, 0 }; - QMetaObject::metacall(o, QMetaObject::ReadProperty, idx, args); - return QVariant(val); - } - break; - case QVariant::Color: - { - QColor val; - void *args[] = { &val, 0 }; - QMetaObject::metacall(o, QMetaObject::ReadProperty, idx, args); - return QVariant(val); - } - break; - case QVariant::Bool: - { - bool val; - void *args[] = { &val, 0 }; - QMetaObject::metacall(o, QMetaObject::ReadProperty, idx, args); - return QVariant(val); - } - break; - default: - { - // If the object is null, we extract the predicted type. While this isn't - // 100% reliable, in many cases it gives us better error messages if we - // assign this null-object to an incompatible property - if (QmlMetaType::isObject(type)) { - // NOTE: This assumes a cast to QObject does not alter the - // object pointer - QObject *val = 0; - void *args[] = { &val, 0 }; - QMetaObject::metacall(o, QMetaObject::ReadProperty, idx, args); - if (!val) return QVariant(type, &val); - else return QVariant::fromValue(val); - } else { - QVariant var = o->metaObject()->property(idx).read(o); - if (QmlMetaType::isObject(var.userType())) { - QObject *obj = 0; - obj = *(QObject **)var.data(); - if (!obj) var = QVariant(var.userType(), &obj); - else var = QVariant::fromValue(obj); - } - return var; - } - } - break; - }; -} - -struct QmlBasicScriptCompiler -{ - QmlBasicScriptCompiler() - : script(0), stateSize(0) {} - - QmlBasicScript *script; - int stateSize; - - QmlParser::Object *context; - QmlParser::Object *component; - QHash<QString, QmlParser::Object *> ids; - - bool compile(QmlJS::AST::Node *); - - bool compileExpression(QmlJS::AST::Node *); - - bool tryConstant(QmlJS::AST::Node *); - bool parseConstant(QmlJS::AST::Node *); - bool tryName(QmlJS::AST::Node *); - bool parseName(QmlJS::AST::Node *); - - bool buildName(QStringList &, QmlJS::AST::Node *); - const QMetaObject *fetch(int type, const QMetaObject *, int idx); - - bool tryBinaryExpression(QmlJS::AST::Node *); - bool compileBinaryExpression(QmlJS::AST::Node *); - - QByteArray data; - QList<ScriptInstruction> bytecode; -}; - -/*! - \internal - \class QmlBasicScript - \brief The QmlBasicScript class provides a fast implementation of a limited subset of QmlJS bindings. - - QmlBasicScript instances are used to accelerate binding. Instead of using - the slower, fully fledged QmlJS engine, many simple bindings can be - evaluated using the QmlBasicScript engine. - - To see if the QmlBasicScript engine can handle a binding, call compile() - and check the return value, or isValid() afterwards. - - To accelerate binding, QmlBasicScript can return a precompiled - version of itself that can be saved for future use. Call compileData() to - get an opaque pointer to the compiled state, and compileDataSize() for the - size of this data in bytes. This data can be saved and passed to future - instances of the QmlBasicScript constructor. The initial copy of compile - data is owned by the QmlBindScript instance on which compile() was called. -*/ - -/*! - Create a new QmlBasicScript instance. -*/ -QmlBasicScript::QmlBasicScript() -: flags(0), d(0), rc(0) -{ -} - -/*! - Load the QmlBasicScript instance with saved \a data. - - \a data \b must be data previously acquired from calling compileData() on a - previously created QmlBasicScript instance. Any other data will almost - certainly cause the QmlBasicScript engine to crash. - - \a data must continue to be valid throughout the QmlBasicScript instance - life. It does not assume ownership of the memory. - - If \a owner is set, it is referenced on creation and dereferenced on - destruction of this instance. -*/ - -void QmlBasicScript::load(const char *data, QmlRefCount *owner) -{ - clear(); - d = (QmlBasicScriptPrivate *)data; - rc = owner; - if (rc) rc->addref(); -} - -/*! - Return the text of the script expression. - */ -QByteArray QmlBasicScript::expression() const -{ - if (!d) - return QByteArray(); - else - return QByteArray(d->expr()); -} - -/*! - Destroy the script instance. -*/ -QmlBasicScript::~QmlBasicScript() -{ - clear(); -} - -/*! - Clear this script. The object will then be in its initial state, as though - it were freshly constructed with default constructor. -*/ -void QmlBasicScript::clear() -{ - if (flags & QmlBasicScriptPrivate::OwnData) - free(d); - if (rc) rc->release(); - d = 0; - rc = 0; - flags = 0; -} - -/*! - Dump the script instructions to stderr for debugging. - */ -void QmlBasicScript::dump() -{ - if (!d) - return; - - qWarning() << d->instructionCount << "instructions:"; - for (int ii = 0; ii < d->instructionCount; ++ii) { - const ScriptInstruction &instr = d->instructions()[ii]; - - switch(instr.type) { - case ScriptInstruction::LoadIdObject: - qWarning().nospace() << "LOAD_ID_OBJECT"; - break; - case ScriptInstruction::FetchConstant: - qWarning().nospace() << "FETCH_CONSTANT"; - break; - case ScriptInstruction::FetchContextConstant: - qWarning().nospace() << "FETCH_CONTEXT_CONSTANT"; - break; - case ScriptInstruction::FetchRootConstant: - qWarning().nospace() << "FETCH_ROOT_CONSTANT"; - break; - case ScriptInstruction::Equals: - qWarning().nospace() << "EQUALS"; - break; - case ScriptInstruction::Int: - qWarning().nospace() << "INT\t\t" << instr.integer.value; - break; - case ScriptInstruction::Bool: - qWarning().nospace() << "BOOL\t\t" << instr.boolean.value; - break; - default: - qWarning().nospace() << "UNKNOWN"; - break; - } - } -} - -/*! - Return true if this is a valid script binding, otherwise returns false. - */ -bool QmlBasicScript::isValid() const -{ - return d != 0; -} - -bool QmlBasicScript::compile(const Expression &expression) -{ - if (!expression.expression.asAST()) return false; - - QByteArray expr = expression.expression.asScript().toUtf8(); - const char *src = expr.constData(); - - QmlBasicScriptCompiler bsc; - bsc.script = this; - bsc.context = expression.context; - bsc.component = expression.component; - bsc.ids = expression.ids; - - if (d) { - if (flags & QmlBasicScriptPrivate::OwnData) - free(d); - d = 0; - flags = 0; - } - - if (bsc.compile(expression.expression.asAST())) { - int len = ::strlen(src); - flags = QmlBasicScriptPrivate::OwnData; - int size = sizeof(QmlBasicScriptPrivate) + - bsc.bytecode.count() * sizeof(ScriptInstruction) + - QmlBasicScriptPrivate::alignRound(bsc.data.count() + len + 1); - d = (QmlBasicScriptPrivate *) malloc(size); - d->size = size; - d->stateSize = bsc.stateSize; - d->instructionCount = bsc.bytecode.count(); - d->exprLen = len; - ::memcpy((char *)d->expr(), src, len + 1); - for (int ii = 0; ii < d->instructionCount; ++ii) - d->instructions()[ii] = bsc.bytecode.at(ii); - ::memcpy((char *)d->data(), bsc.data.constData(), bsc.data.count()); - } - - if (d && qmlBasicScriptDump()) - dump(); - return d != 0; -} - -bool QmlBasicScriptCompiler::compile(QmlJS::AST::Node *node) -{ - return compileExpression(node); -} - -bool QmlBasicScriptCompiler::tryConstant(QmlJS::AST::Node *node) -{ - if (node->kind == AST::Node::Kind_TrueLiteral || - node->kind == AST::Node::Kind_FalseLiteral) - return true; - - if (node->kind == AST::Node::Kind_NumericLiteral) { - AST::NumericLiteral *lit = static_cast<AST::NumericLiteral *>(node); - - return double(int(lit->value)) == lit->value; - } - - return false; -} - -bool QmlBasicScriptCompiler::parseConstant(QmlJS::AST::Node *node) -{ - ScriptInstruction instr; - - if (node->kind == AST::Node::Kind_NumericLiteral) { - AST::NumericLiteral *lit = static_cast<AST::NumericLiteral *>(node); - instr.type = ScriptInstruction::Int; - instr.integer.value = int(lit->value); - } else { - instr.type = ScriptInstruction::Bool; - instr.boolean.value = node->kind == AST::Node::Kind_TrueLiteral; - } - - bytecode.append(instr); - - return true; -} - -bool QmlBasicScriptCompiler::tryName(QmlJS::AST::Node *node) -{ - return node->kind == AST::Node::Kind_IdentifierExpression || - node->kind == AST::Node::Kind_FieldMemberExpression; -} - -bool QmlBasicScriptCompiler::buildName(QStringList &name, - QmlJS::AST::Node *node) -{ - if (node->kind == AST::Node::Kind_IdentifierExpression) { - name << static_cast<AST::IdentifierExpression*>(node)->name->asString(); - } else if (node->kind == AST::Node::Kind_FieldMemberExpression) { - AST::FieldMemberExpression *expr = - static_cast<AST::FieldMemberExpression *>(node); - - if (!buildName(name, expr->base)) - return false; - - name << expr->name->asString(); - } else { - return false; - } - - return true; -} - -const QMetaObject * -QmlBasicScriptCompiler::fetch(int type, const QMetaObject *mo, int idx) -{ - ScriptInstruction instr; - *((int*)&instr.type) = type; - instr.constant.idx = idx; - QMetaProperty prop = mo->property(idx); - if (prop.isConstant()) - instr.constant.notify = 0; - else - instr.constant.notify = prop.notifySignalIndex(); - instr.constant.type = prop.userType(); - bytecode << instr; - return QmlMetaType::metaObjectForType(prop.userType()); -} - -bool QmlBasicScriptCompiler::parseName(AST::Node *node) -{ - QStringList nameParts; - if (!buildName(nameParts, node)) - return false; - - QmlParser::Object *absType = 0; - const QMetaObject *metaType = 0; - - for (int ii = 0; ii < nameParts.count(); ++ii) { - const QString &name = nameParts.at(ii); - - // We don't handle signal properties - if (name.length() > 2 && name.startsWith(QLatin1String("on")) && - name.at(2).isUpper()) - return false; - - if (ii == 0) { - - if (0) { - // ### - Must test for an attached type name - } else if (ids.contains(name)) { - ScriptInstruction instr; - instr.type = ScriptInstruction::LoadIdObject; - instr.fetch.idx = ids.value(name)->idIndex; - bytecode << instr; - absType = ids.value(name); - } else if(name.at(0).isLower()) { - - QByteArray utf8Name = name.toUtf8(); - const char *cname = utf8Name.constData(); - - int d0Idx = context->metaObject()->indexOfProperty(cname); - int d1Idx = -1; - if (d0Idx == -1) - d1Idx = component->metaObject()->indexOfProperty(cname); - - if (d0Idx != -1) { - metaType = fetch(ScriptInstruction::FetchContextConstant, - context->metaObject(), d0Idx); - } else if(d1Idx != -1) { - metaType = fetch(ScriptInstruction::FetchRootConstant, - component->metaObject(), d1Idx); - } else { - return false; - } - - } else { - return false; - } - } else { - - if (!name.at(0).isLower()) - return false; - - const QMetaObject *mo = 0; - if (absType) - mo = absType->metaObject(); - else if(metaType) - mo = metaType; - else - return false; - - QByteArray utf8Name = name.toUtf8(); - const char *cname = utf8Name.constData(); - int idx = mo->indexOfProperty(cname); - if (idx == -1) - return false; - - if (absType || mo->property(idx).isFinal()) { - absType = 0; metaType = 0; - metaType = fetch(ScriptInstruction::FetchConstant, mo, idx); - } else { - return false; - } - - } - } - - return true; -} - -bool QmlBasicScriptCompiler::compileExpression(QmlJS::AST::Node *node) -{ - if (tryBinaryExpression(node)) - return compileBinaryExpression(node); - else if (tryConstant(node)) - return parseConstant(node); - else if (tryName(node)) - return parseName(node); - else - return false; -} - -bool QmlBasicScriptCompiler::tryBinaryExpression(AST::Node *node) -{ - if (node->kind == AST::Node::Kind_BinaryExpression) { - AST::BinaryExpression *expr = - static_cast<AST::BinaryExpression *>(node); - - if (expr->op == QSOperator::Equal) - return true; - } - return false; -} - -bool QmlBasicScriptCompiler::compileBinaryExpression(AST::Node *node) -{ - if (node->kind == AST::Node::Kind_BinaryExpression) { - AST::BinaryExpression *expr = - static_cast<AST::BinaryExpression *>(node); - - if (!compileExpression(expr->left)) return false; - if (!compileExpression(expr->right)) return false; - - ScriptInstruction instr; - switch (expr->op) { - case QSOperator::Equal: - instr.type = ScriptInstruction::Equals; - break; - default: - return false; - } - - bytecode.append(instr); - return true; - } - return false; -} - -/*! - Run the script in \a context and return the result. - */ -QVariant QmlBasicScript::run(QmlContext *context, QObject *me) -{ - if (!isValid()) - return QVariant(); - - QmlContextPrivate *contextPrivate = context->d_func(); - QmlEnginePrivate *enginePrivate = QmlEnginePrivate::get(context->engine()); - - QStack<QVariant> stack; - - for (int idx = 0; idx < d->instructionCount; ++idx) { - const ScriptInstruction &instr = d->instructions()[idx]; - - switch(instr.type) { - case ScriptInstruction::LoadIdObject: - { - stack.push(QVariant::fromValue(contextPrivate->idValues[instr.fetch.idx].data())); - enginePrivate->capturedProperties << - QmlEnginePrivate::CapturedProperty(context, -1, contextPrivate->notifyIndex + instr.fetch.idx); - } - break; - - case ScriptInstruction::FetchContextConstant: - { - stack.push(fetch_value(me, instr.constant.idx, instr.constant.type)); - if (me && instr.constant.notify != 0) - enginePrivate->capturedProperties << - QmlEnginePrivate::CapturedProperty(me, instr.constant.idx, instr.constant.notify); - } - break; - - case ScriptInstruction::FetchRootConstant: - { - QObject *obj = contextPrivate->defaultObjects.at(0); - - stack.push(fetch_value(obj, instr.constant.idx, instr.constant.type)); - if (obj && instr.constant.notify != 0) - enginePrivate->capturedProperties << - QmlEnginePrivate::CapturedProperty(obj, instr.constant.idx, instr.constant.notify); - } - break; - - case ScriptInstruction::FetchConstant: - { - QVariant o = stack.pop(); - QObject *obj = *(QObject **)o.constData(); - - stack.push(fetch_value(obj, instr.constant.idx, instr.constant.type)); - if (obj && instr.constant.notify != 0) - enginePrivate->capturedProperties << - QmlEnginePrivate::CapturedProperty(obj, instr.constant.idx, instr.constant.notify); - } - break; - - case ScriptInstruction::Int: - stack.push(QVariant(instr.integer.value)); - break; - - case ScriptInstruction::Bool: - stack.push(QVariant(instr.boolean.value)); - break; - - case ScriptInstruction::Equals: - { - QVariant rhs = stack.pop(); - QVariant lhs = stack.pop(); - - stack.push(rhs == lhs); - } - break; - default: - break; - } - } - - if (stack.isEmpty()) - return QVariant(); - else - 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. - */ -const char *QmlBasicScript::compileData() const -{ - return (const char *)d; -} - -/*! - Return the size of the script's compile data, or zero if there is no data. - The size will always be a multiple of 4. - */ -unsigned int QmlBasicScript::compileDataSize() const -{ - if (d) - return d->size; - else - return 0; -} - -QT_END_NAMESPACE diff --git a/src/declarative/qml/qmlbasicscript_p.h b/src/declarative/qml/qmlbasicscript_p.h deleted file mode 100644 index c4b436d..0000000 --- a/src/declarative/qml/qmlbasicscript_p.h +++ /dev/null @@ -1,117 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2009 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$ -** 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 Technology Preview License Agreement accompanying -** this package. -** -** 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.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -** -** -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QMLBASICSCRIPT_P_H -#define QMLBASICSCRIPT_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 "qmlparser_p.h" -#include "qmlengine_p.h" - -#include <QtCore/QList> -#include <QtCore/QByteArray> -#include <QtCore/QVariant> - -QT_BEGIN_HEADER - -QT_BEGIN_NAMESPACE - -class QmlRefCount; -class QmlContext; -class QmlBasicScriptPrivate; -class QmlBasicScriptNodeCache; -class QmlBasicScript -{ -public: - QmlBasicScript(); - ~QmlBasicScript(); - - void load(const char *, QmlRefCount * = 0); - - // Always 4-byte aligned - const char *compileData() const; - unsigned int compileDataSize() const; - - QByteArray expression() const; - - struct Expression - { - QmlParser::Object *component; - QmlParser::Object *context; - QmlParser::Property *property; - QmlParser::Variant expression; - QHash<QString, QmlParser::Object *> ids; - QmlEnginePrivate::Imports imports; - }; - - bool compile(const Expression &); - bool isValid() const; - - void clear(); - - void dump(); - - QVariant run(QmlContext *, QObject *); - - bool isSingleIdFetch() const; - int singleIdFetchIndex() const; - -private: - int flags; - QmlBasicScriptPrivate *d; - QmlRefCount *rc; -}; - -QT_END_NAMESPACE - -QT_END_HEADER - -#endif // QMLBASICSCRIPT_P_H diff --git a/src/declarative/qml/qmlbindingoptimizations.cpp b/src/declarative/qml/qmlbindingoptimizations.cpp index beee3c9..1e49636 100644 --- a/src/declarative/qml/qmlbindingoptimizations.cpp +++ b/src/declarative/qml/qmlbindingoptimizations.cpp @@ -170,91 +170,4 @@ void QmlOptimizedBindings::run(Binding *binding) } } -/* - The QmlBinding_Id optimization handles expressions of the type: - - property: id - - where id is a local context id, and property is an object property. - Coercian between id and property must be checked outside the QmlBinding_Id - - it assumes that they coerce successfully. - - The QmlBinding_Id class avoids any signal slot connections, through the - special "bindings" linked list maintained in the - QmlContextPrivate::ContextGuard instance for each id object. -*/ -QmlBinding_Id::QmlBinding_Id(QObject *object, int propertyIdx, - QmlContext *context, int id) -: m_prev(0), m_next(0), m_object(object), m_propertyIdx(propertyIdx), m_id(id) -{ - QmlAbstractExpression::setContext(context); -} - -QmlBinding_Id::~QmlBinding_Id() -{ - removeFromContext(); -} - -void QmlBinding_Id::setEnabled(bool e, QmlMetaProperty::WriteFlags flags) -{ - if (e) { - addToObject(m_object); - update(flags); - } else { - removeFromObject(); - } - - QmlAbstractBinding::setEnabled(e, flags); -} - -int QmlBinding_Id::propertyIndex() -{ - return m_propertyIdx; -} - -void QmlBinding_Id::update(QmlMetaProperty::WriteFlags flags) -{ - 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(); - int status = -1; - void *a[] = { &o, 0, &status, &flags }; - QMetaObject::metacall(m_object, QMetaObject::WriteProperty, - m_propertyIdx, a); - } -} - -void QmlBinding_Id::removeFromContext() -{ - if (m_prev) { - *m_prev = m_next; - if (m_next) m_next->m_prev = m_prev; - m_next = 0; - m_prev = 0; - } -} - -void QmlBinding_Id::reset() -{ - removeFromContext(); - - QObject *o = 0; - int status = -1; - QmlMetaProperty::WriteFlags flags = QmlMetaProperty::DontRemoveBinding; - void *a[] = { &o, 0, &status, &flags }; - 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 index 59a0cc6..42b7d17 100644 --- a/src/declarative/qml/qmlbindingoptimizations_p.h +++ b/src/declarative/qml/qmlbindingoptimizations_p.h @@ -55,7 +55,6 @@ #include "qmlexpression_p.h" #include "qmlbinding.h" -#include "qmlbasicscript_p.h" #include "qmlbindingvme_p.h" QT_BEGIN_HEADER @@ -102,32 +101,6 @@ private: static int methodCount; }; -class QmlBinding_Id : public QmlAbstractExpression, - public QmlAbstractBinding -{ -public: - QmlBinding_Id(QObject *object, int propertyIdx, - QmlContext *context, int id); - virtual ~QmlBinding_Id(); - - // Inherited from QmlAbstractBinding - virtual void setEnabled(bool, QmlMetaProperty::WriteFlags flags); - virtual int propertyIndex(); - virtual void update(QmlMetaProperty::WriteFlags flags); - - void reset(); - -private: - void removeFromContext(); - - QmlBinding_Id **m_prev; - QmlBinding_Id *m_next; - - QObject *m_object; - int m_propertyIdx; - int m_id; -}; - QT_END_NAMESPACE QT_END_HEADER diff --git a/src/declarative/qml/qmlbindingvme.cpp b/src/declarative/qml/qmlbindingvme.cpp index 5efaaca..47f02b2 100644 --- a/src/declarative/qml/qmlbindingvme.cpp +++ b/src/declarative/qml/qmlbindingvme.cpp @@ -52,6 +52,22 @@ QT_BEGIN_NAMESPACE using namespace QmlJS; +QmlBindingVME::Config::Subscription::Signal *QmlBindingVME::Config::Subscription::signal() +{ + if (type == IdType) ((Id *)idData)->~Id(); + if (type != SignalType) new (signalData) Signal; + type = SignalType; + return (Signal *)signalData; +} + +QmlBindingVME::Config::Subscription::Id *QmlBindingVME::Config::Subscription::id() +{ + if (type == SignalType) ((Signal *)signalData)->~Signal(); + if (type != IdType) new (idData) Id; + type = IdType; + return (Id *)idData; +} + namespace { // Supported types: int, qreal, QString (needs constr/destr), QObject*, bool struct Register { @@ -395,10 +411,53 @@ struct QmlBindingCompilerPrivate QByteArray buildExceptionData() const; }; +inline void unsubscribe(int subIndex, QmlBindingVME::Config *config) +{ + QmlBindingVME::Config::Subscription *sub = (config->subscriptions + subIndex); + if (sub->isSignal()) { + QmlBindingVME::Config::Subscription::Signal *s = sub->signal(); + if (s->source) +#if (QT_VERSION >= QT_VERSION_CHECK(4, 6, 2)) + QMetaObject::disconnectOne(s->source, s->notifyIndex, + config->target, config->targetSlot + subIndex); +#else + // QTBUG-6781 + QMetaObject::disconnect(s->source, s->notifyIndex, + config->target, config->targetSlot + subIndex); +#endif + } else if (sub->isId()) { + sub->id()->reset(); + } +} + +inline void subscribeId(QmlContextPrivate *p, int idIndex, + int subIndex, QmlBindingVME::Config *config) +{ + unsubscribe(subIndex, config); + + if (p->idValues[idIndex]) { + QmlBindingVME::Config::Subscription *sub = (config->subscriptions + subIndex); + QmlBindingVME::Config::Subscription::Id *i = sub->id(); + + i->next = p->idValues[idIndex].bindings; + i->prev = &p->idValues[idIndex].bindings; + p->idValues[idIndex].bindings = i; + if (i->next) i->next->prev = &i->next; + + i->target = config->target; + i->methodIndex = config->targetSlot + subIndex; + } +} + inline void subscribe(QObject *o, int notifyIndex, int subIndex, QmlBindingVME::Config *config) { - QmlBindingVME::Config::Subscription *s = config->subscriptions + subIndex; + QmlBindingVME::Config::Subscription *sub = (config->subscriptions + subIndex); + + if (sub->isId()) + unsubscribe(subIndex, config); + + QmlBindingVME::Config::Subscription::Signal *s = sub->signal(); if (o != s->source || notifyIndex != s->notifyIndex) { if (s->source) #if (QT_VERSION >= QT_VERSION_CHECK(4, 6, 2)) @@ -690,10 +749,14 @@ void QmlBindingVME::init(const char *programData, Config *config, } static void throwException(int id, QmlDelayedError *error, - Program *program, QmlContextPrivate *context) + Program *program, QmlContextPrivate *context, + const QString &description = QString()) { error->error.setUrl(context->url); - error->error.setDescription("TypeError: Result of expression is not an object"); + if (description.isEmpty()) + error->error.setDescription(QLatin1String("TypeError: Result of expression is not an object")); + else + error->error.setDescription(description); if (id != 0xFF) { quint64 e = *((quint64 *)(program->data() + program->exceptionDataOffset) + id); error->error.setLine((e >> 32) & 0xFFFFFFFF); @@ -728,18 +791,16 @@ void QmlBindingVME::run(const char *programData, int instrIndex, break; case Instr::SubscribeId: + subscribeId(context, instr->subscribe.index, instr->subscribe.offset, config); + break; + case Instr::Subscribe: { QObject *o = 0; int notifyIndex = instr->subscribe.index; - if (instr->common.type == Instr::SubscribeId) { - o = QmlContextPrivate::get(context); - notifyIndex += context->notifyIndex; - } else { - const Register &object = registers[instr->subscribe.reg]; - if (!object.isUndefined()) o = object.getQObject(); - } + const Register &object = registers[instr->subscribe.reg]; + if (!object.isUndefined()) o = object.getQObject(); subscribe(o, instr->subscribe.index, instr->subscribe.offset, config); } break; @@ -998,7 +1059,8 @@ void QmlBindingVME::run(const char *programData, int instrIndex, { Register &data = registers[instr->store.reg]; if (data.isUndefined()) { - throwException(instr->store.exceptionId, error, program, context); + throwException(instr->store.exceptionId, error, program, context, + QLatin1String("Unable to assign undefined value")); return; } @@ -1374,7 +1436,7 @@ bool QmlBindingCompilerPrivate::compile(QmlJS::AST::Node *node) instr.store.output = 0; instr.store.index = destination->index; instr.store.reg = convertReg; - instr.store.exceptionId = 0xFF; + instr.store.exceptionId = exceptionId(node->expressionCast()); bytecode << instr; if (destination->type == QVariant::String) { @@ -1429,6 +1491,7 @@ bool QmlBindingCompilerPrivate::compile(QmlJS::AST::Node *node) instr.store.output = 0; instr.store.index = destination->index; instr.store.reg = type.reg; + instr.store.exceptionId = exceptionId(node->expressionCast()); bytecode << instr; releaseReg(type.reg); @@ -2317,7 +2380,7 @@ bool QmlBindingCompilerPrivate::subscriptionNeutral(const QSet<QString> &base, quint8 QmlBindingCompilerPrivate::exceptionId(QmlJS::AST::ExpressionNode *n) { quint8 rv = 0xFF; - if (exceptions.count() < 0xFF) { + if (n && exceptions.count() < 0xFF) { rv = (quint8)exceptions.count(); QmlJS::AST::SourceLocation l = n->firstSourceLocation(); quint64 e = l.startLine; @@ -2349,8 +2412,7 @@ bool QmlBindingCompiler::isValid() const /* -1 on failure, otherwise the binding index to use. */ -int QmlBindingCompiler::compile(const QmlBasicScript::Expression &expression, - QmlEnginePrivate *engine) +int QmlBindingCompiler::compile(const Expression &expression, QmlEnginePrivate *engine) { if (!expression.expression.asAST()) return false; diff --git a/src/declarative/qml/qmlbindingvme_p.h b/src/declarative/qml/qmlbindingvme_p.h index 629a979..01280f0 100644 --- a/src/declarative/qml/qmlbindingvme_p.h +++ b/src/declarative/qml/qmlbindingvme_p.h @@ -54,8 +54,8 @@ // #include <QtCore/qglobal.h> -#include <private/qmlbasicscript_p.h> #include <private/qscriptdeclarativeclass_p.h> +#include "qmlexpression_p.h" #include "qmlguard_p.h" QT_BEGIN_HEADER @@ -74,8 +74,32 @@ public: int targetSlot; struct Subscription { - QmlGuard<QObject> source; - int notifyIndex; + struct Signal { + QmlGuard<QObject> source; + int notifyIndex; + }; + + struct Id { + inline Id(); + inline ~Id(); + inline void reset(); + Id *next; + Id**prev; + QObject *target; + int methodIndex; + }; + + enum { InvalidType, SignalType, IdType } type; + inline Subscription(); + inline ~Subscription(); + bool isSignal() const { return type == SignalType; } + bool isId() const { return type == IdType; } + inline Signal *signal(); + inline Id *id(); + union { + char signalData[sizeof(Signal)]; + char idData[sizeof(Id)]; + }; }; Subscription *subscriptions; QScriptDeclarativeClass::PersistentIdentifier *identifiers; @@ -89,6 +113,37 @@ public: static void dump(const char *); }; +QmlBindingVME::Config::Subscription::Subscription() +: type(InvalidType) +{ +} + +QmlBindingVME::Config::Subscription::~Subscription() +{ + if (type == SignalType) ((Signal *)signalData)->~Signal(); + else if (type == IdType) ((Id *)idData)->~Id(); +} + +QmlBindingVME::Config::Subscription::Id::Id() +: next(0), prev(0), target(0), methodIndex(-1) +{ +} + +QmlBindingVME::Config::Subscription::Id::~Id() +{ + reset(); +} + +void QmlBindingVME::Config::Subscription::Id::reset() +{ + if (next) next->prev = prev; + if (prev) *prev = next; + next = 0; + prev = 0; + target = 0; + methodIndex = -1; +} + class QmlBindingCompilerPrivate; class QmlBindingCompiler { @@ -99,8 +154,18 @@ public: // Returns true if bindings were compiled bool isValid() const; + struct Expression + { + QmlParser::Object *component; + QmlParser::Object *context; + QmlParser::Property *property; + QmlParser::Variant expression; + QHash<QString, QmlParser::Object *> ids; + QmlEnginePrivate::Imports imports; + }; + // -1 on failure, otherwise the binding index to use - int compile(const QmlBasicScript::Expression &, QmlEnginePrivate *); + int compile(const Expression &, QmlEnginePrivate *); // Returns the compiled program QByteArray program() const; diff --git a/src/declarative/qml/qmlcompiler.cpp b/src/declarative/qml/qmlcompiler.cpp index 1368324..5937734 100644 --- a/src/declarative/qml/qmlcompiler.cpp +++ b/src/declarative/qml/qmlcompiler.cpp @@ -47,7 +47,6 @@ #include "qmlpropertyvaluesource.h" #include "qmlcomponent.h" #include "qmetaobjectbuilder_p.h" -#include "qmlbasicscript_p.h" #include "qmlstringconverters_p.h" #include "qmlengine_p.h" #include "qmlengine.h" @@ -2558,23 +2557,6 @@ void QmlCompiler::genBindingAssignment(QmlParser::Value *binding, } QmlInstruction store; - - QmlBasicScript bs; - if (ref.dataType == BindingReference::BasicScript) - 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::StoreBinding; store.assignBinding.value = output->indexForByteArray(ref.compiledData); store.assignBinding.context = ref.bindingContext.stack; @@ -2628,7 +2610,7 @@ bool QmlCompiler::completeComponentBuild() COMPILE_CHECK(buildDynamicMeta(aliasObject, ResolveAliases)); } - QmlBasicScript::Expression expr; + QmlBindingCompiler::Expression expr; expr.component = compileState.root; expr.ids = compileState.ids; @@ -2637,15 +2619,12 @@ bool QmlCompiler::completeComponentBuild() for (QHash<QmlParser::Value*,BindingReference>::Iterator iter = compileState.bindings.begin(); iter != compileState.bindings.end(); ++iter) { BindingReference &binding = *iter; - QmlBasicScript bs; expr.context = binding.bindingContext.object; expr.property = binding.property; expr.expression = binding.expression; expr.imports = unit->imports; - bs.compile(expr); - - if (qmlExperimental() && (!bs.isValid() || !bs.isSingleIdFetch())) { + if (qmlExperimental()) { int index = bindingCompiler.compile(expr, QmlEnginePrivate::get(engine)); if (index != -1) { qWarning() << "Accepted for optimization:" << qPrintable(expr.expression.asScript()); @@ -2658,50 +2637,37 @@ bool QmlCompiler::completeComponentBuild() } } - quint32 type; - if (bs.isValid()) { - binding.compiledData = - QByteArray(bs.compileData(), bs.compileDataSize()); - type = QmlExpressionPrivate::BasicScriptEngineData; - binding.dataType = BindingReference::BasicScript; + binding.dataType = BindingReference::QtScript; - componentStat.optimizedBindings++; - } else { - type = QmlExpressionPrivate::PreTransformedQtScriptData; - binding.dataType = BindingReference::QtScript; - - // Pre-rewrite the expression - QString expression = binding.expression.asScript(); - - // ### Optimize - QmlRewrite::SharedBindingTester sharableTest; - bool isSharable = sharableTest.isSharable(expression); - - QmlRewrite::RewriteBinding rewriteBinding; - expression = rewriteBinding(expression); - - quint32 length = expression.length(); - quint32 pc; - - if (isSharable) { - pc = output->cachedClosures.count(); - pc |= 0x80000000; - output->cachedClosures.append(0); - } else { - pc = output->cachedPrograms.length(); - output->cachedPrograms.append(0); - } + // Pre-rewrite the expression + QString expression = binding.expression.asScript(); - binding.compiledData = - QByteArray((const char *)&pc, sizeof(quint32)) + - QByteArray((const char *)&length, sizeof(quint32)) + - QByteArray((const char *)expression.constData(), - expression.length() * sizeof(QChar)); + // ### Optimize + QmlRewrite::SharedBindingTester sharableTest; + bool isSharable = sharableTest.isSharable(expression); + + QmlRewrite::RewriteBinding rewriteBinding; + expression = rewriteBinding(expression); - componentStat.scriptBindings++; + quint32 length = expression.length(); + quint32 pc; + + if (isSharable) { + pc = output->cachedClosures.count(); + pc |= 0x80000000; + output->cachedClosures.append(0); + } else { + pc = output->cachedPrograms.length(); + output->cachedPrograms.append(0); } - binding.compiledData.prepend(QByteArray((const char *)&type, - sizeof(quint32))); + + binding.compiledData = + QByteArray((const char *)&pc, sizeof(quint32)) + + QByteArray((const char *)&length, sizeof(quint32)) + + QByteArray((const char *)expression.constData(), + expression.length() * sizeof(QChar)); + + componentStat.scriptBindings++; } if (bindingCompiler.isValid()) { diff --git a/src/declarative/qml/qmlcompiler_p.h b/src/declarative/qml/qmlcompiler_p.h index 732fbad..f3f266b 100644 --- a/src/declarative/qml/qmlcompiler_p.h +++ b/src/declarative/qml/qmlcompiler_p.h @@ -279,7 +279,7 @@ private: QmlParser::Property *property; QmlParser::Value *value; - enum DataType { QtScript, BasicScript, Experimental }; + enum DataType { QtScript, Experimental }; DataType dataType; int compiledIndex; diff --git a/src/declarative/qml/qmlcontext.cpp b/src/declarative/qml/qmlcontext.cpp index e7ac864..f97f142 100644 --- a/src/declarative/qml/qmlcontext.cpp +++ b/src/declarative/qml/qmlcontext.cpp @@ -105,8 +105,12 @@ void QmlContextPrivate::destroyed(ContextGuard *guard) if (parent && QObjectPrivate::get(parent)->wasDeleted) return; - while(guard->bindings) + while(guard->bindings) { + QObject *o = guard->bindings->target; + int mi = guard->bindings->methodIndex; guard->bindings->reset(); + if (o) o->qt_metacall(QMetaObject::InvokeMetaMethod, mi, 0); + } for (int ii = 0; ii < idValueCount; ++ii) { if (&idValues[ii] == guard) { diff --git a/src/declarative/qml/qmlcontext.h b/src/declarative/qml/qmlcontext.h index 7547004..bf389a0 100644 --- a/src/declarative/qml/qmlcontext.h +++ b/src/declarative/qml/qmlcontext.h @@ -88,7 +88,6 @@ private: friend class QmlEnginePrivate; friend class QmlExpression; friend class QmlExpressionPrivate; - friend class QmlBasicScript; friend class QmlContextScriptClass; friend class QmlObjectScriptClass; friend class QmlComponent; diff --git a/src/declarative/qml/qmlcontext_p.h b/src/declarative/qml/qmlcontext_p.h index e682ee2..ffb4298 100644 --- a/src/declarative/qml/qmlcontext_p.h +++ b/src/declarative/qml/qmlcontext_p.h @@ -59,6 +59,7 @@ #include "qmlengine_p.h" #include "qmlintegercache_p.h" #include "qmltypenamecache_p.h" +#include "qmlbindingvme_p.h" #include <QtCore/qhash.h> #include <QtScript/qscriptvalue.h> @@ -117,7 +118,7 @@ public: { ContextGuard() : priv(0), bindings(0) {} QmlContextPrivate *priv; - QmlBinding_Id *bindings; + QmlBindingVME::Config::Subscription::Id *bindings; ContextGuard &operator=(QObject *obj) { (QmlGuard<QObject>&)*this = obj; return *this; } diff --git a/src/declarative/qml/qmlengine.cpp b/src/declarative/qml/qmlengine.cpp index 122eb07..5a40468 100644 --- a/src/declarative/qml/qmlengine.cpp +++ b/src/declarative/qml/qmlengine.cpp @@ -46,7 +46,6 @@ #include "qmlcompiler_p.h" #include "qmlglobalscriptclass_p.h" #include "qml.h" -#include "qmlbasicscript_p.h" #include "qmlcontext.h" #include "qmlexpression.h" #include "qmlcomponent.h" diff --git a/src/declarative/qml/qmlexpression.cpp b/src/declarative/qml/qmlexpression.cpp index dcc9c30..3e8d71a 100644 --- a/src/declarative/qml/qmlexpression.cpp +++ b/src/declarative/qml/qmlexpression.cpp @@ -114,52 +114,46 @@ void QmlExpressionPrivate::init(QmlContext *ctxt, void *expr, QmlRefCount *rc, data->line = lineNumber; quint32 *exprData = (quint32 *)expr; - Q_ASSERT(*exprData == BasicScriptEngineData || - *exprData == PreTransformedQtScriptData); - if (*exprData == BasicScriptEngineData) { - data->sse.load((const char *)(exprData + 1), rc); - } else { - QmlCompiledData *dd = (QmlCompiledData *)rc; + QmlCompiledData *dd = (QmlCompiledData *)rc; - data->expressionRewritten = true; - data->expression = QString::fromRawData((QChar *)(exprData + 3), exprData[2]); + data->expressionRewritten = true; + data->expression = QString::fromRawData((QChar *)(exprData + 2), exprData[1]); - int progIdx = *(exprData + 1); - bool isShared = progIdx & 0x80000000; - progIdx &= 0x7FFFFFFF; + int progIdx = *(exprData); + bool isShared = progIdx & 0x80000000; + progIdx &= 0x7FFFFFFF; - QmlEngine *engine = ctxt->engine(); - QmlEnginePrivate *ep = QmlEnginePrivate::get(engine); - QScriptEngine *scriptEngine = QmlEnginePrivate::getScriptEngine(engine); + QmlEngine *engine = ctxt->engine(); + QmlEnginePrivate *ep = QmlEnginePrivate::get(engine); + QScriptEngine *scriptEngine = QmlEnginePrivate::getScriptEngine(engine); - if (isShared) { + if (isShared) { - if (!dd->cachedClosures.at(progIdx)) { - QScriptContext *scriptContext = QScriptDeclarativeClass::pushCleanContext(scriptEngine); - scriptContext->pushScope(ep->contextClass->newSharedContext()); - dd->cachedClosures[progIdx] = new QScriptValue(scriptEngine->evaluate(data->expression, data->url, data->line)); - scriptEngine->popContext(); - } + if (!dd->cachedClosures.at(progIdx)) { + QScriptContext *scriptContext = QScriptDeclarativeClass::pushCleanContext(scriptEngine); + scriptContext->pushScope(ep->contextClass->newSharedContext()); + dd->cachedClosures[progIdx] = new QScriptValue(scriptEngine->evaluate(data->expression, data->url, data->line)); + scriptEngine->popContext(); + } - data->expressionFunction = *dd->cachedClosures.at(progIdx); - data->isShared = true; - data->expressionFunctionValid = true; + data->expressionFunction = *dd->cachedClosures.at(progIdx); + data->isShared = true; + data->expressionFunctionValid = true; - } else { + } else { #if !defined(Q_OS_SYMBIAN) //XXX Why doesn't this work? - if (!dd->cachedPrograms.at(progIdx)) { - dd->cachedPrograms[progIdx] = - new QScriptProgram(data->expression, data->url, data->line); - } + if (!dd->cachedPrograms.at(progIdx)) { + dd->cachedPrograms[progIdx] = + new QScriptProgram(data->expression, data->url, data->line); + } - data->expressionFunction = evalInObjectScope(ctxt, me, *dd->cachedPrograms.at(progIdx)); + data->expressionFunction = evalInObjectScope(ctxt, me, *dd->cachedPrograms.at(progIdx)); #else - data->expressionFunction = evalInObjectScope(ctxt, me, data->expression); + data->expressionFunction = evalInObjectScope(ctxt, me, data->expression); #endif - data->expressionFunctionValid = true; - } + data->expressionFunctionValid = true; } data->QmlAbstractExpression::setContext(ctxt); @@ -272,10 +266,7 @@ QmlContext *QmlExpression::context() const QString QmlExpression::expression() const { Q_D(const QmlExpression); - if (d->data->sse.isValid()) - return QString::fromUtf8(d->data->sse.expression()); - else - return d->data->expression; + return d->data->expression; } /*! @@ -299,19 +290,6 @@ void QmlExpression::setExpression(const QString &expression) d->data->expressionFunctionValid = false; d->data->expressionRewritten = false; d->data->expressionFunction = QScriptValue(); - - d->data->sse.clear(); -} - -QVariant QmlExpressionPrivate::evalSSE() -{ -#ifdef Q_ENABLE_PERFORMANCE_LOG - QmlPerfTimer<QmlPerf::BindValueSSE> perfsse; -#endif - - QVariant rv = data->sse.run(data->context(), data->me); - - return rv; } void QmlExpressionPrivate::exceptionToError(QScriptEngine *scriptEngine, @@ -456,7 +434,7 @@ QVariant QmlExpressionPrivate::value(QObject *secondaryScope, bool *isUndefined) return rv; } - if (!data->sse.isValid() && data->expression.isEmpty()) + if (data->expression.isEmpty()) return rv; #ifdef Q_ENABLE_PERFORMANCE_LOG @@ -477,11 +455,7 @@ QVariant QmlExpressionPrivate::value(QObject *secondaryScope, bool *isUndefined) QmlExpressionData *localData = data; localData->addref(); - if (data->sse.isValid()) { - rv = evalSSE(); - } else { - rv = evalQtScript(secondaryScope, isUndefined); - } + rv = evalQtScript(secondaryScope, isUndefined); ep->currentExpression = lastCurrentExpression; ep->captureProperties = lastCaptureProperties; diff --git a/src/declarative/qml/qmlexpression.h b/src/declarative/qml/qmlexpression.h index cc02d56..4df7641 100644 --- a/src/declarative/qml/qmlexpression.h +++ b/src/declarative/qml/qmlexpression.h @@ -58,7 +58,6 @@ class QmlRefCount; class QmlEngine; class QmlContext; class QmlExpressionPrivate; -class QmlBasicScript; class Q_DECLARATIVE_EXPORT QmlExpression : public QObject { Q_OBJECT diff --git a/src/declarative/qml/qmlexpression_p.h b/src/declarative/qml/qmlexpression_p.h index 5be93f0..1fbb075 100644 --- a/src/declarative/qml/qmlexpression_p.h +++ b/src/declarative/qml/qmlexpression_p.h @@ -55,7 +55,6 @@ #include "qmlexpression.h" -#include "qmlbasicscript_p.h" #include "qmlengine_p.h" #include "qmlguard_p.h" @@ -120,7 +119,6 @@ public: bool expressionRewritten:1; QScriptValue expressionFunction; - QmlBasicScript sse; QObject *me; bool trackChange; @@ -160,18 +158,12 @@ public: QmlExpressionPrivate(QmlExpressionData *); ~QmlExpressionPrivate(); - enum CompiledDataType { - BasicScriptEngineData = 1, - PreTransformedQtScriptData = 2 - }; - void init(QmlContext *, const QString &, QObject *); void init(QmlContext *, void *, QmlRefCount *, QObject *, const QString &, int); QmlExpressionData *data; QVariant value(QObject *secondaryScope = 0, bool *isUndefined = 0); - QVariant evalSSE(); QVariant evalQtScript(QObject *secondaryScope, bool *isUndefined = 0); void updateGuards(const QPODVector<QmlEnginePrivate::CapturedProperty> &properties); diff --git a/src/declarative/qml/qmlinstruction.cpp b/src/declarative/qml/qmlinstruction.cpp index 2ddad49..d99bf65 100644 --- a/src/declarative/qml/qmlinstruction.cpp +++ b/src/declarative/qml/qmlinstruction.cpp @@ -161,9 +161,6 @@ void QmlCompiledData::dump(QmlInstruction *instr, int idx) case QmlInstruction::StoreCompiledBinding: qWarning().nospace() << idx << "\t\t" << line << "\t" << "STORE_COMPILED_BINDING\t" << instr->assignBinding.property << "\t" << instr->assignBinding.value << "\t" << instr->assignBinding.context; break; - case QmlInstruction::StoreIdOptBinding: - qWarning().nospace() << idx << "\t\t" << line << "\t" << "STORE_ID_OPT_BINDING\t" << instr->assignIdOptBinding.property << "\t" << instr->assignIdOptBinding.id; - break; case QmlInstruction::StoreValueSource: qWarning().nospace() << idx << "\t\t" << line << "\t" << "STORE_VALUE_SOURCE\t" << instr->assignValueSource.property << "\t" << instr->assignValueSource.castValue; break; diff --git a/src/declarative/qml/qmlinstruction_p.h b/src/declarative/qml/qmlinstruction_p.h index 44fa196..0639397 100644 --- a/src/declarative/qml/qmlinstruction_p.h +++ b/src/declarative/qml/qmlinstruction_p.h @@ -129,7 +129,6 @@ public: StoreBinding, /* assignBinding */ StoreCompiledBinding, /* assignBinding */ - StoreIdOptBinding, /* assignIdOptBinding */ StoreValueSource, /* assignValueSource */ StoreValueInterceptor, /* assignValueInterceptor */ diff --git a/src/declarative/qml/qmlvme.cpp b/src/declarative/qml/qmlvme.cpp index 06795a8..6b2e7af 100644 --- a/src/declarative/qml/qmlvme.cpp +++ b/src/declarative/qml/qmlvme.cpp @@ -627,23 +627,6 @@ QObject *QmlVME::run(QmlVMEStack<QObject *> &stack, QmlContext *ctxt, } break; - case QmlInstruction::StoreIdOptBinding: - { - int coreIndex = instr.assignIdOptBinding.property; - if (stack.count() == 1 && bindingSkipList.testBit(coreIndex)) - break; - - QObject *target = stack.top(); - - QmlBinding_Id *bind = - new QmlBinding_Id(target, instr.assignIdOptBinding.property, - ctxt, instr.assignIdOptBinding.id); - bindValues.append(bind); - bind->m_mePtr = &bindValues.values[bindValues.count - 1]; - bind->addToObject(target); - } - break; - case QmlInstruction::StoreValueSource: { QObject *obj = stack.pop(); |