diff options
author | Aaron Kennedy <aaron.kennedy@nokia.com> | 2009-12-14 08:39:45 (GMT) |
---|---|---|
committer | Aaron Kennedy <aaron.kennedy@nokia.com> | 2009-12-14 08:39:45 (GMT) |
commit | af688178ed2cbfeb72cd43205178e9f797ffefdc (patch) | |
tree | 17637ad2b7c2e712e9f3f0cfecdbdeaf78525675 | |
parent | 6a99fc240fc0644065d775d7f764792bdf6ee717 (diff) | |
download | Qt-af688178ed2cbfeb72cd43205178e9f797ffefdc.zip Qt-af688178ed2cbfeb72cd43205178e9f797ffefdc.tar.gz Qt-af688178ed2cbfeb72cd43205178e9f797ffefdc.tar.bz2 |
Binding optimizer extensions
-rw-r--r-- | src/declarative/qml/qmlbasicscript_p.h | 2 | ||||
-rw-r--r-- | src/declarative/qml/qmlbindingvme.cpp | 177 | ||||
-rw-r--r-- | src/declarative/qml/qmlbindingvme_p.h | 2 | ||||
-rw-r--r-- | src/declarative/qml/qmlcompiler.cpp | 4 | ||||
-rw-r--r-- | src/declarative/qml/qmlengine_p.h | 2 |
5 files changed, 161 insertions, 26 deletions
diff --git a/src/declarative/qml/qmlbasicscript_p.h b/src/declarative/qml/qmlbasicscript_p.h index 830d2bd..3af09c2 100644 --- a/src/declarative/qml/qmlbasicscript_p.h +++ b/src/declarative/qml/qmlbasicscript_p.h @@ -54,6 +54,7 @@ // #include "qmlparser_p.h" +#include "qmlengine_p.h" #include <QtCore/QList> #include <QtCore/QByteArray> @@ -88,6 +89,7 @@ public: QmlParser::Property *property; QmlParser::Variant expression; QHash<QString, QmlParser::Object *> ids; + QmlEnginePrivate::Imports imports; }; bool compile(const Expression &); diff --git a/src/declarative/qml/qmlbindingvme.cpp b/src/declarative/qml/qmlbindingvme.cpp index 26dd303..3cadb62 100644 --- a/src/declarative/qml/qmlbindingvme.cpp +++ b/src/declarative/qml/qmlbindingvme.cpp @@ -83,6 +83,7 @@ struct Instr { LoadId, // load LoadScope, // load LoadRoot, // load + LoadAttached, // attached ConvertIntToReal, // unaryop ConvertRealToInt, // unaryop @@ -117,6 +118,7 @@ struct Instr { FindPropertyTerminal, // find CleanupGeneric, // cleanup ConvertGenericToReal, // genericunaryop + ConvertGenericToBool, // genericunaryop ConvertGenericToString, // genericunaryop } type; @@ -137,8 +139,13 @@ struct Instr { } load; struct { int output; + int reg; int index; + } attached; + struct { + int output; int reg; + int index; } store; struct { int output; @@ -221,6 +228,8 @@ struct QmlBindingCompiler const QMetaObject *metaObject; int type; int reg; + + QSet<QString> subscriptionSet; }; QmlBindingCompiler() : registers(0), strings(0) {} @@ -230,6 +239,8 @@ struct QmlBindingCompiler QmlParser::Object *component; QmlParser::Property *destination; QHash<QString, QmlParser::Object *> ids; + QmlEnginePrivate::Imports imports; + QmlEnginePrivate *engine; bool compile(QmlJS::AST::Node *); @@ -262,11 +273,14 @@ struct QmlBindingCompiler QByteArray data; QSet<QString> subscriptionSet; - bool subscription(const QStringList &); + QHash<QString, int> subscriptionIds; + bool subscription(const QStringList &, Result *); + int subscriptionIndex(const QStringList &); + bool subscriptionNeutral(const QSet<QString> &base, const QSet<QString> &lhs, const QSet<QString> &rhs); QVector<Instr> bytecode; }; -QByteArray QmlBindingVME::compile(const QmlBasicScript::Expression &expression) +QByteArray QmlBindingVME::compile(const QmlBasicScript::Expression &expression, QmlEnginePrivate *engine) { if (!expression.expression.asAST()) return false; @@ -275,6 +289,8 @@ QByteArray QmlBindingVME::compile(const QmlBasicScript::Expression &expression) bsc.component = expression.component; bsc.destination = expression.property; bsc.ids = expression.ids; + bsc.imports = expression.imports; + bsc.engine = engine; bool ok = bsc.compile(expression.expression.asAST()); @@ -475,7 +491,7 @@ static bool findgeneric(Register *output, // val } -// Conversion functions +// Conversion functions - these MUST match the QtScript expression path inline static qreal toReal(Register *reg, int type, bool *ok = 0) { if (ok) *ok = true; @@ -595,6 +611,15 @@ void QmlBindingVME::run(const char *programData, Config *config, registers[instr->load.reg].setQObject(context->defaultObjects.at(0)); break; + case Instr::LoadAttached: + { + QObject *o = qmlAttachedPropertiesObjectById(instr->attached.index, + registers[instr->attached.reg].getQObject(), + true); + registers[instr->attached.output].setQObject(o); + } + break; + case Instr::ConvertIntToReal: registers[instr->unaryop.output].setqreal(qreal(registers[instr->unaryop.src].getint())); break; @@ -730,6 +755,13 @@ void QmlBindingVME::run(const char *programData, Config *config, } break; + case Instr::ConvertGenericToBool: + { + int type = registers[instr->genericunaryop.srcType].getint(); + registers[instr->genericunaryop.output].setbool(toBool(registers + instr->genericunaryop.src, type)); + } + break; + case Instr::ConvertGenericToString: { int type = registers[instr->genericunaryop.srcType].getint(); @@ -775,6 +807,9 @@ void QmlBindingVME::dump(const QByteArray &programData) case Instr::LoadRoot: qWarning().nospace() << "LoadRoot" << "\t\t" << instr->load.index << "\t" << instr->load.reg; break; + case Instr::LoadAttached: + qWarning().nospace() << "LoadAttached" << "\t\t" << instr->attached.output << "\t" << instr->attached.reg << "\t" << instr->attached.index; + break; case Instr::ConvertIntToReal: qWarning().nospace() << "ConvertIntToReal" << "\t" << instr->unaryop.output << "\t" << instr->unaryop.src; break; @@ -836,7 +871,7 @@ void QmlBindingVME::dump(const QByteArray &programData) qWarning().nospace() << "FindProperty" << "\t\t" << instr->find.reg << "\t" << instr->find.src << "\t" << instr->find.typeReg << "\t" << instr->find.name; break; case Instr::FindPropertyTerminal: - qWarning().nospace() << "FindPropertyTerminal" << "\t\t" << instr->find.reg << "\t" << instr->find.src << "\t" << instr->find.typeReg << "\t" << instr->find.name; + qWarning().nospace() << "FindPropertyTerminal" << "\t" << instr->find.reg << "\t" << instr->find.src << "\t" << instr->find.typeReg << "\t" << instr->find.name; break; case Instr::CleanupGeneric: qWarning().nospace() << "CleanupGeneric" << "\t\t" << instr->cleanup.reg << "\t" << instr->cleanup.typeReg; @@ -844,6 +879,9 @@ void QmlBindingVME::dump(const QByteArray &programData) case Instr::ConvertGenericToReal: qWarning().nospace() << "ConvertGenericToReal" << "\t" << instr->genericunaryop.output << "\t" << instr->genericunaryop.src << "\t" << instr->genericunaryop.srcType; break; + case Instr::ConvertGenericToBool: + qWarning().nospace() << "ConvertGenericToBool" << "\t" << instr->genericunaryop.output << "\t" << instr->genericunaryop.src << "\t" << instr->genericunaryop.srcType; + break; case Instr::ConvertGenericToString: qWarning().nospace() << "ConvertGenericToString" << "\t" << instr->genericunaryop.output << "\t" << instr->genericunaryop.src << "\t" << instr->genericunaryop.srcType; break; @@ -881,14 +919,15 @@ bool QmlBindingCompiler::compile(QmlJS::AST::Node *node) Instr init; init.type = Instr::Init; - init.init.subscriptions = subscriptionSet.count(); + init.init.subscriptions = subscriptionIds.count(); init.init.identifiers = strings; bytecode.prepend(init); } if (type.unknownType) { if (destination->type != QMetaType::QReal && - destination->type != QVariant::String) + destination->type != QVariant::String && + destination->type != QMetaType::Bool) return false; int convertReg = acquireReg(); @@ -907,6 +946,13 @@ bool QmlBindingCompiler::compile(QmlJS::AST::Node *node) convert.genericunaryop.src = type.reg; convert.genericunaryop.srcType = 2; // XXX bytecode << convert; + } else if (destination->type == QMetaType::Bool) { + Instr convert; + convert.type = Instr::ConvertGenericToBool; + convert.genericunaryop.output = convertReg; + convert.genericunaryop.src = type.reg; + convert.genericunaryop.srcType = 2; // XXX + bytecode << convert; } Instr cleanup; @@ -1025,6 +1071,8 @@ bool QmlBindingCompiler::parseName(AST::Node *node, Result &type) QStringList subscribeName; + bool wasAttachedObject = false; + for (int ii = 0; ii < nameParts.count(); ++ii) { const QString &name = nameParts.at(ii); @@ -1032,13 +1080,47 @@ bool QmlBindingCompiler::parseName(AST::Node *node, Result &type) if (name.length() > 2 && name.startsWith(QLatin1String("on")) && name.at(2).isUpper()) return false; - if (name.at(0).isUpper()) - return false; + QmlType *attachType = 0; + if (name.at(0).isUpper()) { + // Could be an attached property + if (ii == nameParts.count() - 1) + return false; + if (nameParts.at(ii + 1).at(0).isUpper()) + return false; + + QmlEnginePrivate::ImportedNamespace *ns = 0; + if (!engine->resolveType(imports, name.toUtf8(), &attachType, 0, 0, 0, &ns)) + return false; + if (ns || !attachType || !attachType->attachedPropertiesType()) + return false; + + wasAttachedObject = true; + } if (ii == 0) { - if (ids.contains(name)) { + if (attachType) { + Instr instr; + instr.type = Instr::LoadScope; + instr.load.index = 0; + instr.load.reg = reg; + bytecode << instr; + + Instr attach; + attach.type = Instr::LoadAttached; + attach.attached.output = reg; + attach.attached.reg = reg; + attach.attached.index = attachType->index(); + bytecode << attach; + + absType = 0; + type.metaObject = attachType->attachedPropertiesType(); + + subscribeName << QLatin1String("$$$ATTACH_") + name; + + continue; + } else if (ids.contains(name)) { QmlParser::Object *idObject = ids.value(name); absType = idObject; type.metaObject = absType->metaObject(); @@ -1066,10 +1148,10 @@ bool QmlBindingCompiler::parseName(AST::Node *node, Result &type) subscribeName << QLatin1String("$$$ID_") + name; - if (subscription(subscribeName)) { + if (subscription(subscribeName, &type)) { Instr sub; sub.type = Instr::SubscribeId; - sub.subscribe.offset = subscriptionSet.count() - 1; + sub.subscribe.offset = subscriptionIndex(subscribeName); sub.subscribe.reg = reg; sub.subscribe.index = instr.load.index; bytecode << sub; @@ -1121,8 +1203,8 @@ bool QmlBindingCompiler::parseName(AST::Node *node, Result &type) find.find.name = registerString(name); subscribeName << QString(QLatin1String("$$$Generic_") + name); - if (subscription(subscribeName)) - find.find.subscribeIndex = subscriptionSet.count() - 1; + if (subscription(subscribeName, &type)) + find.find.subscribeIndex = subscriptionIndex(subscribeName); else find.find.subscribeIndex = -1; @@ -1136,6 +1218,21 @@ bool QmlBindingCompiler::parseName(AST::Node *node, Result &type) } else { + if (attachType) { + Instr attach; + attach.type = Instr::LoadAttached; + attach.attached.output = reg; + attach.attached.reg = reg; + attach.attached.index = attachType->index(); + bytecode << attach; + + absType = 0; + type.metaObject = attachType->attachedPropertiesType(); + + subscribeName << QLatin1String("$$$ATTACH_") + name; + continue; + } + const QMetaObject *mo = 0; if (absType) mo = absType->metaObject(); @@ -1150,7 +1247,7 @@ bool QmlBindingCompiler::parseName(AST::Node *node, Result &type) subscribeName << name; - if (absType || (mo && mo->property(idx).isFinal())) { + if (absType || (wasAttachedObject && idx != -1) || (mo && mo->property(idx).isFinal())) { absType = 0; type = fetch(mo, reg, idx, subscribeName); if (type.type == -1) @@ -1167,8 +1264,8 @@ bool QmlBindingCompiler::parseName(AST::Node *node, Result &type) prop.find.src = reg; prop.find.typeReg = 2; // XXX prop.find.name = registerString(name); - if (subscription(subscribeName)) - prop.find.subscribeIndex = subscriptionSet.count() - 1; + if (subscription(subscribeName, &type)) + prop.find.subscribeIndex = subscriptionIndex(subscribeName); else prop.find.subscribeIndex = -1; @@ -1179,6 +1276,8 @@ bool QmlBindingCompiler::parseName(AST::Node *node, Result &type) bytecode << prop; } } + + wasAttachedObject = false; } return true; @@ -1335,7 +1434,9 @@ bool QmlBindingCompiler::parseConditional(QmlJS::AST::Node *node, Result &type) // Release to allow reuse of reg releaseReg(etype.reg); - int preConditionalSubscriptions = subscriptionSet.count(); + QSet<QString> preSubSet = subscriptionSet; + + // int preConditionalSubscriptions = subscriptionSet.count(); Result ok; if (!parseExpression(expression->ok, ok)) return false; @@ -1349,6 +1450,8 @@ bool QmlBindingCompiler::parseConditional(QmlJS::AST::Node *node, Result &type) releaseReg(ok.reg); bytecode[skipIdx].skip.count = bytecode.count() - skipIdx - 1; + subscriptionSet = preSubSet; + Result ko; if (!parseExpression(expression->ko, ko)) return false; if (ko.unknownType) return false; @@ -1360,7 +1463,9 @@ bool QmlBindingCompiler::parseConditional(QmlJS::AST::Node *node, Result &type) if (ok != ko) return false; // Must be same type and in same register - if (preConditionalSubscriptions != subscriptionSet.count()) + subscriptionSet = preSubSet; + + if (!subscriptionNeutral(subscriptionSet, ok.subscriptionSet, ko.subscriptionSet)) return false; // Conditionals cannot introduce new subscriptions type = ok; @@ -1434,10 +1539,11 @@ QmlBindingCompiler::Result QmlBindingCompiler::fetch(const QMetaObject *mo, int reg, int idx, const QStringList &subName) { QMetaProperty prop = mo->property(idx); - if (subscription(subName) && prop.hasNotifySignal() && prop.notifySignalIndex() != -1) { + Result rv; + if (subscription(subName, &rv) && prop.hasNotifySignal() && prop.notifySignalIndex() != -1) { Instr sub; sub.type = Instr::Subscribe; - sub.subscribe.offset = subscriptionSet.count() - 1; + sub.subscribe.offset = subscriptionIndex(subName); sub.subscribe.reg = reg; sub.subscribe.index = prop.notifySignalIndex(); bytecode << sub; @@ -1450,7 +1556,6 @@ QmlBindingCompiler::fetch(const QMetaObject *mo, int reg, int idx, const QString instr.fetch.output = reg; bytecode << instr; - Result rv; rv.type = prop.userType(); rv.metaObject = QmlMetaType::metaObjectForType(rv.type); rv.reg = reg; @@ -1503,9 +1608,10 @@ int QmlBindingCompiler::registerString(const QString &string) return strings - 1; } -bool QmlBindingCompiler::subscription(const QStringList &sub) +bool QmlBindingCompiler::subscription(const QStringList &sub, Result *result) { QString str = sub.join(QLatin1String(".")); + result->subscriptionSet.insert(str); if (subscriptionSet.contains(str)) { return false; @@ -1515,5 +1621,32 @@ bool QmlBindingCompiler::subscription(const QStringList &sub) } } +int QmlBindingCompiler::subscriptionIndex(const QStringList &sub) +{ + QString str = sub.join(QLatin1String(".")); + QHash<QString, int>::ConstIterator iter = subscriptionIds.find(str); + if (iter == subscriptionIds.end()) + iter = subscriptionIds.insert(str, subscriptionIds.count()); + return *iter; +} + +/* + Returns true if lhs contains no subscriptions that aren't also in base or rhs AND + rhs contains no subscriptions that aren't also in base or lhs. +*/ +bool QmlBindingCompiler::subscriptionNeutral(const QSet<QString> &base, + const QSet<QString> &lhs, + const QSet<QString> &rhs) +{ + QSet<QString> difflhs = lhs; + difflhs.subtract(rhs); + QSet<QString> diffrhs = rhs; + diffrhs.subtract(lhs); + + difflhs.unite(diffrhs); + difflhs.subtract(base); + + return difflhs.isEmpty(); +} QT_END_NAMESPACE diff --git a/src/declarative/qml/qmlbindingvme_p.h b/src/declarative/qml/qmlbindingvme_p.h index 9a0239d..a01c308 100644 --- a/src/declarative/qml/qmlbindingvme_p.h +++ b/src/declarative/qml/qmlbindingvme_p.h @@ -80,7 +80,7 @@ public: QScriptDeclarativeClass::PersistentIdentifier *identifiers; }; - static QByteArray compile(const QmlBasicScript::Expression &); + static QByteArray compile(const QmlBasicScript::Expression &, QmlEnginePrivate *); static void run(const char *program, Config *config, QmlContextPrivate *context, QObject **scopes, QObject **outputs); diff --git a/src/declarative/qml/qmlcompiler.cpp b/src/declarative/qml/qmlcompiler.cpp index fa7da95..34608d6 100644 --- a/src/declarative/qml/qmlcompiler.cpp +++ b/src/declarative/qml/qmlcompiler.cpp @@ -2536,12 +2536,13 @@ bool QmlCompiler::completeComponentBuild() 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() && !bs.isSingleContextProperty()))) { - QByteArray qmvdata = QmlBindingVME::compile(expr); + QByteArray qmvdata = QmlBindingVME::compile(expr, QmlEnginePrivate::get(engine)); if (!qmvdata.isEmpty()) { qWarning() << expr.expression.asScript(); QmlBindingVME::dump(qmvdata); @@ -2566,6 +2567,7 @@ bool QmlCompiler::completeComponentBuild() // Pre-rewrite the expression QString expression = binding.expression.asScript(); + qWarning() << "Unoptimized" << expression; // ### Optimize QmlRewrite::SharedBindingTester sharableTest; diff --git a/src/declarative/qml/qmlengine_p.h b/src/declarative/qml/qmlengine_p.h index 1d83d0f..c3db6cf 100644 --- a/src/declarative/qml/qmlengine_p.h +++ b/src/declarative/qml/qmlengine_p.h @@ -59,7 +59,6 @@ #include "qmlcompositetypemanager_p.h" #include "qpodvector_p.h" #include "qml.h" -#include "qmlbasicscript_p.h" #include "qmlvaluetype_p.h" #include "qmlcontext.h" #include "qmlexpression.h" @@ -86,7 +85,6 @@ class QmlContext; class QmlEngine; class QmlContextPrivate; class QmlExpression; -class QmlBasicScriptNodeCache; class QmlContextScriptClass; class QmlObjectScriptClass; class QmlTypeNameScriptClass; |