diff options
Diffstat (limited to 'src/declarative/qml/qmlcompiler.cpp')
-rw-r--r-- | src/declarative/qml/qmlcompiler.cpp | 345 |
1 files changed, 182 insertions, 163 deletions
diff --git a/src/declarative/qml/qmlcompiler.cpp b/src/declarative/qml/qmlcompiler.cpp index cce8109..3029934 100644 --- a/src/declarative/qml/qmlcompiler.cpp +++ b/src/declarative/qml/qmlcompiler.cpp @@ -46,7 +46,7 @@ #include <qmlpropertyvaluesource.h> #include <qmlcomponent.h> #include "private/qmetaobjectbuilder_p.h" -#include <qmlbasicscript.h> +#include "qmlbasicscript_p.h" #include <QColor> #include <QDebug> #include <QPointF> @@ -62,6 +62,7 @@ #include "private/qmlcustomparser_p_p.h" #include <private/qmlcontext_p.h> #include <private/qmlcomponent_p.h> +#include "parser/javascriptast_p.h" #include "qmlscriptparser_p.h" @@ -516,6 +517,7 @@ bool QmlCompiler::compile(QmlEngine *engine, } output = 0; + return !isError(); } @@ -542,7 +544,7 @@ void QmlCompiler::compileTree(Object *tree) def.type = QmlInstruction::SetDefault; output->bytecode << def; - optimizeExpressions(0, output->bytecode.count() - 1, 0); + finalizeComponent(0); } bool QmlCompiler::compileObject(Object *obj, int ctxt) @@ -588,6 +590,8 @@ bool QmlCompiler::compileObject(Object *obj, int ctxt) begin.begin.castValue = parserStatusCast; begin.line = obj->location.start.line; output->bytecode << begin; + + compileState.parserStatusCount++; } // Check if this is a custom parser type. Custom parser types allow @@ -688,9 +692,14 @@ bool QmlCompiler::compileComponent(Object *obj, int ctxt) if (!isValidId(val)) COMPILE_EXCEPTION("Invalid id property value"); - if (ids.contains(val)) + if (compileState.ids.contains(val)) COMPILE_EXCEPTION("id is not unique"); - ids.insert(val); + + IdReference reference; + reference.id = val; + reference.object = obj; + reference.instructionIdx = output->bytecode.count(); + compileState.ids.insert(val, reference); int pref = output->indexForString(val); QmlInstruction id; @@ -699,8 +708,6 @@ bool QmlCompiler::compileComponent(Object *obj, int ctxt) id.setId.value = pref; id.setId.save = -1; - savedTypes.insert(output->bytecode.count(), -1); - output->bytecode << id; } @@ -724,16 +731,14 @@ bool QmlCompiler::compileComponentFromRoot(Object *obj, int ctxt) init.line = obj->location.start.line; output->bytecode << init; - QSet<QString> oldIds = ids; - ids.clear(); + ComponentCompileState oldComponentCompileState = compileState; + compileState = ComponentCompileState(); if (obj) COMPILE_CHECK(compileObject(obj, ctxt)); - ids = oldIds; + finalizeComponent(count); create.createComponent.count = output->bytecode.count() - count; - - int inc = optimizeExpressions(count, count - 1 + create.createComponent.count, count); - create.createComponent.count += inc; + compileState = oldComponentCompileState; return true; } @@ -914,7 +919,7 @@ bool QmlCompiler::compileProperty(Property *prop, Object *obj, int ctxt) } else if (isAttachedPropertyName(prop->name)) { - COMPILE_CHECK(compileAttachedProperty(prop, obj, ctxt)); + COMPILE_CHECK(compileAttachedProperty(prop, ctxt)); } else if (prop->index == -1) { @@ -950,41 +955,43 @@ bool QmlCompiler::compileIdProperty(QmlParser::Property *prop, if (prop->values.count() > 1) COMPILE_EXCEPTION2(prop, "The object id may only be set once"); - if (prop->values.count() == 1) { - if (prop->values.at(0)->object) - COMPILE_EXCEPTION("Cannot assign an object as an id"); - QString val = prop->values.at(0)->primitive(); - if (!isValidId(val)) - COMPILE_EXCEPTION(val << "is not a valid id"); - if (ids.contains(val)) - COMPILE_EXCEPTION("id is not unique"); - ids.insert(val); + if (prop->values.at(0)->object) + COMPILE_EXCEPTION("Cannot assign an object as an id"); + QString val = prop->values.at(0)->primitive(); + if (!isValidId(val)) + COMPILE_EXCEPTION(val << "is not a valid id"); + if (compileState.ids.contains(val)) + COMPILE_EXCEPTION("id is not unique"); - int pref = output->indexForString(val); + int pref = output->indexForString(val); - if (prop->type == QVariant::String) { - QmlInstruction assign; - assign.type = QmlInstruction::StoreString; - assign.storeString.propertyIndex = prop->index; - assign.storeString.value = pref; - assign.line = prop->values.at(0)->location.start.line; - output->bytecode << assign; + if (prop->type == QVariant::String) { + QmlInstruction assign; + assign.type = QmlInstruction::StoreString; + assign.storeString.propertyIndex = prop->index; + assign.storeString.value = pref; + assign.line = prop->values.at(0)->location.start.line; + output->bytecode << assign; - prop->values.at(0)->type = Value::Id; - } else { - prop->values.at(0)->type = Value::Literal; - } + prop->values.at(0)->type = Value::Id; + } else { + prop->values.at(0)->type = Value::Literal; + } - QmlInstruction id; - id.type = QmlInstruction::SetId; - id.line = prop->values.at(0)->location.start.line; - id.setId.value = pref; - id.setId.save = -1; - savedTypes.insert(output->bytecode.count(), obj->type); - output->bytecode << id; + IdReference reference; + reference.id = val; + reference.object = obj; + reference.instructionIdx = output->bytecode.count(); + compileState.ids.insert(val, reference); - obj->id = val.toLatin1(); - } + QmlInstruction id; + id.type = QmlInstruction::SetId; + id.line = prop->values.at(0)->location.start.line; + id.setId.value = pref; + id.setId.save = -1; + output->bytecode << id; + + obj->id = val.toLatin1(); return true; } @@ -995,7 +1002,6 @@ bool QmlCompiler::compileIdProperty(QmlParser::Property *prop, // } // GridView is an attached property object. bool QmlCompiler::compileAttachedProperty(QmlParser::Property *prop, - QmlParser::Object *obj, int ctxt) { Q_ASSERT(prop->value); @@ -1117,9 +1123,7 @@ bool QmlCompiler::compileListProperty(QmlParser::Property *prop, COMPILE_EXCEPTION("Can only assign one binding to lists"); assignedBinding = true; - COMPILE_CHECK(compileBinding(v->value.asScript(), prop, ctxt, - obj->metaObject(), - v->location.start.line)); + COMPILE_CHECK(compileBinding(v, prop, ctxt)); v->type = Value::PropertyBinding; } else { COMPILE_EXCEPTION("Cannot assign primitives to lists"); @@ -1158,7 +1162,7 @@ bool QmlCompiler::compilePropertyAssignment(QmlParser::Property *prop, Value *v = prop->values.at(ii); if (v->object) { - COMPILE_CHECK(compilePropertyObjectAssignment(prop, obj, v, ctxt)); + COMPILE_CHECK(compilePropertyObjectAssignment(prop, v, ctxt)); } else { @@ -1172,7 +1176,6 @@ bool QmlCompiler::compilePropertyAssignment(QmlParser::Property *prop, // Compile assigning a single object instance to a regular property bool QmlCompiler::compilePropertyObjectAssignment(QmlParser::Property *prop, - QmlParser::Object *obj, QmlParser::Value *v, int ctxt) { @@ -1289,9 +1292,7 @@ bool QmlCompiler::compilePropertyLiteralAssignment(QmlParser::Property *prop, if (v->value.isScript()) { - COMPILE_CHECK(compileBinding(v->value.asScript(), prop, ctxt, - obj->metaObject(), - v->location.start.line)); + COMPILE_CHECK(compileBinding(v, prop, ctxt)); v->type = Value::PropertyBinding; @@ -1396,145 +1397,163 @@ bool QmlCompiler::compileDynamicMeta(QmlParser::Object *obj) return true; } -bool QmlCompiler::compileBinding(const QString &bind, QmlParser::Property *prop, - int ctxt, const QMetaObject *mo, qint64 line) +bool QmlCompiler::compileBinding(QmlParser::Value *value, + QmlParser::Property *prop, + int ctxt) { - Q_ASSERT(mo); Q_ASSERT(prop->index); + Q_ASSERT(prop->parent); + Q_ASSERT(prop->parent->metaObject()); - QmlBasicScript bs; - bs.compile(bind.toLatin1()); - - int bref; - if (bs.isValid()) { - bref = output->indexForByteArray(QByteArray(bs.compileData(), bs.compileDataSize())); - } else { - bref = output->indexForString(bind); - } - - QmlInstruction assign; - assign.assignBinding.context = ctxt; - assign.line = line; - - if (bs.isValid()) - assign.type = QmlInstruction::StoreCompiledBinding; - else - assign.type = QmlInstruction::StoreBinding; - - assign.assignBinding.property = prop->index; - assign.assignBinding.value = bref; - QMetaProperty mp = mo->property(assign.assignBinding.property); + QMetaProperty mp = prop->parent->metaObject()->property(prop->index); if (!mp.isWritable() && !QmlMetaType::isList(prop->type)) COMPILE_EXCEPTION2(prop, "Cannot assign binding to read-only property"); - assign.assignBinding.category = QmlMetaProperty::propertyCategory(mp); - savedTypes.insert(output->bytecode.count(), prop->type); - output->bytecode << assign; + BindingReference reference; + reference.expression = value->value; + reference.property = prop; + reference.value = value; + reference.instructionIdx = output->bytecode.count(); + reference.bindingContext = ctxt; + compileState.bindings << reference; + + output->bytecode << QmlInstruction();; return true; } -int QmlCompiler::optimizeExpressions(int start, int end, int patch) -{ - QHash<QString, int> ids; - int saveCount = 0; - int newInstrs = 0; - int bindingsCount = 0; - int parserStatusCount = 0; - - for (int ii = start; ii <= end; ++ii) { - const QmlInstruction &instr = output->bytecode.at(ii); - - if (instr.type == QmlInstruction::CreateComponent) { - ii += instr.createComponent.count - 1; - continue; - } +#if 0 + +#include <iostream> +#ifdef Q_CC_GNU +#include <cxxabi.h> +#endif + +//////////////////////////////////////////////////////////////////////////////// +// AST Dump +//////////////////////////////////////////////////////////////////////////////// +class Dump: protected JavaScript::AST::Visitor +{ + std::ostream &out; + int depth; + +public: + Dump(std::ostream &out) + : out(out), depth(-1) + { } + + void operator()(JavaScript::AST::Node *node) + { JavaScript::AST::Node::acceptChild(node, this); } + +protected: + virtual bool preVisit(JavaScript::AST::Node *node) + { + const char *name = typeid(*node).name(); +#ifdef Q_CC_GNU + name = abi::__cxa_demangle(name, 0, 0, 0) + 17; +#endif + std::cout << std::string(++depth, ' ') << name << std::endl; + return true; + } + + virtual void postVisit(JavaScript::AST::Node *) + { + --depth; + } +}; +#endif - if (instr.type == QmlInstruction::SetId) { - QString id = output->primitives.at(instr.setId.value); - ids.insert(id, ii); - } +// Update the init instruction with final data, and optimize some simple +// bindings +void QmlCompiler::finalizeComponent(int patch) +{ + for (int ii = 0; ii < compileState.bindings.count(); ++ii) { + const BindingReference &binding = compileState.bindings.at(ii); + finalizeBinding(binding); } - for (int ii = start; ii <= end; ++ii) { - const QmlInstruction &instr = output->bytecode.at(ii); - - if (instr.type == QmlInstruction::CreateComponent) { - ii += instr.createComponent.count - 1; - continue; - } - - if (instr.type == QmlInstruction::StoreBinding || - instr.type == QmlInstruction::StoreCompiledBinding) { - ++bindingsCount; - } else if (instr.type == QmlInstruction::BeginObject) { - ++parserStatusCount; - } - - - if (instr.type == QmlInstruction::StoreCompiledBinding) { - QmlBasicScript s(output->datas.at(instr.assignBinding.value).constData()); - - if (s.isSingleLoad()) { - QString slt = QLatin1String(s.singleLoadTarget()); - if (!slt.at(0).isUpper()) - continue; + output->bytecode[patch].init.dataSize = compileState.savedObjects;; + output->bytecode[patch].init.bindingsSize = compileState.bindings.count(); + output->bytecode[patch].init.parserStatusSize = + compileState.parserStatusCount; +} - if (ids.contains(slt) && - instr.assignBinding.category == QmlMetaProperty::Object) { - int id = ids[slt]; +void QmlCompiler::finalizeBinding(const BindingReference &binding) +{ + QmlBasicScript bs; + bs.compile(binding.expression); - int idType = savedTypes.value(id); - int storeType = savedTypes.value(ii); + QmlInstruction &instr = output->bytecode[binding.instructionIdx]; + instr.line = binding.value->location.start.line; - const QMetaObject *idMo = (idType == -1)?&QmlComponent::staticMetaObject:output->types.at(idType).metaObject(); - const QMetaObject *storeMo = - QmlMetaType::rawMetaObjectForType(storeType); + // Single load optimization + if (bs.isValid() && bs.isSingleLoad()) { - bool canAssign = false; - while (!canAssign && idMo) { - if (idMo == storeMo) - canAssign = true; - else - idMo = idMo->superClass(); - } + QString singleLoadTarget = QLatin1String(bs.singleLoadTarget()); - if (!canAssign) - continue; + if (singleLoadTarget.at(0).isUpper() && + compileState.ids.contains(singleLoadTarget) && + QmlMetaType::isObject(binding.property->type)) { - int saveId = -1; + IdReference reference = compileState.ids[singleLoadTarget]; - if (output->bytecode.at(id).setId.save != -1) { - saveId = output->bytecode.at(id).setId.save; - } else { - output->bytecode[id].setId.save = saveCount; - saveId = saveCount; - ++saveCount; - } + const QMetaObject *idMo = reference.object->metaObject(); + const QMetaObject *storeMo = + QmlMetaType::rawMetaObjectForType(binding.property->type); - int prop = instr.assignBinding.property; + Q_ASSERT(idMo); + Q_ASSERT(storeMo); - QmlInstruction &rwinstr = output->bytecode[ii]; - rwinstr.type = QmlInstruction::PushProperty; - rwinstr.pushProperty.property = prop; + bool canAssign = false; + while (!canAssign && idMo) { + if (idMo == storeMo) + canAssign = true; + else + idMo = idMo->superClass(); + } - QmlInstruction instr; - instr.type = QmlInstruction::StoreStackObject; - instr.line = 0; - instr.assignStackObject.property = newInstrs; - instr.assignStackObject.object = saveId; - output->bytecode << instr; - ++newInstrs; + if (canAssign) { + int instructionIdx = reference.instructionIdx; + if (output->bytecode.at(instructionIdx).setId.save == -1) { + output->bytecode[instructionIdx].setId.save = + compileState.savedObjects++; } + int saveId = output->bytecode.at(instructionIdx).setId.save; + + instr.type = QmlInstruction::PushProperty; + instr.pushProperty.property = binding.property->index; + + QmlInstruction store; + store.type = QmlInstruction::StoreStackObject; + store.line = 0; + store.assignStackObject.property = + compileState.pushedProperties++; + store.assignStackObject.object = saveId; + output->bytecode << store; + return; } - } + } + } + + // General binding fallback + int bref; + if (bs.isValid()) { + bref = output->indexForByteArray(QByteArray(bs.compileData(), bs.compileDataSize())); + } else { + bref = output->indexForString(binding.expression.asScript()); } - output->bytecode[patch].init.dataSize = saveCount; - output->bytecode[patch].init.bindingsSize = bindingsCount; - output->bytecode[patch].init.parserStatusSize = parserStatusCount;; + instr.assignBinding.context = binding.bindingContext; + + if (bs.isValid()) + instr.type = QmlInstruction::StoreCompiledBinding; + else + instr.type = QmlInstruction::StoreBinding; - return newInstrs; + instr.assignBinding.property = binding.property->index; + instr.assignBinding.value = bref; + QMetaProperty mp = binding.property->parent->metaObject()->property(binding.property->index); + instr.assignBinding.category = QmlMetaProperty::propertyCategory(mp); } QmlCompiledData::QmlCompiledData() |