diff options
author | Aaron Kennedy <aaron.kennedy@nokia.com> | 2009-05-28 03:25:31 (GMT) |
---|---|---|
committer | Aaron Kennedy <aaron.kennedy@nokia.com> | 2009-05-28 03:25:31 (GMT) |
commit | 1090d5d1fad890d9f43e87e19277e1f624921d6d (patch) | |
tree | 7420c5469b0cc509a67fccab86e434a71faf97ec | |
parent | 4587282af7bfb9f6b1a8329651073bb4127c62b8 (diff) | |
download | Qt-1090d5d1fad890d9f43e87e19277e1f624921d6d.zip Qt-1090d5d1fad890d9f43e87e19277e1f624921d6d.tar.gz Qt-1090d5d1fad890d9f43e87e19277e1f624921d6d.tar.bz2 |
Delay the compilation of bindings until the end
This way we have a better understanding of the complete context in which the binding will be executed.
-rw-r--r-- | src/declarative/qml/qmlcompiler.cpp | 175 | ||||
-rw-r--r-- | src/declarative/qml/qmlcompiler_p.h | 14 | ||||
-rw-r--r-- | src/declarative/qml/qmlparser.cpp | 17 | ||||
-rw-r--r-- | src/declarative/qml/qmlparser_p.h | 3 | ||||
-rw-r--r-- | src/declarative/qml/qmlscriptparser.cpp | 1 |
5 files changed, 107 insertions, 103 deletions
diff --git a/src/declarative/qml/qmlcompiler.cpp b/src/declarative/qml/qmlcompiler.cpp index 75d01c2..3029934 100644 --- a/src/declarative/qml/qmlcompiler.cpp +++ b/src/declarative/qml/qmlcompiler.cpp @@ -736,10 +736,8 @@ bool QmlCompiler::compileComponentFromRoot(Object *obj, int ctxt) if (obj) COMPILE_CHECK(compileObject(obj, ctxt)); + finalizeComponent(count); create.createComponent.count = output->bytecode.count() - count; - - int inc = finalizeComponent(count); - create.createComponent.count += inc; compileState = oldComponentCompileState; return true; } @@ -1125,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, 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"); @@ -1296,9 +1292,7 @@ bool QmlCompiler::compilePropertyLiteralAssignment(QmlParser::Property *prop, if (v->value.isScript()) { - COMPILE_CHECK(compileBinding(v->value, prop, ctxt, - obj->metaObject(), - v->location.start.line)); + COMPILE_CHECK(compileBinding(v, prop, ctxt)); v->type = Value::PropertyBinding; @@ -1403,46 +1397,27 @@ bool QmlCompiler::compileDynamicMeta(QmlParser::Object *obj) return true; } -bool QmlCompiler::compileBinding(const QmlParser::Variant &bind, +bool QmlCompiler::compileBinding(QmlParser::Value *value, QmlParser::Property *prop, - int ctxt, const QMetaObject *mo, qint64 line) + int ctxt) { - Q_ASSERT(mo); Q_ASSERT(prop->index); + Q_ASSERT(prop->parent); + Q_ASSERT(prop->parent->metaObject()); - QMetaProperty mp = mo->property(prop->index); + 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"); - QmlBasicScript bs; - bs.compile(bind); - - int bref; - if (bs.isValid()) { - bref = output->indexForByteArray(QByteArray(bs.compileData(), bs.compileDataSize())); - } else { - bref = output->indexForString(bind.asScript()); - } - - 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; - assign.assignBinding.category = QmlMetaProperty::propertyCategory(mp); BindingReference reference; - reference.expression = bind; + reference.expression = value->value; reference.property = prop; + reference.value = value; reference.instructionIdx = output->bytecode.count(); + reference.bindingContext = ctxt; compileState.bindings << reference; - output->bytecode << assign; + output->bytecode << QmlInstruction();; return true; } @@ -1490,81 +1465,95 @@ protected: // Update the init instruction with final data, and optimize some simple // bindings -int QmlCompiler::finalizeComponent(int patch) +void QmlCompiler::finalizeComponent(int patch) { - int saveCount = 0; - int newInstrs = 0; - for (int ii = 0; ii < compileState.bindings.count(); ++ii) { const BindingReference &binding = compileState.bindings.at(ii); + finalizeBinding(binding); + } - QmlInstruction &instr = output->bytecode[binding.instructionIdx]; - - 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; - - if (compileState.ids.contains(slt) && - instr.assignBinding.category == QmlMetaProperty::Object) { + output->bytecode[patch].init.dataSize = compileState.savedObjects;; + output->bytecode[patch].init.bindingsSize = compileState.bindings.count(); + output->bytecode[patch].init.parserStatusSize = + compileState.parserStatusCount; +} - IdReference reference = - compileState.ids[slt]; +void QmlCompiler::finalizeBinding(const BindingReference &binding) +{ + QmlBasicScript bs; + bs.compile(binding.expression); - const QMetaObject *idMo = reference.object->metaObject(); - const QMetaObject *storeMo = QmlMetaType::rawMetaObjectForType(binding.property->type); + QmlInstruction &instr = output->bytecode[binding.instructionIdx]; + instr.line = binding.value->location.start.line; - Q_ASSERT(idMo); - Q_ASSERT(storeMo); + // 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]; - int instructionIdx = reference.instructionIdx; - if (output->bytecode.at(instructionIdx).setId.save != -1) { - saveId = output->bytecode.at(instructionIdx).setId.save; - } else { - output->bytecode[instructionIdx].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); - instr.type = QmlInstruction::PushProperty; - instr.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; } - } + } } - output->bytecode[patch].init.dataSize = saveCount; - output->bytecode[patch].init.bindingsSize = compileState.bindings.count(); - output->bytecode[patch].init.parserStatusSize = - compileState.parserStatusCount; + // General binding fallback + int bref; + if (bs.isValid()) { + bref = output->indexForByteArray(QByteArray(bs.compileData(), bs.compileDataSize())); + } else { + bref = output->indexForString(binding.expression.asScript()); + } + + 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() diff --git a/src/declarative/qml/qmlcompiler_p.h b/src/declarative/qml/qmlcompiler_p.h index b1963da..eb24b91 100644 --- a/src/declarative/qml/qmlcompiler_p.h +++ b/src/declarative/qml/qmlcompiler_p.h @@ -158,10 +158,12 @@ private: QmlParser::Value *value); bool compileDynamicMeta(QmlParser::Object *obj); - bool compileBinding(const QmlParser::Variant &, QmlParser::Property *prop, - int ctxt, const QMetaObject *, qint64); + bool compileBinding(QmlParser::Value *, QmlParser::Property *prop, + int ctxt); - int finalizeComponent(int patch); + void finalizeComponent(int patch); + class BindingReference; + void finalizeBinding(const BindingReference &); struct IdReference { QString id; @@ -172,14 +174,18 @@ private: struct BindingReference { QmlParser::Variant expression; QmlParser::Property *property; + QmlParser::Value *value; int instructionIdx; + int bindingContext; }; struct ComponentCompileState { - ComponentCompileState() : parserStatusCount(0) {} + ComponentCompileState() : parserStatusCount(0), savedObjects(0), pushedProperties(0) {} QHash<QString, IdReference> ids; int parserStatusCount; + int savedObjects; + int pushedProperties; QList<BindingReference> bindings; }; ComponentCompileState compileState; diff --git a/src/declarative/qml/qmlparser.cpp b/src/declarative/qml/qmlparser.cpp index f262b5d..fadfbb1 100644 --- a/src/declarative/qml/qmlparser.cpp +++ b/src/declarative/qml/qmlparser.cpp @@ -83,18 +83,23 @@ const QMetaObject *Object::metaObject() const QmlParser::Property *Object::getDefaultProperty() { - if (!defaultProperty) + if (!defaultProperty) { defaultProperty = new Property; + defaultProperty->parent = this; + } return defaultProperty; } Property *QmlParser::Object::getProperty(const QByteArray &name, bool create) { if (!properties.contains(name)) { - if (create) - properties.insert(name, new Property(name)); - else + if (create) { + Property *property = new Property(name); + property->parent = this; + properties.insert(name, property); + } else { return 0; + } } return properties[name]; } @@ -153,12 +158,12 @@ void QmlParser::Object::dump(int indent) const } QmlParser::Property::Property() -: type(0), index(-1), value(0), isDefault(true) +: parent(0), type(0), index(-1), value(0), isDefault(true) { } QmlParser::Property::Property(const QByteArray &n) -: type(0), index(-1), value(0), name(n), isDefault(false) +: parent(0), type(0), index(-1), value(0), name(n), isDefault(false) { } diff --git a/src/declarative/qml/qmlparser_p.h b/src/declarative/qml/qmlparser_p.h index cb9b540..020cae5 100644 --- a/src/declarative/qml/qmlparser_p.h +++ b/src/declarative/qml/qmlparser_p.h @@ -252,6 +252,9 @@ namespace QmlParser Property(const QByteArray &n); virtual ~Property(); + // The Object to which this property is attached + Object *parent; + Object *getValue(); void addValue(Value *v); diff --git a/src/declarative/qml/qmlscriptparser.cpp b/src/declarative/qml/qmlscriptparser.cpp index b1ffc98..75c81a7 100644 --- a/src/declarative/qml/qmlscriptparser.cpp +++ b/src/declarative/qml/qmlscriptparser.cpp @@ -532,6 +532,7 @@ bool ProcessAST::visit(AST::UiPublicMember *node) if (node->expression) { // default value property.defaultValue = new Property; + property.defaultValue->parent = _stateStack.top().object; Value *value = new Value; value->location = location(node->expression->firstSourceLocation(), node->expression->lastSourceLocation()); |