summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAaron Kennedy <aaron.kennedy@nokia.com>2009-05-28 03:25:31 (GMT)
committerAaron Kennedy <aaron.kennedy@nokia.com>2009-05-28 03:25:31 (GMT)
commit1090d5d1fad890d9f43e87e19277e1f624921d6d (patch)
tree7420c5469b0cc509a67fccab86e434a71faf97ec
parent4587282af7bfb9f6b1a8329651073bb4127c62b8 (diff)
downloadQt-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.cpp175
-rw-r--r--src/declarative/qml/qmlcompiler_p.h14
-rw-r--r--src/declarative/qml/qmlparser.cpp17
-rw-r--r--src/declarative/qml/qmlparser_p.h3
-rw-r--r--src/declarative/qml/qmlscriptparser.cpp1
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());