From 6b88d7152a72a3a6ba12cb6b4eeeecc1a0c24c51 Mon Sep 17 00:00:00 2001 From: Aaron Kennedy Date: Wed, 10 Jun 2009 15:03:29 +1000 Subject: Improve list assignment performance --- src/declarative/qml/qmlcompiler.cpp | 68 +++++++++++++++++--- src/declarative/qml/qmlcompiler_p.h | 2 + src/declarative/qml/qmlinstruction_p.h | 4 +- src/declarative/qml/qmlvme.cpp | 110 +++++++++++++++++---------------- 4 files changed, 120 insertions(+), 64 deletions(-) diff --git a/src/declarative/qml/qmlcompiler.cpp b/src/declarative/qml/qmlcompiler.cpp index 04a488d..16e1b13 100644 --- a/src/declarative/qml/qmlcompiler.cpp +++ b/src/declarative/qml/qmlcompiler.cpp @@ -1091,7 +1091,9 @@ bool QmlCompiler::compileListProperty(QmlParser::Property *prop, fetch.line = prop->location.start.line; fetch.type = QmlInstruction::FetchQmlList; fetch.fetchQmlList.property = prop->index; - fetch.fetchQmlList.type = QmlMetaType::qmlListType(t); + int listType = QmlMetaType::qmlListType(t); + bool listTypeIsInterface = QmlMetaType::isInterface(listType); + fetch.fetchQmlList.type = listType; output->bytecode << fetch; for (int ii = 0; ii < prop->values.count(); ++ii) { @@ -1099,10 +1101,23 @@ bool QmlCompiler::compileListProperty(QmlParser::Property *prop, if (v->object) { v->type = Value::CreatedObject; COMPILE_CHECK(compileObject(v->object, ctxt)); - QmlInstruction assign; - assign.type = QmlInstruction::AssignObjectList; - assign.line = prop->location.start.line; - output->bytecode << assign; + + if (!listTypeIsInterface) { + if (canConvert(listType, v->object)) { + QmlInstruction store; + store.type = QmlInstruction::StoreObjectQmlList; + store.line = prop->location.start.line; + output->bytecode << store; + } else { + COMPILE_EXCEPTION("Cannot assign object to list"); + } + + } else { + QmlInstruction assign; + assign.type = QmlInstruction::AssignObjectList; + assign.line = prop->location.start.line; + output->bytecode << assign; + } } else { COMPILE_EXCEPTION("Cannot assign primitives to lists"); } @@ -1116,7 +1131,10 @@ bool QmlCompiler::compileListProperty(QmlParser::Property *prop, QmlInstruction fetch; fetch.type = QmlInstruction::FetchQList; fetch.line = prop->location.start.line; - fetch.fetch.property = prop->index; + fetch.fetchQmlList.property = prop->index; + int listType = QmlMetaType::listType(t); + bool listTypeIsInterface = QmlMetaType::isInterface(listType); + fetch.fetchQmlList.type = listType; output->bytecode << fetch; bool assignedBinding = false; @@ -1125,10 +1143,22 @@ bool QmlCompiler::compileListProperty(QmlParser::Property *prop, if (v->object) { v->type = Value::CreatedObject; COMPILE_CHECK(compileObject(v->object, ctxt)); - QmlInstruction assign; - assign.type = QmlInstruction::AssignObjectList; - assign.line = v->location.start.line; - output->bytecode << assign; + + if (!listTypeIsInterface) { + if (canConvert(listType, v->object)) { + QmlInstruction store; + store.type = QmlInstruction::StoreObjectQList; + store.line = prop->location.start.line; + output->bytecode << store; + } else { + COMPILE_EXCEPTION("Cannot assign object to list"); + } + } else { + QmlInstruction assign; + assign.type = QmlInstruction::AssignObjectList; + assign.line = v->location.start.line; + output->bytecode << assign; + } } else if (v->value.isScript()) { if (assignedBinding) COMPILE_EXCEPTION("Can only assign one binding to lists"); @@ -1575,6 +1605,24 @@ void QmlCompiler::finalizeBinding(const BindingReference &binding) instr.assignBinding.category = QmlMetaProperty::propertyCategory(mp); } +/*! + Returns true if object can be assigned to a (QObject) property of type + convertType. +*/ +bool QmlCompiler::canConvert(int convertType, QmlParser::Object *object) +{ + const QMetaObject *convertTypeMo = + QmlMetaType::rawMetaObjectForType(convertType); + const QMetaObject *objectMo = object->metaObject(); + + while (objectMo) { + if (objectMo == convertTypeMo) + return true; + objectMo = objectMo->superClass(); + } + return false; +} + QmlCompiledData::QmlCompiledData() { } diff --git a/src/declarative/qml/qmlcompiler_p.h b/src/declarative/qml/qmlcompiler_p.h index 6b6d8cb..3b1a496 100644 --- a/src/declarative/qml/qmlcompiler_p.h +++ b/src/declarative/qml/qmlcompiler_p.h @@ -179,6 +179,8 @@ private: struct BindingReference; void finalizeBinding(const BindingReference &); + bool canConvert(int, QmlParser::Object *); + struct IdReference { QString id; QmlParser::Object *object; diff --git a/src/declarative/qml/qmlinstruction_p.h b/src/declarative/qml/qmlinstruction_p.h index bdbbaff..a1d923d 100644 --- a/src/declarative/qml/qmlinstruction_p.h +++ b/src/declarative/qml/qmlinstruction_p.h @@ -105,8 +105,6 @@ public: StoreSignal, /* storeSignal */ - StoreObjectQmlList, - // XXX need to handle storing objects in variants // @@ -122,6 +120,8 @@ public: BeginObject, /* begin */ CompleteObject, /* complete */ + StoreObjectQmlList, /* NA */ + StoreObjectQList, /* NA */ AssignObjectList, /* NA */ FetchAttached, /* fetchAttached */ diff --git a/src/declarative/qml/qmlvme.cpp b/src/declarative/qml/qmlvme.cpp index 9ed7e95..3f7739e 100644 --- a/src/declarative/qml/qmlvme.cpp +++ b/src/declarative/qml/qmlvme.cpp @@ -87,6 +87,7 @@ Q_DECLARE_PERFORMANCE_LOG(QFxCompiler) { Q_DECLARE_PERFORMANCE_METRIC(InstrStoreObject); Q_DECLARE_PERFORMANCE_METRIC(InstrStoreSignal); Q_DECLARE_PERFORMANCE_METRIC(InstrStoreObjectQmlList); + Q_DECLARE_PERFORMANCE_METRIC(InstrStoreObjectQList); Q_DECLARE_PERFORMANCE_METRIC(InstrAssignSignalObject); Q_DECLARE_PERFORMANCE_METRIC(InstrStoreBinding); Q_DECLARE_PERFORMANCE_METRIC(InstrStoreCompiledBinding); @@ -126,6 +127,7 @@ Q_DEFINE_PERFORMANCE_LOG(QFxCompiler, "QFxCompiler") { Q_DEFINE_PERFORMANCE_METRIC(InstrStoreObject, "StoreObject"); Q_DEFINE_PERFORMANCE_METRIC(InstrStoreSignal, "StoreSignal"); Q_DEFINE_PERFORMANCE_METRIC(InstrStoreObjectQmlList, "StoreObjectQmlList"); + Q_DEFINE_PERFORMANCE_METRIC(InstrStoreObjectQList, "StoreObjectQList"); Q_DEFINE_PERFORMANCE_METRIC(InstrAssignSignalObject, "AssignSignalObject"); Q_DEFINE_PERFORMANCE_METRIC(InstrStoreBinding, "StoreBinding"); Q_DEFINE_PERFORMANCE_METRIC(InstrStoreCompiledBinding, "StoreCompiledBinding"); @@ -171,13 +173,18 @@ QmlVME::QmlVME() struct ListInstance { ListInstance() {} + /* ListInstance(const QVariant &l, int t) : list(l), type(t), qmlListInterface(0) {} + */ + ListInstance(QList *q, int t) + : type(t), qListInterface(q) {} ListInstance(QmlPrivate::ListInterface *q, int t) : type(t), qmlListInterface(q) {} - QVariant list; + //QVariant list; int type; + QList *qListInterface; QmlPrivate::ListInterface *qmlListInterface; }; @@ -737,65 +744,56 @@ case QmlInstruction::StoreDouble: } break; + case QmlInstruction::StoreObjectQmlList: + { +#ifdef Q_ENABLE_PERFORMANCE_LOG + QFxCompilerTimer cc; +#endif + QObject *assign = stack.pop(); + const ListInstance &list = qliststack.top(); + + void *d = (void *)&assign; + list.qmlListInterface->append(d); + } + break; + + case QmlInstruction::StoreObjectQList: + { +#ifdef Q_ENABLE_PERFORMANCE_LOG + QFxCompilerTimer cc; +#endif + QObject *assign = stack.pop(); + + const ListInstance &list = qliststack.top(); + list.qListInterface->append((void *)assign); + } + break; + case QmlInstruction::AssignObjectList: { + // This is only used for assigning interfaces #ifdef Q_ENABLE_PERFORMANCE_LOG QFxCompilerTimer cc; #endif QObject *assign = stack.pop(); const ListInstance &list = qliststack.top(); - if (list.qmlListInterface) { - int type = list.type; - - void *d = 0; - void *ptr = 0; - bool found = false; - - if (QmlMetaType::isInterface(type)) { - const char *iid = QmlMetaType::interfaceIId(type); - if (iid) - ptr = assign->qt_metacast(iid); - if (ptr) { - d = &ptr; - found = true; - } - } else { - const QMetaObject *mo = - QmlMetaType::rawMetaObjectForType(type); - - const QMetaObject *assignMo = assign->metaObject(); - while(!found && assignMo) { - if (assignMo == mo) - found = true; - else - assignMo = assignMo->superClass(); - } - - // NOTE: This assumes a cast to QObject does not alter - // the object pointer - d = (void *)&assign; - } + int type = list.type; - if (!found) - VME_EXCEPTION("Cannot assign object to list"); + void *ptr = 0; - list.qmlListInterface->append(d); + const char *iid = QmlMetaType::interfaceIId(type); + if (iid) + ptr = assign->qt_metacast(iid); + if (!ptr) + VME_EXCEPTION("Cannot assign object to list"); + + if (list.qmlListInterface) { + void *d = (void *)&ptr; + list.qmlListInterface->append(d); } else { - int type = list.type; - - if (QmlMetaType::isInterface(type)) { - void *ptr = 0; - const char *iid = QmlMetaType::interfaceIId(type); - if (iid) - ptr = assign->qt_metacast(iid); - QVariant v(list.type, &ptr); - QmlMetaType::append(list.list, v); - } else { - QVariant v = QmlMetaType::fromObject(assign, list.type); - QmlMetaType::append(list.list, v); - } + list.qListInterface->append(ptr); } } break; @@ -883,10 +881,18 @@ case QmlInstruction::StoreDouble: QFxCompilerTimer cc; #endif QObject *target = stack.top(); - QMetaProperty prop = - target->metaObject()->property(instr.fetch.property); - QVariant v = prop.read(target); - qliststack.push(ListInstance(v, QmlMetaType::listType(prop.userType()))); + + void *a[1]; + // We know that QList* can be converted to + // QList* + QList *list = 0; + a[0] = &list; + QMetaObject::metacall(target, QMetaObject::ReadProperty, + instr.fetchQmlList.property, a); + if (!list) + VME_EXCEPTION("Cannot assign to null list"); + + qliststack.push(ListInstance(list, instr.fetchQmlList.type)); } break; -- cgit v0.12