From 505b621140c2356ebc5db1da50047222021d5190 Mon Sep 17 00:00:00 2001 From: Aaron Kennedy Date: Tue, 15 Dec 2009 14:34:27 +1000 Subject: Binding optimizer extensions --- src/declarative/qml/qmlbindingvme.cpp | 213 +++++++++++++++++++++++++++------- 1 file changed, 173 insertions(+), 40 deletions(-) diff --git a/src/declarative/qml/qmlbindingvme.cpp b/src/declarative/qml/qmlbindingvme.cpp index 3cadb62..692be68 100644 --- a/src/declarative/qml/qmlbindingvme.cpp +++ b/src/declarative/qml/qmlbindingvme.cpp @@ -66,6 +66,7 @@ struct Register { bool getbool() { return *((bool *)data); } QVariant *getvariantptr() { return (QVariant *)typeDataPtr(); } + QString *getstringptr() { return (QString *)typeDataPtr(); } void *typeDataPtr() { return (void *)&data; } void *typeMemory() { return (void *)data; } @@ -75,6 +76,8 @@ struct Register { struct Instr { enum { + Noop, + Init, // init Subscribe, // subscribe @@ -98,11 +101,18 @@ struct Instr { MinusReal, // binaryop MinusInt, // binaryop + CompareReal, // binaryop + CompareString, // binaryop + + NotCompareReal, // binaryop + NotCompareString, // binaryop + GreaterThanReal, // binaryop NewString, // construct CleanupString, // cleanup + Copy, // copy Fetch, // fetch Store, // store @@ -154,6 +164,10 @@ struct Instr { } fetch; struct { int reg; + int src; + } copy; + struct { + int reg; } construct; struct { int reg; @@ -262,10 +276,12 @@ struct QmlBindingCompiler bool parseConstant(QmlJS::AST::Node *, Result &); bool buildName(QStringList &, QmlJS::AST::Node *); - Result fetch(const QMetaObject *, int reg, int idx, const QStringList &); + bool fetch(Result &type, const QMetaObject *, int reg, int idx, const QStringList &); quint32 registers; - int acquireReg(); + QHash > registerCleanups; + int acquireReg(int cleanup = Instr::Noop, int cleanupType = 0); + void registerCleanup(int reg, int cleanup, int cleanupType = 0); void releaseReg(int); int registerString(const QString &); @@ -372,6 +388,9 @@ static bool findproperty(QObject *obj, const QScriptDeclarativeClass::Identifier &name, bool isTerminal) { + if (!obj) + return false; + QmlPropertyCache::Data local; QmlPropertyCache::Data *property = findproperty(obj, name, enginePriv, local); @@ -576,6 +595,8 @@ void QmlBindingVME::run(const char *programData, Config *config, while (instr) { switch (instr->type) { + case Instr::Noop: + break; case Instr::Init: if (!config->subscriptions && instr->init.subscriptions) config->subscriptions = new Config::Subscription[instr->init.subscriptions]; @@ -660,6 +681,26 @@ void QmlBindingVME::run(const char *programData, Config *config, registers[instr->binaryop.src2].getint()); break; + case Instr::CompareReal: + registers[instr->binaryop.output].setbool(registers[instr->binaryop.src1].getqreal() == + registers[instr->binaryop.src2].getqreal()); + break; + + case Instr::CompareString: + registers[instr->binaryop.output].setbool(*registers[instr->binaryop.src1].getstringptr() == + *registers[instr->binaryop.src2].getstringptr()); + break; + + case Instr::NotCompareReal: + registers[instr->binaryop.output].setbool(registers[instr->binaryop.src1].getqreal() != + registers[instr->binaryop.src2].getqreal()); + break; + + case Instr::NotCompareString: + registers[instr->binaryop.output].setbool(*registers[instr->binaryop.src1].getstringptr() != + *registers[instr->binaryop.src2].getstringptr()); + break; + case Instr::GreaterThanReal: registers[instr->binaryop.output].setbool(registers[instr->binaryop.src1].getqreal() > registers[instr->binaryop.src2].getqreal()); @@ -695,6 +736,10 @@ void QmlBindingVME::run(const char *programData, Config *config, } break; + case Instr::Copy: + registers[instr->copy.reg] = registers[instr->copy.src]; + break; + case Instr::Skip: if (instr->skip.reg == -1 || !registers[instr->skip.reg].getbool()) instr += instr->skip.count; @@ -789,6 +834,9 @@ void QmlBindingVME::dump(const QByteArray &programData) while (count--) { switch (instr->type) { + case Instr::Noop: + qWarning().nospace() << "Noop"; + break; case Instr::Init: qWarning().nospace() << "Init" << "\t\t\t" << instr->init.subscriptions << "\t" << instr->init.identifiers; break; @@ -837,6 +885,18 @@ void QmlBindingVME::dump(const QByteArray &programData) case Instr::MinusInt: qWarning().nospace() << "MinusInt" << "\t\t" << instr->binaryop.output << "\t" << instr->binaryop.src1 << "\t" << instr->binaryop.src2; break; + case Instr::CompareReal: + qWarning().nospace() << "CompareReal" << "\t\t" << instr->binaryop.output << "\t" << instr->binaryop.src1 << "\t" << instr->binaryop.src2; + break; + case Instr::CompareString: + qWarning().nospace() << "CompareString" << "\t\t" << instr->binaryop.output << "\t" << instr->binaryop.src1 << "\t" << instr->binaryop.src2; + break; + case Instr::NotCompareReal: + qWarning().nospace() << "NotCompareReal" << "\t\t" << instr->binaryop.output << "\t" << instr->binaryop.src1 << "\t" << instr->binaryop.src2; + break; + case Instr::NotCompareString: + qWarning().nospace() << "NotCompareString" << "\t\t" << instr->binaryop.output << "\t" << instr->binaryop.src1 << "\t" << instr->binaryop.src2; + break; case Instr::GreaterThanReal: qWarning().nospace() << "GreaterThanReal" << "\t\t" << instr->binaryop.output << "\t" << instr->binaryop.src1 << "\t" << instr->binaryop.src2; break; @@ -852,6 +912,9 @@ void QmlBindingVME::dump(const QByteArray &programData) case Instr::Store: qWarning().nospace() << "Store" << "\t\t\t" << instr->store.output << "\t" << instr->store.index << "\t" << instr->store.reg; break; + case Instr::Copy: + qWarning().nospace() << "Copy" << "\t\t\t" << instr->copy.reg << "\t" << instr->copy.src; + break; case Instr::Skip: qWarning().nospace() << "Skip" << "\t\t\t" << instr->skip.reg << "\t" << instr->skip.count; break; @@ -1018,6 +1081,8 @@ bool QmlBindingCompiler::compile(QmlJS::AST::Node *node) instr.store.reg = type.reg; bytecode << instr; + releaseReg(type.reg); + Instr done; done.type = Instr::Done; bytecode << done; @@ -1178,7 +1243,7 @@ bool QmlBindingCompiler::parseName(AST::Node *node, Result &type) subscribeName << QLatin1String("$$$Scope"); subscribeName << name; - type = fetch(context->metaObject(), reg, d0Idx, subscribeName); + fetch(type, context->metaObject(), reg, d0Idx, subscribeName); } else if(d1Idx != -1) { Instr instr; instr.type = Instr::LoadRoot; @@ -1189,7 +1254,7 @@ bool QmlBindingCompiler::parseName(AST::Node *node, Result &type) subscribeName << QLatin1String("$$$Root"); subscribeName << name; - type = fetch(component->metaObject(), reg, d1Idx, subscribeName); + fetch(type, component->metaObject(), reg, d1Idx, subscribeName); } else { Instr find; if (nameParts.count() == 1) @@ -1249,7 +1314,7 @@ bool QmlBindingCompiler::parseName(AST::Node *node, Result &type) if (absType || (wasAttachedObject && idx != -1) || (mo && mo->property(idx).isFinal())) { absType = 0; - type = fetch(mo, reg, idx, subscribeName); + fetch(type, mo, reg, idx, subscribeName); if (type.type == -1) return false; } else { @@ -1300,6 +1365,8 @@ bool QmlBindingCompiler::parseArith(QmlJS::AST::Node *node, Result &type) { AST::BinaryExpression *expression = static_cast(node); + type.reg = acquireReg(); + Result lhs; Result rhs; @@ -1343,13 +1410,6 @@ bool QmlBindingCompiler::parseArith(QmlJS::AST::Node *node, Result &type) qFatal("Unsupported arithmetic operator"); } - // We release early so we can reuse one of the registers as - // the output - releaseReg(lhs.reg); - releaseReg(rhs.reg); - - type.reg = acquireReg(); - arith.binaryop.output = type.reg; arith.binaryop.src1 = lhs.reg; arith.binaryop.src2 = rhs.reg; @@ -1357,6 +1417,11 @@ bool QmlBindingCompiler::parseArith(QmlJS::AST::Node *node, Result &type) type.metaObject = 0; type.type = nativeReal?QMetaType::QReal:QMetaType::Int; + type.subscriptionSet.unite(lhs.subscriptionSet); + type.subscriptionSet.unite(rhs.subscriptionSet); + + releaseReg(lhs.reg); + releaseReg(rhs.reg); return true; } @@ -1367,7 +1432,9 @@ bool QmlBindingCompiler::tryLogic(QmlJS::AST::Node *node) return false; AST::BinaryExpression *expression = static_cast(node); - if (expression->op == QSOperator::Gt) + if (expression->op == QSOperator::Gt || + expression->op == QSOperator::Equal || + expression->op == QSOperator::NotEqual) return true; else return false; @@ -1383,24 +1450,47 @@ bool QmlBindingCompiler::parseLogic(QmlJS::AST::Node *node, Result &type) if (!parseExpression(expression->left, lhs)) return false; if (!parseExpression(expression->right, rhs)) return false; - if (lhs.type != QMetaType::QReal || rhs.type != QMetaType::QReal) - return false; - - // We release early so we can reuse one of the registers as - // the output - releaseReg(lhs.reg); - releaseReg(rhs.reg); - type.reg = acquireReg(); type.metaObject = 0; type.type = QVariant::Bool; - Instr op; - op.type = Instr::GreaterThanReal; - op.binaryop.output = type.reg; - op.binaryop.src1 = lhs.reg; - op.binaryop.src2 = rhs.reg; - bytecode << op; + if (lhs.type == QMetaType::QReal && rhs.type == QMetaType::QReal) { + + Instr op; + if (expression->op == QSOperator::Gt) + op.type = Instr::GreaterThanReal; + else if (expression->op == QSOperator::Equal) + op.type = Instr::CompareReal; + else if (expression->op == QSOperator::NotEqual) + op.type = Instr::NotCompareReal; + else + return false; + op.binaryop.output = type.reg; + op.binaryop.src1 = lhs.reg; + op.binaryop.src2 = rhs.reg; + bytecode << op; + + + } else if (lhs.type == QMetaType::QString && rhs.type == QMetaType::QString) { + + Instr op; + if (expression->op == QSOperator::Equal) + op.type = Instr::CompareString; + else if (expression->op == QSOperator::NotEqual) + op.type = Instr::NotCompareString; + else + return false; + op.binaryop.output = type.reg; + op.binaryop.src1 = lhs.reg; + op.binaryop.src2 = rhs.reg; + bytecode << op; + + } else { + return false; + } + + releaseReg(lhs.reg); + releaseReg(rhs.reg); return true; } @@ -1535,11 +1625,13 @@ bool QmlBindingCompiler::buildName(QStringList &name, return true; } -QmlBindingCompiler::Result -QmlBindingCompiler::fetch(const QMetaObject *mo, int reg, int idx, const QStringList &subName) + +bool QmlBindingCompiler::fetch(Result &rv, const QMetaObject *mo, int reg, int idx, const QStringList &subName) { QMetaProperty prop = mo->property(idx); - Result rv; + rv.metaObject = 0; + rv.type = 0; + if (subscription(subName, &rv) && prop.hasNotifySignal() && prop.notifySignalIndex() != -1) { Instr sub; sub.type = Instr::Subscribe; @@ -1549,32 +1641,63 @@ QmlBindingCompiler::fetch(const QMetaObject *mo, int reg, int idx, const QString bytecode << sub; } - Instr instr; - instr.type = Instr::Fetch; - instr.fetch.objectReg = reg; - instr.fetch.index = idx; - instr.fetch.output = reg; - bytecode << instr; + Instr fetch; + fetch.type = Instr::Fetch; + fetch.fetch.objectReg = reg; + fetch.fetch.index = idx; + fetch.fetch.output = reg; rv.type = prop.userType(); rv.metaObject = QmlMetaType::metaObjectForType(rv.type); rv.reg = reg; + if (rv.type == QMetaType::QString) { + int tmp = acquireReg(); + Instr copy; + copy.type = Instr::Copy; + copy.copy.reg = tmp; + copy.copy.src = reg; + bytecode << copy; + releaseReg(tmp); + fetch.fetch.objectReg = tmp; + + Instr setup; + setup.type = Instr::NewString; + setup.construct.reg = reg; + bytecode << setup; + registerCleanup(reg, Instr::CleanupString); + } + + bytecode << fetch; + if (!rv.metaObject && rv.type != QMetaType::QReal && rv.type != QMetaType::Int && rv.type != QMetaType::Bool && - rv.type != qMetaTypeId()) - return Result(); // Unsupported type (string not supported yet); + rv.type != qMetaTypeId() && + rv.type != QMetaType::QString) { + rv.metaObject = 0; + rv.type = 0; + return false; // Unsupported type (string not supported yet); + } + + return true; +} - return rv; +void QmlBindingCompiler::registerCleanup(int reg, int cleanup, int cleanupType) +{ + registerCleanups.insert(reg, qMakePair(cleanup, cleanupType)); } -int QmlBindingCompiler::acquireReg() +int QmlBindingCompiler::acquireReg(int cleanup, int cleanupType) { for (int ii = 0; ii < 32; ++ii) { if (!(registers & (1 << ii))) { registers |= (1 << ii); + + if (cleanup != Instr::Noop) + registerCleanup(ii, cleanup, cleanupType); + return ii; } } @@ -1585,6 +1708,16 @@ void QmlBindingCompiler::releaseReg(int reg) { Q_ASSERT(reg >= 0 && reg <= 31); + if (registerCleanups.contains(reg)) { + QPair c = registerCleanups[reg]; + registerCleanups.remove(reg); + Instr cleanup; + (int &)cleanup.type = c.first; + cleanup.cleanup.reg = reg; + cleanup.cleanup.typeReg = c.second; + bytecode << cleanup; + } + quint32 mask = 1 << reg; registers &= ~mask; } -- cgit v0.12