From b6c8497cdf070c8404a1f3784c4ee6df191bd546 Mon Sep 17 00:00:00 2001 From: Aaron Kennedy Date: Wed, 21 Dec 2011 16:34:36 +0000 Subject: 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 --- src/declarative/qml/qdeclarativecompiler.cpp | 173 ++++++++++++++++++++---- src/declarative/qml/qdeclarativecompiler_p.h | 37 +++-- src/declarative/qml/qdeclarativeinstruction.cpp | 6 + src/declarative/qml/qdeclarativeinstruction_p.h | 18 +++ src/declarative/qml/qdeclarativescript.cpp | 2 +- src/declarative/qml/qdeclarativescript_p.h | 6 +- src/declarative/qml/qdeclarativevme.cpp | 8 ++ 7 files changed, 210 insertions(+), 40 deletions(-) (limited to 'src') 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(); @@ -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(); + JSBindingReference *reference = pool->New(); 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(); + JSBindingReference *reference = pool->New(); 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(binding)) { + if (AST::IdentifierExpression *i = AST::cast(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(arg1->expression)->value; + if (arg2) n = (int)AST::cast(arg2->expression)->value; + + TrBindingReference *reference = pool->New(); + 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(arg1->expression)->value; + if (arg2) comment = AST::cast(arg2->expression)->value; + if (arg3) n = (int)AST::cast(arg3->expression)->value; + + TrBindingReference *reference = pool->New(); + 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(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(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(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(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(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 sharedBindings; + QList 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; diff --git a/src/declarative/qml/qdeclarativecompiler_p.h b/src/declarative/qml/qdeclarativecompiler_p.h index 77f5b860dc..c592fd9a63 100644 --- a/src/declarative/qml/qdeclarativecompiler_p.h +++ b/src/declarative/qml/qdeclarativecompiler_p.h @@ -179,23 +179,36 @@ namespace QDeclarativeCompilerTypes { QDeclarativeScript::Object *object; }; - struct BindingReference : public QDeclarativePool::Class + struct BindingReference { - BindingReference() : nextReference(0) {} + enum DataType { QtScript, V4, V8, + Tr, TrId }; + DataType dataType; + }; + + struct JSBindingReference : public QDeclarativePool::Class, + public BindingReference + { + JSBindingReference() : nextReference(0) {} QDeclarativeScript::Variant expression; QDeclarativeScript::Property *property; QDeclarativeScript::Value *value; - enum DataType { QtScript, V4, V8 }; - DataType dataType; - int compiledIndex; QString rewrittenExpression; BindingContext bindingContext; - BindingReference *nextReference; + JSBindingReference *nextReference; + }; + + struct TrBindingReference : public QDeclarativePool::POD, + public BindingReference + { + QStringRef text; + QStringRef comment; + int n; }; struct IdList : public QFieldList BindingReferenceList; - BindingReferenceList bindings; + typedef QDeclarativeCompilerTypes::JSBindingReference B; + typedef QFieldList JSBindingReferenceList; + JSBindingReferenceList bindings; typedef QDeclarativeScript::Object O; typedef QFieldList AliasingObjectsList; AliasingObjectsList aliasingObjects; @@ -347,6 +360,8 @@ private: bool checkDynamicMeta(QDeclarativeScript::Object *obj); bool buildBinding(QDeclarativeScript::Value *, QDeclarativeScript::Property *prop, const QDeclarativeCompilerTypes::BindingContext &ctxt); + bool buildLiteralBinding(QDeclarativeScript::Value *, QDeclarativeScript::Property *prop, + const QDeclarativeCompilerTypes::BindingContext &ctxt); bool buildComponentFromRoot(QDeclarativeScript::Object *obj, const QDeclarativeCompilerTypes::BindingContext &); bool compileAlias(QFastMetaBuilder &, QByteArray &data, @@ -378,6 +393,7 @@ private: QDeclarativeScript::Property *valueTypeProp); int componentTypeRef(); + int translationContextIndex(); static QDeclarativeType *toQmlType(QDeclarativeScript::Object *from); bool canCoerce(int to, QDeclarativeScript::Object *from); @@ -399,7 +415,7 @@ private: void dumpStats(); - void addBindingReference(QDeclarativeCompilerTypes::BindingReference *); + void addBindingReference(QDeclarativeCompilerTypes::JSBindingReference *); QDeclarativeCompilerTypes::ComponentCompileState *compileState; @@ -415,6 +431,7 @@ private: QDeclarativeScript::Object *unitRoot; QDeclarativeTypeData *unit; int cachedComponentTypeRef; + int cachedTranslationContextIndex; // Compiler component statistics. Only collected if QML_COMPILER_STATS=1 struct ComponentStat diff --git a/src/declarative/qml/qdeclarativeinstruction.cpp b/src/declarative/qml/qdeclarativeinstruction.cpp index da5c29069e..720b769fa2 100644 --- a/src/declarative/qml/qdeclarativeinstruction.cpp +++ b/src/declarative/qml/qdeclarativeinstruction.cpp @@ -117,6 +117,12 @@ void QDeclarativeCompiledData::dump(QDeclarativeInstruction *instr, int idx) case QDeclarativeInstruction::StoreStringQList: qWarning().nospace() << idx << "\t\t" << "STORE_STRING_QLIST\t\t" << instr->storeString.propertyIndex << "\t" << instr->storeString.value << "\t\t" << primitives.at(instr->storeString.value); break; + case QDeclarativeInstruction::StoreTrString: + qWarning().nospace() << idx << "\t\t" << "STORE_TR_STRING\t" << instr->storeTrString.propertyIndex << "\t" << instr->storeTrString.context << "\t" << instr->storeTrString.text << "\t" << instr->storeTrString.comment << "\t" << instr->storeTrString.n; + break; + case QDeclarativeInstruction::StoreTrIdString: + qWarning().nospace() << idx << "\t\t" << "STORE_TRID_STRING\t" << instr->storeTrIdString.propertyIndex << "\t" << instr->storeTrIdString.text << "\t" << instr->storeTrIdString.n; + break; case QDeclarativeInstruction::StoreByteArray: qWarning().nospace() << idx << "\t\t" << "STORE_BYTEARRAY" << instr->storeByteArray.propertyIndex << "\t" << instr->storeByteArray.value << "\t\t" << datas.at(instr->storeByteArray.value); break; diff --git a/src/declarative/qml/qdeclarativeinstruction_p.h b/src/declarative/qml/qdeclarativeinstruction_p.h index 6da2fd834f..448b43d1bc 100644 --- a/src/declarative/qml/qdeclarativeinstruction_p.h +++ b/src/declarative/qml/qdeclarativeinstruction_p.h @@ -81,6 +81,8 @@ QT_BEGIN_NAMESPACE F(StoreString, storeString) \ F(StoreStringList, storeString) \ F(StoreStringQList, storeString) \ + F(StoreTrString, storeTrString) \ + F(StoreTrIdString, storeTrIdString) \ F(StoreByteArray, storeByteArray) \ F(StoreUrl, storeUrl) \ F(StoreUrlQList, storeUrl) \ @@ -298,6 +300,20 @@ union QDeclarativeInstruction int propertyIndex; int value; }; + struct instr_storeTrString { + QML_INSTR_HEADER + int propertyIndex; + int context; + int text; + int comment; + int n; + }; + struct instr_storeTrIdString { + QML_INSTR_HEADER + int propertyIndex; + int text; + int n; + }; struct instr_storeByteArray { QML_INSTR_HEADER int propertyIndex; @@ -494,6 +510,8 @@ union QDeclarativeInstruction instr_storeInteger storeInteger; instr_storeBool storeBool; instr_storeString storeString; + instr_storeTrString storeTrString; + instr_storeTrIdString storeTrIdString; instr_storeByteArray storeByteArray; instr_storeScriptString storeScriptString; instr_storeScript storeScript; diff --git a/src/declarative/qml/qdeclarativescript.cpp b/src/declarative/qml/qdeclarativescript.cpp index 9d18cb3889..7d0b543504 100644 --- a/src/declarative/qml/qdeclarativescript.cpp +++ b/src/declarative/qml/qdeclarativescript.cpp @@ -252,7 +252,7 @@ bool QDeclarativeScript::Property::isEmpty() const } QDeclarativeScript::Value::Value() -: type(Unknown), object(0), bindingReference(0), signalExpressionContextStack(0), nextValue(0) +: type(Unknown), object(0), bindingReference(0), nextValue(0) { } diff --git a/src/declarative/qml/qdeclarativescript_p.h b/src/declarative/qml/qdeclarativescript_p.h index a83cd9f8f0..9b54177cd6 100644 --- a/src/declarative/qml/qdeclarativescript_p.h +++ b/src/declarative/qml/qdeclarativescript_p.h @@ -223,8 +223,10 @@ public: LocationSpan location; // Used by compiler - QDeclarativeCompilerTypes::BindingReference *bindingReference; - int signalExpressionContextStack; + union { + QDeclarativeCompilerTypes::BindingReference *bindingReference; + int signalExpressionContextStack; + }; // Used in Property::ValueList lists Value *nextValue; diff --git a/src/declarative/qml/qdeclarativevme.cpp b/src/declarative/qml/qdeclarativevme.cpp index 4f4e57c8d2..db0a57c83d 100644 --- a/src/declarative/qml/qdeclarativevme.cpp +++ b/src/declarative/qml/qdeclarativevme.cpp @@ -381,6 +381,13 @@ QObject *QDeclarativeVME::run(QList *errors, QML_STORE_POINTER(StoreString, &PRIMITIVES.at(instr.value)); QML_STORE_POINTER(StoreByteArray, &DATAS.at(instr.value)); QML_STORE_POINTER(StoreUrl, &URLS.at(instr.value)); + QML_STORE_VALUE(StoreTrString, QString, + QCoreApplication::translate(DATAS.at(instr.context).constData(), + DATAS.at(instr.text).constData(), + DATAS.at(instr.comment).constData(), + QCoreApplication::UnicodeUTF8, + instr.n)); + QML_STORE_VALUE(StoreTrIdString, QString, qtTrId(DATAS.at(instr.text).constData(), instr.n)); // Store a literal value in a QList QML_STORE_LIST(StoreStringList, QStringList, PRIMITIVES.at(instr.value)); @@ -403,6 +410,7 @@ QObject *QDeclarativeVME::run(QList *errors, QML_STORE_VAR(StoreVarDouble, v8::Number::New(instr.value)); QML_STORE_VAR(StoreVarBool, v8::Boolean::New(instr.value)); + QML_BEGIN_INSTR(Init) // Ensure that the compiled data has been initialized if (!COMP->isInitialized()) COMP->initialize(engine); -- cgit v1.2.3