diff options
author | Aaron Kennedy <aaron.kennedy@nokia.com> | 2011-12-21 16:34:36 +0000 |
---|---|---|
committer | Qt by Nokia <qt-info@nokia.com> | 2011-12-21 18:42:48 +0100 |
commit | b6c8497cdf070c8404a1f3784c4ee6df191bd546 (patch) | |
tree | 029a5ce39adbad2c9eb1213e57d38fecdd9e6041 /src/declarative/qml/qdeclarativecompiler.cpp | |
parent | 8249c72213bc7d212c05aa086b3145a5742706a3 (diff) |
Detect and optimize qsTr() and qsTrId() bindings
As these two are frequently used with constants, we can detect them in
the compiler, and run the appropriate C++ functions directly in the VME.
This saves pointlessly creating and running bindings.
Change-Id: I148a150400c13fda7955949453405202f18b1a6b
Reviewed-by: Roberto Raggi <roberto.raggi@nokia.com>
Diffstat (limited to 'src/declarative/qml/qdeclarativecompiler.cpp')
-rw-r--r-- | src/declarative/qml/qdeclarativecompiler.cpp | 173 |
1 files changed, 146 insertions, 27 deletions
diff --git a/src/declarative/qml/qdeclarativecompiler.cpp b/src/declarative/qml/qdeclarativecompiler.cpp index 44f1f5901d..10e64b34df 100644 --- a/src/declarative/qml/qdeclarativecompiler.cpp +++ b/src/declarative/qml/qdeclarativecompiler.cpp @@ -83,6 +83,7 @@ QT_BEGIN_NAMESPACE DEFINE_BOOL_CONFIG_OPTION(compilerDump, QML_COMPILER_DUMP); DEFINE_BOOL_CONFIG_OPTION(compilerStatDump, QML_COMPILER_STATS); +using namespace QDeclarativeJS; using namespace QDeclarativeScript; using namespace QDeclarativeCompilerTypes; @@ -91,13 +92,15 @@ static QString on_string(QLatin1String("on")); static QString Changed_string(QLatin1String("Changed")); static QString Component_string(QLatin1String("Component")); static QString Component_import_string(QLatin1String("QML/Component")); +static QString qsTr_string(QLatin1String("qsTr")); +static QString qsTrId_string(QLatin1String("qsTrId")); /*! Instantiate a new QDeclarativeCompiler. */ QDeclarativeCompiler::QDeclarativeCompiler(QDeclarativePool *pool) : pool(pool), output(0), engine(0), unitRoot(0), unit(0), cachedComponentTypeRef(-1), - componentStats(0) + cachedTranslationContextIndex(-1), componentStats(0) { if (compilerStatDump()) componentStats = pool->New<ComponentStats>(); @@ -832,6 +835,7 @@ bool QDeclarativeCompiler::compile(QDeclarativeEngine *engine, this->enginePrivate = 0; this->unit = 0; this->cachedComponentTypeRef = -1; + this->cachedTranslationContextIndex = -1; this->unitRoot = 0; return !isError(); @@ -1606,6 +1610,20 @@ int QDeclarativeCompiler::componentTypeRef() return cachedComponentTypeRef; } +int QDeclarativeCompiler::translationContextIndex() +{ + if (cachedTranslationContextIndex == -1) { + // This code must match that in the qsTr() implementation + QString path = output->url.toString(); + int lastSlash = path.lastIndexOf(QLatin1Char('/')); + QString context = (lastSlash > -1) ? path.mid(lastSlash + 1, path.length()-lastSlash-5) : + QString(); + QByteArray contextUtf8 = context.toUtf8(); + cachedTranslationContextIndex = output->indexForByteArray(contextUtf8); + } + return cachedTranslationContextIndex; +} + bool QDeclarativeCompiler::buildSignal(QDeclarativeScript::Property *prop, QDeclarativeScript::Object *obj, const BindingContext &ctxt) { @@ -2028,7 +2046,7 @@ void QDeclarativeCompiler::addId(const QString &id, QDeclarativeScript::Object * compileState->ids.append(obj); } -void QDeclarativeCompiler::addBindingReference(BindingReference *ref) +void QDeclarativeCompiler::addBindingReference(JSBindingReference *ref) { Q_ASSERT(ref->value && !ref->value->bindingReference); ref->value->bindingReference = ref; @@ -2185,7 +2203,7 @@ bool QDeclarativeCompiler::buildValueTypeProperty(QObject *type, if (isEnumAssignment) { value->type = Value::Literal; } else { - BindingReference *reference = pool->New<BindingReference>(); + JSBindingReference *reference = pool->New<JSBindingReference>(); reference->expression = value->value; reference->property = prop; reference->value = value; @@ -2456,7 +2474,9 @@ bool QDeclarativeCompiler::buildPropertyLiteralAssignment(QDeclarativeScript::Pr } } - COMPILE_CHECK(buildBinding(v, prop, ctxt)); + // Test for other binding optimizations + if (!buildLiteralBinding(v, prop, ctxt)) + COMPILE_CHECK(buildBinding(v, prop, ctxt)); v->type = Value::PropertyBinding; @@ -3294,7 +3314,7 @@ bool QDeclarativeCompiler::buildBinding(QDeclarativeScript::Value *value, if (!prop->core.isWritable() && !prop->core.isQList() && !prop->isReadOnlyDeclaration) COMPILE_EXCEPTION(prop, tr("Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString())); - BindingReference *reference = pool->New<BindingReference>(); + JSBindingReference *reference = pool->New<JSBindingReference>(); reference->expression = value->value; reference->property = prop; reference->value = value; @@ -3304,6 +3324,79 @@ bool QDeclarativeCompiler::buildBinding(QDeclarativeScript::Value *value, return true; } +bool QDeclarativeCompiler::buildLiteralBinding(QDeclarativeScript::Value *v, + QDeclarativeScript::Property *prop, + const QDeclarativeCompilerTypes::BindingContext &) +{ + Q_ASSERT(v->value.isScript()); + + if (!prop->core.isWritable()) + return false; + + AST::Node *binding = v->value.asAST(); + + if (prop->type == QVariant::String) { + if (AST::CallExpression *e = AST::cast<AST::CallExpression *>(binding)) { + if (AST::IdentifierExpression *i = AST::cast<AST::IdentifierExpression *>(e->base)) { + if (i->name == qsTrId_string) { + AST::ArgumentList *arg1 = e->arguments?e->arguments:0; + AST::ArgumentList *arg2 = arg1?arg1->next:0; + + if (arg1 && arg1->expression->kind == AST::Node::Kind_StringLiteral && + (!arg2 || arg2->expression->kind == AST::Node::Kind_NumericLiteral) && + (!arg2 || !arg2->next)) { + + QStringRef text; + int n = -1; + + text = AST::cast<AST::StringLiteral *>(arg1->expression)->value; + if (arg2) n = (int)AST::cast<AST::NumericLiteral *>(arg2->expression)->value; + + TrBindingReference *reference = pool->New<TrBindingReference>(); + reference->dataType = BindingReference::TrId; + reference->text = text; + reference->n = n; + v->bindingReference = reference; + return true; + } + + } else if (i->name == qsTr_string) { + + AST::ArgumentList *arg1 = e->arguments?e->arguments:0; + AST::ArgumentList *arg2 = arg1?arg1->next:0; + AST::ArgumentList *arg3 = arg2?arg2->next:0; + + if (arg1 && arg1->expression->kind == AST::Node::Kind_StringLiteral && + (!arg2 || arg2->expression->kind == AST::Node::Kind_StringLiteral) && + (!arg3 || arg3->expression->kind == AST::Node::Kind_NumericLiteral) && + (!arg3 || !arg3->next)) { + + QStringRef text; + QStringRef comment; + int n = -1; + + text = AST::cast<AST::StringLiteral *>(arg1->expression)->value; + if (arg2) comment = AST::cast<AST::StringLiteral *>(arg2->expression)->value; + if (arg3) n = (int)AST::cast<AST::NumericLiteral *>(arg3->expression)->value; + + TrBindingReference *reference = pool->New<TrBindingReference>(); + reference->dataType = BindingReference::Tr; + reference->text = text; + reference->comment = comment; + reference->n = n; + v->bindingReference = reference; + return true; + } + + } + } + } + + } + + return false; +} + void QDeclarativeCompiler::genBindingAssignment(QDeclarativeScript::Value *binding, QDeclarativeScript::Property *prop, QDeclarativeScript::Object *obj, @@ -3313,11 +3406,31 @@ void QDeclarativeCompiler::genBindingAssignment(QDeclarativeScript::Value *bindi Q_ASSERT(binding->bindingReference); const BindingReference &ref = *binding->bindingReference; - if (ref.dataType == BindingReference::V4) { + if (ref.dataType == BindingReference::TrId) { + const TrBindingReference &tr = static_cast<const TrBindingReference &>(ref); + + Instruction::StoreTrIdString store; + store.propertyIndex = prop->core.coreIndex; + store.text = output->indexForByteArray(tr.text.toUtf8()); + store.n = tr.n; + output->addInstruction(store); + } else if (ref.dataType == BindingReference::Tr) { + const TrBindingReference &tr = static_cast<const TrBindingReference &>(ref); + + Instruction::StoreTrString store; + store.propertyIndex = prop->core.coreIndex; + store.context = translationContextIndex(); + store.text = output->indexForByteArray(tr.text.toUtf8()); + store.comment = output->indexForByteArray(tr.comment.toUtf8()); + store.n = tr.n; + output->addInstruction(store); + } else if (ref.dataType == BindingReference::V4) { + const JSBindingReference &js = static_cast<const JSBindingReference &>(ref); + Instruction::StoreV4Binding store; - store.value = ref.compiledIndex; - store.context = ref.bindingContext.stack; - store.owner = ref.bindingContext.owner; + store.value = js.compiledIndex; + store.context = js.bindingContext.stack; + store.owner = js.bindingContext.owner; if (valueTypeProperty) { store.property = (valueTypeProperty->index & 0xFFFF) | ((valueTypeProperty->type & 0xFF)) << 16 | @@ -3331,10 +3444,12 @@ void QDeclarativeCompiler::genBindingAssignment(QDeclarativeScript::Value *bindi store.column = binding->location.start.column; output->addInstruction(store); } else if (ref.dataType == BindingReference::V8) { + const JSBindingReference &js = static_cast<const JSBindingReference &>(ref); + Instruction::StoreV8Binding store; - store.value = ref.compiledIndex; - store.context = ref.bindingContext.stack; - store.owner = ref.bindingContext.owner; + store.value = js.compiledIndex; + store.context = js.bindingContext.stack; + store.owner = js.bindingContext.owner; if (valueTypeProperty) { store.isRoot = (compileState->root == valueTypeProperty->parent); } else { @@ -3343,20 +3458,22 @@ void QDeclarativeCompiler::genBindingAssignment(QDeclarativeScript::Value *bindi store.line = binding->location.start.line; store.column = binding->location.start.column; - Q_ASSERT(ref.bindingContext.owner == 0 || - (ref.bindingContext.owner != 0 && valueTypeProperty)); - if (ref.bindingContext.owner) { + Q_ASSERT(js.bindingContext.owner == 0 || + (js.bindingContext.owner != 0 && valueTypeProperty)); + if (js.bindingContext.owner) { store.property = genValueTypeData(prop, valueTypeProperty); } else { store.property = prop->core; } output->addInstruction(store); - } else { + } else if (ref.dataType == BindingReference::QtScript) { + const JSBindingReference &js = static_cast<const JSBindingReference &>(ref); + QDeclarativeInstruction store; - store.assignBinding.value = output->indexForString(ref.rewrittenExpression); - store.assignBinding.context = ref.bindingContext.stack; - store.assignBinding.owner = ref.bindingContext.owner; + store.assignBinding.value = output->indexForString(js.rewrittenExpression); + store.assignBinding.context = js.bindingContext.stack; + store.assignBinding.owner = js.bindingContext.owner; store.assignBinding.line = binding->location.start.line; store.assignBinding.column = binding->location.start.column; @@ -3366,9 +3483,9 @@ void QDeclarativeCompiler::genBindingAssignment(QDeclarativeScript::Value *bindi store.assignBinding.isRoot = (compileState->root == obj); } - Q_ASSERT(ref.bindingContext.owner == 0 || - (ref.bindingContext.owner != 0 && valueTypeProperty)); - if (ref.bindingContext.owner) { + Q_ASSERT(js.bindingContext.owner == 0 || + (js.bindingContext.owner != 0 && valueTypeProperty)); + if (js.bindingContext.owner) { store.assignBinding.property = genValueTypeData(prop, valueTypeProperty); } else { store.assignBinding.property = prop->core; @@ -3377,6 +3494,8 @@ void QDeclarativeCompiler::genBindingAssignment(QDeclarativeScript::Value *bindi !prop->isAlias ? QDeclarativeInstruction::StoreBinding : QDeclarativeInstruction::StoreBindingOnAlias , store); + } else { + Q_ASSERT(!"Unhandled BindingReference::DataType type"); } } @@ -3420,11 +3539,11 @@ bool QDeclarativeCompiler::completeComponentBuild() QV4Compiler bindingCompiler; - QList<BindingReference*> sharedBindings; + QList<JSBindingReference*> sharedBindings; - for (BindingReference *b = compileState->bindings.first(); b; b = b->nextReference) { + for (JSBindingReference *b = compileState->bindings.first(); b; b = b->nextReference) { - BindingReference &binding = *b; + JSBindingReference &binding = *b; // ### We don't currently optimize for bindings on alias's - because // of the solution to QTBUG-13719 @@ -3465,7 +3584,7 @@ bool QDeclarativeCompiler::completeComponentBuild() if (!sharedBindings.isEmpty()) { struct Sort { - static bool lt(const BindingReference *lhs, const BindingReference *rhs) + static bool lt(const JSBindingReference *lhs, const JSBindingReference *rhs) { return lhs->value->location.start.line < rhs->value->location.start.line; } @@ -3478,7 +3597,7 @@ bool QDeclarativeCompiler::completeComponentBuild() QString functionArray(QLatin1String("[")); for (int ii = 0; ii < sharedBindings.count(); ++ii) { - BindingReference *reference = sharedBindings.at(ii); + JSBindingReference *reference = sharedBindings.at(ii); QDeclarativeScript::Value *value = reference->value; const QString &expression = reference->rewrittenExpression; |