diff options
author | Aaron Kennedy <aaron.kennedy@nokia.com> | 2010-01-09 09:09:15 (GMT) |
---|---|---|
committer | Aaron Kennedy <aaron.kennedy@nokia.com> | 2010-01-09 09:09:15 (GMT) |
commit | 41f7ccb2dd21dcd4b0f2aa172bb813095cb2ade3 (patch) | |
tree | 60746e15deeb1ca5c2ff6f0f096bc96c6aeef6aa /src/declarative/qml | |
parent | 3ade772efd07fe342c10274b5fc6387965ac0c9d (diff) | |
download | Qt-41f7ccb2dd21dcd4b0f2aa172bb813095cb2ade3.zip Qt-41f7ccb2dd21dcd4b0f2aa172bb813095cb2ade3.tar.gz Qt-41f7ccb2dd21dcd4b0f2aa172bb813095cb2ade3.tar.bz2 |
Optimization: Bypass qt_metacall for synthesized methods
Diffstat (limited to 'src/declarative/qml')
-rw-r--r-- | src/declarative/qml/qmlcompileddata.cpp | 5 | ||||
-rw-r--r-- | src/declarative/qml/qmlcompiler.cpp | 19 | ||||
-rw-r--r-- | src/declarative/qml/qmlcompiler_p.h | 2 | ||||
-rw-r--r-- | src/declarative/qml/qmlobjectscriptclass.cpp | 11 | ||||
-rw-r--r-- | src/declarative/qml/qmlpropertycache.cpp | 81 | ||||
-rw-r--r-- | src/declarative/qml/qmlpropertycache_p.h | 20 | ||||
-rw-r--r-- | src/declarative/qml/qmlvmemetaobject.cpp | 50 | ||||
-rw-r--r-- | src/declarative/qml/qmlvmemetaobject_p.h | 4 |
8 files changed, 163 insertions, 29 deletions
diff --git a/src/declarative/qml/qmlcompileddata.cpp b/src/declarative/qml/qmlcompileddata.cpp index 198b574..de9bf96 100644 --- a/src/declarative/qml/qmlcompileddata.cpp +++ b/src/declarative/qml/qmlcompileddata.cpp @@ -162,7 +162,7 @@ int QmlCompiledData::indexForLocation(const QmlParser::LocationSpan &l) } QmlCompiledData::QmlCompiledData() -: importCache(0), root(0) +: importCache(0), root(0), rootPropertyCache(0) { } @@ -182,6 +182,9 @@ QmlCompiledData::~QmlCompiledData() if (importCache) importCache->release(); + if (rootPropertyCache) + rootPropertyCache->release(); + qDeleteAll(cachedPrograms); qDeleteAll(cachedClosures); } diff --git a/src/declarative/qml/qmlcompiler.cpp b/src/declarative/qml/qmlcompiler.cpp index 7c43305..7f8bc7a 100644 --- a/src/declarative/qml/qmlcompiler.cpp +++ b/src/declarative/qml/qmlcompiler.cpp @@ -90,7 +90,7 @@ using namespace QmlParser; Instantiate a new QmlCompiler. */ QmlCompiler::QmlCompiler() -: output(0), engine(0) +: output(0), engine(0), unitRoot(0), unit(0) { } @@ -611,6 +611,7 @@ bool QmlCompiler::compile(QmlEngine *engine, this->engine = engine; this->unit = unit; + this->unitRoot = root; compileTree(root); if (!isError()) { @@ -626,6 +627,8 @@ bool QmlCompiler::compile(QmlEngine *engine, savedCompileStates.clear(); output = 0; this->engine = 0; + this->unit = 0; + this->unitRoot = 0; return !isError(); } @@ -836,7 +839,19 @@ void QmlCompiler::genObject(QmlParser::Object *obj) meta.storeMeta.aliasData = output->indexForByteArray(obj->synthdata); meta.storeMeta.propertyCache = output->propertyCaches.count(); // ### Surely the creation of this property cache could be more efficient - output->propertyCaches << QmlPropertyCache::create(engine, obj->metaObject()); + QmlPropertyCache *propertyCache = 0; + if (tr.component && QmlComponentPrivate::get(tr.component)->cc->rootPropertyCache) { + propertyCache = QmlComponentPrivate::get(tr.component)->cc->rootPropertyCache->copy(); + } else { + propertyCache = QmlPropertyCache::create(engine, obj->metaObject()->superClass()); + } + propertyCache->append(engine, obj->metaObject(), QmlPropertyCache::Data::NoFlags, + QmlPropertyCache::Data::IsVMEFunction); + if (obj == unitRoot) { + propertyCache->addref(); + output->rootPropertyCache = propertyCache; + } + output->propertyCaches << propertyCache; output->bytecode << meta; } diff --git a/src/declarative/qml/qmlcompiler_p.h b/src/declarative/qml/qmlcompiler_p.h index 740d97c..c0e50e4 100644 --- a/src/declarative/qml/qmlcompiler_p.h +++ b/src/declarative/qml/qmlcompiler_p.h @@ -107,6 +107,7 @@ public: const QMetaObject *root; QAbstractDynamicMetaObject rootData; + QmlPropertyCache *rootPropertyCache; QList<QString> primitives; QList<float> floatData; QList<int> intData; @@ -324,6 +325,7 @@ private: QList<QmlError> exceptions; QmlCompiledData *output; QmlEngine *engine; + QmlParser::Object *unitRoot; QmlCompositeTypeData *unit; }; QT_END_NAMESPACE diff --git a/src/declarative/qml/qmlobjectscriptclass.cpp b/src/declarative/qml/qmlobjectscriptclass.cpp index 73dfd75..f372561 100644 --- a/src/declarative/qml/qmlobjectscriptclass.cpp +++ b/src/declarative/qml/qmlobjectscriptclass.cpp @@ -48,6 +48,7 @@ #include "qmllistscriptclass_p.h" #include "qmlbinding.h" #include "qmlguard_p.h" +#include "qmlvmemetaobject_p.h" #include <QtCore/qtimer.h> @@ -216,9 +217,13 @@ QScriptValue QmlObjectScriptClass::property(QObject *obj, const Identifier &name return enginePriv->typeNameClass->newObject(obj, lastTNData->typeNamespace); } else if (lastData->flags & QmlPropertyCache::Data::IsFunction) { - // ### Optimize - QScriptValue sobj = scriptEngine->newQObject(obj); - return sobj.property(toString(name)); + if (lastData->flags & QmlPropertyCache::Data::IsVMEFunction) { + return ((QmlVMEMetaObject *)(obj->metaObject()))->vmeMethod(lastData->coreIndex); + } else { + // ### Optimize + QScriptValue sobj = scriptEngine->newQObject(obj); + return sobj.property(toString(name)); + } } else { if (enginePriv->captureProperties && !(lastData->flags & QmlPropertyCache::Data::IsConstant)) { enginePriv->capturedProperties << diff --git a/src/declarative/qml/qmlpropertycache.cpp b/src/declarative/qml/qmlpropertycache.cpp index bc7d7de..394fa35 100644 --- a/src/declarative/qml/qmlpropertycache.cpp +++ b/src/declarative/qml/qmlpropertycache.cpp @@ -87,8 +87,8 @@ void QmlPropertyCache::Data::load(const QMetaMethod &m) } -QmlPropertyCache::QmlPropertyCache(QmlEngine *engine) -: QmlCleanup(engine) +QmlPropertyCache::QmlPropertyCache(QmlEngine *e) +: QmlCleanup(e), engine(e) { } @@ -145,6 +145,83 @@ QmlPropertyCache::Data QmlPropertyCache::create(const QMetaObject *metaObject, return rv; } +QmlPropertyCache *QmlPropertyCache::copy() const +{ + QmlPropertyCache *cache = new QmlPropertyCache(engine); + cache->indexCache = indexCache; + cache->stringCache = stringCache; + cache->identifierCache = identifierCache; + + for (int ii = 0; ii < indexCache.count(); ++ii) + indexCache.at(ii)->addref(); + for (StringCache::ConstIterator iter = stringCache.begin(); iter != stringCache.end(); ++iter) + (*iter)->addref(); + for (IdentifierCache::ConstIterator iter = identifierCache.begin(); iter != identifierCache.end(); ++iter) + (*iter)->addref(); + + return cache; +} + +void QmlPropertyCache::append(QmlEngine *engine, const QMetaObject *metaObject, + Data::Flag propertyFlags, Data::Flag methodFlags) +{ + QmlEnginePrivate *enginePriv = QmlEnginePrivate::get(engine); + + int propCount = metaObject->propertyCount(); + int propOffset = metaObject->propertyOffset(); + + indexCache.resize(propCount); + for (int ii = propOffset; ii < propCount; ++ii) { + QMetaProperty p = metaObject->property(ii); + QString propName = QString::fromUtf8(p.name()); + + RData *data = new RData; + data->identifier = enginePriv->objectClass->createPersistentIdentifier(propName); + + data->load(p, engine); + data->flags |= propertyFlags; + + indexCache[ii] = data; + + if (stringCache.contains(propName)) { + stringCache[propName]->release(); + identifierCache[data->identifier.identifier]->release(); + } + + stringCache.insert(propName, data); + identifierCache.insert(data->identifier.identifier, data); + data->addref(); + data->addref(); + } + + int methodCount = metaObject->methodCount(); + int methodOffset = metaObject->methodOffset(); + for (int ii = methodOffset; ii < methodCount; ++ii) { + QMetaMethod m = metaObject->method(ii); + QString methodName = QString::fromUtf8(m.signature()); + + int parenIdx = methodName.indexOf(QLatin1Char('(')); + Q_ASSERT(parenIdx != -1); + methodName = methodName.left(parenIdx); + + RData *data = new RData; + data->identifier = enginePriv->objectClass->createPersistentIdentifier(methodName); + + if (stringCache.contains(methodName)) { + stringCache[methodName]->release(); + identifierCache[data->identifier.identifier]->release(); + } + + data->load(m); + if (m.methodType() == QMetaMethod::Slot || m.methodType() == QMetaMethod::Method) + data->flags |= methodFlags; + + stringCache.insert(methodName, data); + identifierCache.insert(data->identifier.identifier, data); + data->addref(); + } +} + // ### Optimize - check engine for the parent meta object etc. QmlPropertyCache *QmlPropertyCache::create(QmlEngine *engine, const QMetaObject *metaObject) { diff --git a/src/declarative/qml/qmlpropertycache_p.h b/src/declarative/qml/qmlpropertycache_p.h index 50b4cf2..feaa683 100644 --- a/src/declarative/qml/qmlpropertycache_p.h +++ b/src/declarative/qml/qmlpropertycache_p.h @@ -75,18 +75,21 @@ public: inline bool operator==(const Data &); enum Flag { + NoFlags = 0x00000000, + // Can apply to all properties, except IsFunction IsConstant = 0x00000001, IsWritable = 0x00000002, // These are mutually exclusive IsFunction = 0x00000004, - IsQObjectDerived = 0x00000008, - IsEnumType = 0x00000010, - IsQmlList = 0x00000020, - IsQList = 0x00000040, - IsQmlBinding = 0x00000080, - IsQScriptValue = 0x00000100 + IsVMEFunction = 0x00000008, + IsQObjectDerived = 0x00000010, + IsEnumType = 0x00000020, + IsQmlList = 0x00000040, + IsQList = 0x00000080, + IsQmlBinding = 0x00000100, + IsQScriptValue = 0x00000200 }; Q_DECLARE_FLAGS(Flags, Flag) @@ -112,6 +115,10 @@ public: void update(QmlEngine *, const QMetaObject *); + QmlPropertyCache *copy() const; + void append(QmlEngine *, const QMetaObject *, Data::Flag propertyFlags = Data::NoFlags, + Data::Flag methodFlags = Data::NoFlags); + static QmlPropertyCache *create(QmlEngine *, const QMetaObject *); static Data create(const QMetaObject *, const QString &); @@ -131,6 +138,7 @@ private: typedef QHash<QString, RData *> StringCache; typedef QHash<QScriptDeclarativeClass::Identifier, RData *> IdentifierCache; + QmlEngine *engine; IndexCache indexCache; StringCache stringCache; IdentifierCache identifierCache; diff --git a/src/declarative/qml/qmlvmemetaobject.cpp b/src/declarative/qml/qmlvmemetaobject.cpp index fd699c3..c863ffd 100644 --- a/src/declarative/qml/qmlvmemetaobject.cpp +++ b/src/declarative/qml/qmlvmemetaobject.cpp @@ -265,27 +265,16 @@ int QmlVMEMetaObject::metaCall(QMetaObject::Call c, int _id, void **a) QmlEnginePrivate *ep = QmlEnginePrivate::get(ctxt->engine()); - if (!methods) - methods = new QScriptValue[metaData->methodCount]; - - QmlVMEMetaData::MethodData *data = metaData->methodData() + id; - if (!methods[id].isValid()) { - const QChar *body = - (const QChar *)(((const char*)metaData) + data->bodyOffset); - - QString code = QString::fromRawData(body, data->bodyLength); - - // XXX Use QScriptProgram - methods[id] = QmlExpressionPrivate::evalInObjectScope(ctxt, object, code); - } + QScriptValue function = method(id); QScriptValueList args; + QmlVMEMetaData::MethodData *data = metaData->methodData() + id; if (data->parameterCount) { for (int ii = 0; ii < data->parameterCount; ++ii) { args << ep->scriptValueFromVariant(*(QVariant *)a[ii + 1]); } } - QScriptValue rv = methods[id].call(ep->scriptEngine.globalObject(), args); + QScriptValue rv = function.call(ep->objectClass->newQObject(object), args); if (a[0]) *reinterpret_cast<QVariant *>(a[0]) = ep->scriptValueToVariant(rv); @@ -301,6 +290,29 @@ int QmlVMEMetaObject::metaCall(QMetaObject::Call c, int _id, void **a) return object->qt_metacall(c, _id, a); } +QScriptValue QmlVMEMetaObject::method(int index) +{ + if (!methods) + methods = new QScriptValue[metaData->methodCount]; + + if (!methods[index].isValid()) { + QmlVMEMetaData::MethodData *data = metaData->methodData() + index; + + const QChar *body = + (const QChar *)(((const char*)metaData) + data->bodyOffset); + + QString code = QString::fromRawData(body, data->bodyLength); + + // XXX Use QScriptProgram + // XXX We should evaluate all methods in a single big script block to + // improve the call time between dynamic methods defined on the same + // object + methods[index] = QmlExpressionPrivate::evalInObjectScope(ctxt, object, code); + } + + return methods[index]; +} + void QmlVMEMetaObject::listChanged(int id) { activate(object, methodOffset + id, 0); @@ -314,5 +326,15 @@ void QmlVMEMetaObject::registerInterceptor(int index, int valueIndex, QmlPropert interceptors.insert(index, qMakePair(valueIndex, interceptor)); } +QScriptValue QmlVMEMetaObject::vmeMethod(int index) +{ + if (index < methodOffset) { + Q_ASSERT(parent); + return static_cast<QmlVMEMetaObject *>(parent)->vmeMethod(index); + } + int plainSignals = metaData->signalCount + metaData->propertyCount + metaData->aliasCount; + Q_ASSERT(index >= (methodOffset + plainSignals) && index < (methodOffset + metaData->methodCount)); + return method(index - methodOffset - plainSignals); +} QT_END_NAMESPACE diff --git a/src/declarative/qml/qmlvmemetaobject_p.h b/src/declarative/qml/qmlvmemetaobject_p.h index b79e42c..497d8f6 100644 --- a/src/declarative/qml/qmlvmemetaobject_p.h +++ b/src/declarative/qml/qmlvmemetaobject_p.h @@ -114,7 +114,7 @@ public: ~QmlVMEMetaObject(); void registerInterceptor(int index, int valueIndex, QmlPropertyValueInterceptor *interceptor); - + QScriptValue vmeMethod(int index); protected: virtual int metaCall(QMetaObject::Call _c, int _id, void **_a); @@ -131,7 +131,9 @@ private: QBitArray aConnected; QBitArray aInterceptors; QHash<int, QPair<int, QmlPropertyValueInterceptor*> > interceptors; + QScriptValue *methods; + QScriptValue method(int); QAbstractDynamicMetaObject *parent; |