aboutsummaryrefslogtreecommitdiffstats
path: root/src/declarative/qml/qdeclarativecompiler.cpp
diff options
context:
space:
mode:
authorAaron Kennedy <aaron.kennedy@nokia.com>2011-12-21 16:34:36 +0000
committerQt by Nokia <qt-info@nokia.com>2011-12-21 18:42:48 +0100
commitb6c8497cdf070c8404a1f3784c4ee6df191bd546 (patch)
tree029a5ce39adbad2c9eb1213e57d38fecdd9e6041 /src/declarative/qml/qdeclarativecompiler.cpp
parent8249c72213bc7d212c05aa086b3145a5742706a3 (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.cpp173
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;