From 49527e854a9edb0a92e64264d6efac6be46cf0ed Mon Sep 17 00:00:00 2001 From: Aaron Kennedy Date: Wed, 30 Sep 2009 11:07:07 +1000 Subject: Create a property cache for synthesized metaobjects --- src/declarative/qml/qml.pri | 6 +- src/declarative/qml/qmlcompileddata.cpp | 3 + src/declarative/qml/qmlcompiler.cpp | 6 +- src/declarative/qml/qmlcompiler_p.h | 3 + src/declarative/qml/qmldeclarativedata_p.h | 3 + src/declarative/qml/qmlengine.cpp | 14 ++- src/declarative/qml/qmlengine_p.h | 18 +++- src/declarative/qml/qmlinstruction.cpp | 2 +- src/declarative/qml/qmlinstruction_p.h | 2 +- src/declarative/qml/qmlmetaproperty.cpp | 71 +++------------ src/declarative/qml/qmlmetaproperty_p.h | 22 ----- src/declarative/qml/qmlpropertycache.cpp | 137 +++++++++++++++++++++++++++++ src/declarative/qml/qmlpropertycache_p.h | 100 +++++++++++++++++++++ src/declarative/qml/qmlvme.cpp | 9 +- 14 files changed, 303 insertions(+), 93 deletions(-) create mode 100644 src/declarative/qml/qmlpropertycache.cpp create mode 100644 src/declarative/qml/qmlpropertycache_p.h diff --git a/src/declarative/qml/qml.pri b/src/declarative/qml/qml.pri index 8349e29..216adb1 100644 --- a/src/declarative/qml/qml.pri +++ b/src/declarative/qml/qml.pri @@ -34,7 +34,8 @@ SOURCES += qml/qmlparser.cpp \ qml/qmlxmlhttprequest.cpp \ qml/qmlsqldatabase.cpp \ qml/qmetaobjectbuilder.cpp \ - qml/qmlwatcher.cpp + qml/qmlwatcher.cpp \ + qml/qmlpropertycache.cpp HEADERS += qml/qmlparser_p.h \ qml/qmlinstruction_p.h \ @@ -86,7 +87,8 @@ HEADERS += qml/qmlparser_p.h \ qml/qmlxmlhttprequest_p.h \ qml/qmlsqldatabase_p.h \ qml/qmetaobjectbuilder_p.h \ - qml/qmlwatcher_p.h + qml/qmlwatcher_p.h \ + qml/qmlpropertycache_p.h # for qtscript debugger contains(QT_CONFIG, scripttools):QT += scripttools diff --git a/src/declarative/qml/qmlcompileddata.cpp b/src/declarative/qml/qmlcompileddata.cpp index a46d893..a603d4e 100644 --- a/src/declarative/qml/qmlcompileddata.cpp +++ b/src/declarative/qml/qmlcompileddata.cpp @@ -160,6 +160,9 @@ QmlCompiledData::~QmlCompiledData() types.at(ii).ref->release(); } + for (int ii = 0; ii < propertyCaches.count(); ++ii) + propertyCaches.at(ii)->release(); + qDeleteAll(programs); } diff --git a/src/declarative/qml/qmlcompiler.cpp b/src/declarative/qml/qmlcompiler.cpp index e67f79a..0b4ac20 100644 --- a/src/declarative/qml/qmlcompiler.cpp +++ b/src/declarative/qml/qmlcompiler.cpp @@ -647,7 +647,7 @@ void QmlCompiler::compileTree(Object *tree) Q_ASSERT(tree->metatype); static_cast(output->root) = *tree->metaObject(); - if (!tree->metadata.isEmpty()) + if (!tree->metadata.isEmpty()) QmlEnginePrivate::get(engine)->registerCompositeType(output); } @@ -807,7 +807,9 @@ void QmlCompiler::genObject(QmlParser::Object *obj) meta.line = -1; meta.storeMeta.data = output->indexForByteArray(obj->metadata); meta.storeMeta.aliasData = output->indexForByteArray(obj->synthdata); - meta.storeMeta.slotData = -1; + meta.storeMeta.propertyCache = output->propertyCaches.count(); + // ### Surely the creation of this property cache could be more efficient + output->propertyCaches << QmlPropertyCache::create(engine, obj->metaObject()); output->bytecode << meta; } diff --git a/src/declarative/qml/qmlcompiler_p.h b/src/declarative/qml/qmlcompiler_p.h index 447c421..677aba7 100644 --- a/src/declarative/qml/qmlcompiler_p.h +++ b/src/declarative/qml/qmlcompiler_p.h @@ -62,6 +62,7 @@ #include #include #include +#include QT_BEGIN_NAMESPACE @@ -99,6 +100,7 @@ public: int index; int type; }; + QAbstractDynamicMetaObject root; QList primitives; QList floatData; @@ -108,6 +110,7 @@ public: QList locations; QList bytecode; QList programs; + QList propertyCaches; void dumpInstructions(); private: diff --git a/src/declarative/qml/qmldeclarativedata_p.h b/src/declarative/qml/qmldeclarativedata_p.h index ade961f..b4c87b8 100644 --- a/src/declarative/qml/qmldeclarativedata_p.h +++ b/src/declarative/qml/qmldeclarativedata_p.h @@ -60,6 +60,7 @@ QT_BEGIN_NAMESPACE class QmlCompiledData; class QmlAbstractBinding; class QmlContext; +class QmlPropertyCache; class QmlDeclarativeData : public QDeclarativeData { public: @@ -85,6 +86,8 @@ public: QHash *attachedProperties; + QmlPropertyCache *propertyCache; + static QmlDeclarativeData *get(const QObject *object, bool create = false) { QObjectPrivate *priv = QObjectPrivate::get(const_cast(object)); diff --git a/src/declarative/qml/qmlengine.cpp b/src/declarative/qml/qmlengine.cpp index 72603ed..757670b 100644 --- a/src/declarative/qml/qmlengine.cpp +++ b/src/declarative/qml/qmlengine.cpp @@ -41,11 +41,12 @@ #undef QT3_SUPPORT // don't want it here - it just causes bugs (which is why we removed it) -#include +#include #include #include #include #include +#include #ifdef QT_SCRIPTTOOLS_LIB #include @@ -192,6 +193,8 @@ QmlEnginePrivate::~QmlEnginePrivate() contextClass = 0; delete objectClass; objectClass = 0; + delete objectClass2; + objectClass2 = 0; delete valueTypeClass; valueTypeClass = 0; delete typeNameClass; @@ -211,6 +214,9 @@ QmlEnginePrivate::~QmlEnginePrivate() clear(parserStatus[ii]); for(QHash::ConstIterator iter = m_compositeTypes.constBegin(); iter != m_compositeTypes.constEnd(); ++iter) (*iter)->release(); + for(QHash::Iterator iter = propertyCache.begin(); iter != propertyCache.end(); ++iter) + (*iter)->release(); + } void QmlEnginePrivate::clear(SimpleList &bvs) @@ -236,6 +242,7 @@ void QmlEnginePrivate::init() scriptEngine.installTranslatorFunctions(); contextClass = new QmlContextScriptClass(q); objectClass = new QmlObjectScriptClass(q); + objectClass2 = new QScriptDeclarativeClass(&scriptEngine); valueTypeClass = new QmlValueTypeScriptClass(q); typeNameClass = new QmlTypeNameScriptClass(q); rootContext = new QmlContext(q,true); @@ -700,7 +707,7 @@ QObject *qmlAttachedPropertiesObjectById(int id, const QObject *object, bool cre QmlDeclarativeData::QmlDeclarativeData(QmlContext *ctxt) : context(ctxt), bindings(0), bindingBitsSize(0), bindingBits(0), outerContext(0), lineNumber(0), columnNumber(0), deferredComponent(0), - deferredIdx(0), attachedProperties(0) + deferredIdx(0), attachedProperties(0), propertyCache(0) { } @@ -725,6 +732,9 @@ void QmlDeclarativeData::destroyed(QObject *object) if (bindingBits) free(bindingBits); + if (propertyCache) + propertyCache->release(); + delete this; } diff --git a/src/declarative/qml/qmlengine_p.h b/src/declarative/qml/qmlengine_p.h index 74e24d4..68019e2 100644 --- a/src/declarative/qml/qmlengine_p.h +++ b/src/declarative/qml/qmlengine_p.h @@ -72,6 +72,7 @@ #include #include #include +#include QT_BEGIN_NAMESPACE @@ -88,6 +89,7 @@ class QScriptEngineDebugger; class QNetworkReply; class QNetworkAccessManager; class QmlAbstractBinding; +class QScriptDeclarativeClass; class QmlEnginePrivate : public QObjectPrivate { @@ -149,6 +151,7 @@ public: } resolveData; QmlContextScriptClass *contextClass; QmlObjectScriptClass *objectClass; + QScriptDeclarativeClass *objectClass2; QmlValueTypeScriptClass *valueTypeClass; QmlTypeNameScriptClass *typeNameClass; // Used by DOM Core 3 API @@ -212,10 +215,17 @@ public: // ### Fixme typedef QHash, bool> FunctionCache; FunctionCache functionCache; - QHash propertyCache; - static QmlMetaObjectCache *cache(QmlEnginePrivate *priv, QObject *obj) { - if (!priv || !obj || QObjectPrivate::get(obj)->metaObject) return 0; - return &priv->propertyCache[obj->metaObject()]; + QHash propertyCache; + QmlPropertyCache *cache(QObject *obj) { + Q_Q(QmlEngine); + if (!obj || QObjectPrivate::get(obj)->metaObject) return 0; + const QMetaObject *mo = obj->metaObject(); + QmlPropertyCache *rv = propertyCache.value(mo); + if (!rv) { + rv = QmlPropertyCache::create(q, mo); + propertyCache.insert(mo, rv); + } + return rv; } struct Imports { diff --git a/src/declarative/qml/qmlinstruction.cpp b/src/declarative/qml/qmlinstruction.cpp index b71c6e3..18439f4 100644 --- a/src/declarative/qml/qmlinstruction.cpp +++ b/src/declarative/qml/qmlinstruction.cpp @@ -69,7 +69,7 @@ void QmlCompiledData::dump(QmlInstruction *instr, int idx) qWarning() << idx << "\t" << line << "\t" << "CREATE_COMPONENT\t" << instr->createComponent.count; break; case QmlInstruction::StoreMetaObject: - qWarning() << idx << "\t" << line << "\t" << "STORE_META\t\t" << instr->storeMeta.data << "\t" << instr->storeMeta.slotData; + qWarning() << idx << "\t" << line << "\t" << "STORE_META\t\t" << instr->storeMeta.data << "\t"; break; case QmlInstruction::StoreFloat: qWarning() << idx << "\t" << line << "\t" << "STORE_FLOAT\t\t" << instr->storeFloat.propertyIndex << "\t" << instr->storeFloat.value; diff --git a/src/declarative/qml/qmlinstruction_p.h b/src/declarative/qml/qmlinstruction_p.h index 2c9ceac..e62bfdf 100644 --- a/src/declarative/qml/qmlinstruction_p.h +++ b/src/declarative/qml/qmlinstruction_p.h @@ -175,8 +175,8 @@ public: } create; struct { int data; - int slotData; int aliasData; + int propertyCache; } storeMeta; struct { int value; diff --git a/src/declarative/qml/qmlmetaproperty.cpp b/src/declarative/qml/qmlmetaproperty.cpp index efc4a2b..f7882dc 100644 --- a/src/declarative/qml/qmlmetaproperty.cpp +++ b/src/declarative/qml/qmlmetaproperty.cpp @@ -58,56 +58,6 @@ Q_DECLARE_METATYPE(QList); QT_BEGIN_NAMESPACE -QmlMetaObjectCache::QmlMetaObjectCache() -: propertyCache(0) -{ -} - -void QmlMetaObjectCache::init(const QMetaObject *metaObject) -{ - if (propertyCache || !metaObject) - return; - - int propCount = metaObject->propertyCount(); - - propertyCache = new Data[propCount]; - for (int ii = 0; ii < propCount; ++ii) { - QMetaProperty p = metaObject->property(ii); - propertyCache[ii].propType = p.userType(); - propertyCache[ii].coreIndex = ii; - propertyCache[ii].name = QLatin1String(p.name()); - - propertyNameCache.insert(propertyCache[ii].name, ii); - } -} - -QmlMetaObjectCache::~QmlMetaObjectCache() -{ - delete [] propertyCache; -} - -QmlMetaObjectCache::Data * -QmlMetaObjectCache::property(int index, const QMetaObject *metaObject) -{ - init(metaObject); - - return propertyCache + index; -} - -QmlMetaObjectCache::Data * -QmlMetaObjectCache::property(const QString &name, const QMetaObject *metaObject) -{ - init(metaObject); - - QHash::ConstIterator iter = propertyNameCache.find(name); - - if (iter != propertyNameCache.end()) { - return propertyCache + *iter; - } else { - return 0; - } -} - /*! \class QmlMetaProperty \brief The QmlMetaProperty class abstracts accessing QML properties. @@ -258,11 +208,17 @@ void QmlMetaPropertyPrivate::initProperty(QObject *obj, const QString &name) } // Property - QmlMetaObjectCache *cache = QmlEnginePrivate::cache(enginePrivate, obj); + QmlPropertyCache *cache = 0; + QmlDeclarativeData *ddata = QmlDeclarativeData::get(obj); + if (ddata) + cache = ddata->propertyCache; + if (!cache) + cache = enginePrivate?enginePrivate->cache(obj):0; + if (cache) { - QmlMetaObjectCache::Data *data = - cache->property(name, obj->metaObject()); - if (data) { + QmlPropertyCache::Data *data = cache->property(name); + + if (data && !data->isFunction) { type = QmlMetaProperty::Property; propType = data->propType; coreIdx = data->coreIndex; @@ -272,7 +228,7 @@ void QmlMetaPropertyPrivate::initProperty(QObject *obj, const QString &name) QMetaProperty p = QmlMetaType::property(obj, name.toUtf8().constData()); propType = p.userType(); coreIdx = p.propertyIndex(); - if (p.name()) + if (p.name()) type = QmlMetaProperty::Property; } } @@ -1186,13 +1142,12 @@ void QmlMetaProperty::restore(quint32 id, QObject *obj, QmlContext *ctxt) } else if (d->type & Property) { - QmlMetaObjectCache *cache = QmlEnginePrivate::cache(enginePrivate, obj); + QmlPropertyCache *cache = enginePrivate?enginePrivate->cache(obj):0; d->coreIdx = id; if (cache) { - QmlMetaObjectCache::Data *data = - cache->property(id, obj->metaObject()); + QmlPropertyCache::Data *data = cache->property(id); d->propType = data->propType; d->name = data->name; } else { diff --git a/src/declarative/qml/qmlmetaproperty_p.h b/src/declarative/qml/qmlmetaproperty_p.h index 1ccf913..0d96174 100644 --- a/src/declarative/qml/qmlmetaproperty_p.h +++ b/src/declarative/qml/qmlmetaproperty_p.h @@ -58,28 +58,6 @@ QT_BEGIN_NAMESPACE -class QmlMetaObjectCache -{ -public: - QmlMetaObjectCache(); - ~QmlMetaObjectCache(); - - struct Data { - int propType; - int coreIndex; - QString name; - }; - - Data *property(const QString &, const QMetaObject *); - Data *property(int, const QMetaObject *); - -private: - void init(const QMetaObject *); - - Data *propertyCache; - QHash propertyNameCache; -}; - class QmlContext; class QmlMetaPropertyPrivate { diff --git a/src/declarative/qml/qmlpropertycache.cpp b/src/declarative/qml/qmlpropertycache.cpp new file mode 100644 index 0000000..f88b3a3 --- /dev/null +++ b/src/declarative/qml/qmlpropertycache.cpp @@ -0,0 +1,137 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmlpropertycache_p.h" +#include "qmlengine_p.h" + +QmlPropertyCache::QmlPropertyCache() +{ +} + +QmlPropertyCache::~QmlPropertyCache() +{ + for (int ii = 0; ii < indexCache.count(); ++ii) + indexCache.at(ii)->release(); + + for (StringCache::ConstIterator iter = stringCache.begin(); + iter != stringCache.end(); ++iter) + (*iter)->release(); + + for (IdentifierCache::ConstIterator iter = identifierCache.begin(); + iter != identifierCache.end(); ++iter) + (*iter)->release(); +} + +// ### Optimize - check engine for the parent meta object etc. +QmlPropertyCache *QmlPropertyCache::create(QmlEngine *engine, const QMetaObject *metaObject) +{ + Q_ASSERT(engine); + Q_ASSERT(metaObject); + + QmlPropertyCache *cache = new QmlPropertyCache; + + QmlEnginePrivate *enginePriv = QmlEnginePrivate::get(engine); + + // ### The properties/methods should probably be spliced on a per-metaobject basis + int propCount = metaObject->propertyCount(); + + cache->indexCache.resize(propCount); + for (int ii = propCount - 1; ii >= 0; --ii) { + QMetaProperty p = metaObject->property(ii); + QString propName = QLatin1String(p.name()); + + QScriptDeclarativeClass::PersistentIdentifier *data = + enginePriv->objectClass2->createPersistentIdentifier(propName); + data->propType = p.userType(); + data->coreIndex = ii; + data->name = propName; + + cache->indexCache[ii] = data; + + if (cache->stringCache.contains(propName)) + continue; + + cache->stringCache.insert(propName, data); + cache->identifierCache.insert(data->identifier, data); + data->addref(); + data->addref(); + } + + int methodCount = metaObject->methodCount(); + for (int ii = methodCount - 1; ii >= 0; --ii) { + QMetaMethod m = metaObject->method(ii); + QString methodName = QLatin1String(m.signature()); + + int parenIdx = methodName.indexOf(QLatin1Char('(')); + Q_ASSERT(parenIdx != -1); + methodName = methodName.left(parenIdx); + + if (cache->stringCache.contains(methodName)) + continue; + + QScriptDeclarativeClass::PersistentIdentifier *data = + enginePriv->objectClass2->createPersistentIdentifier(methodName); + cache->stringCache.insert(methodName, data); + cache->identifierCache.insert(data->identifier, data); + data->addref(); + data->addref(); + + data->isFunction = true; + } + + return cache; +} + +QmlPropertyCache::Data * +QmlPropertyCache::property(int index) const +{ + if (index < 0 || index >= indexCache.count()) + return 0; + + return indexCache.at(index); +} + +QmlPropertyCache::Data * +QmlPropertyCache::property(const QString &str) const +{ + return stringCache.value(str); +} + diff --git a/src/declarative/qml/qmlpropertycache_p.h b/src/declarative/qml/qmlpropertycache_p.h new file mode 100644 index 0000000..c10fafa --- /dev/null +++ b/src/declarative/qml/qmlpropertycache_p.h @@ -0,0 +1,100 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMLPROPERTYCACHE_P_H +#define QMLPROPERTYCACHE_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include +#include +#include + +QT_BEGIN_NAMESPACE + +class QmlEngine; +class QMetaProperty; +class QmlPropertyCache : public QmlRefCount +{ +public: + QmlPropertyCache(); + virtual ~QmlPropertyCache(); + + struct Data : public QmlRefCount { + Data() : isFunction(false) {} + + bool isFunction; + int propType; + int coreIndex; + QString name; + }; + + static QmlPropertyCache *create(QmlEngine *, const QMetaObject *); + + Data *property(const QScriptDeclarativeClass::Identifier &id) const { + return identifierCache.value(id); + } + + Data *property(const QString &) const; + Data *property(int) const; + +private: + typedef QVector *> IndexCache; + typedef QHash *> StringCache; + typedef QHash *> IdentifierCache; + + IndexCache indexCache; + StringCache stringCache; + IdentifierCache identifierCache; +}; + +QT_END_NAMESPACE + +#endif // QMLPROPERTYCACHE_P_H diff --git a/src/declarative/qml/qmlvme.cpp b/src/declarative/qml/qmlvme.cpp index 44b17e6..a5d2732 100644 --- a/src/declarative/qml/qmlvme.cpp +++ b/src/declarative/qml/qmlvme.cpp @@ -143,6 +143,7 @@ QObject *QmlVME::run(QStack &stack, QmlContext *ctxt, const QList &customTypeData = comp->customTypeData; const QList &intData = comp->intData; const QList &floatData = comp->floatData; + const QList &propertyCaches = comp->propertyCaches; QmlEnginePrivate::SimpleList bindValues; @@ -259,9 +260,15 @@ QObject *QmlVME::run(QStack &stack, QmlContext *ctxt, const QByteArray &metadata = datas.at(instr.storeMeta.data); QMetaObjectBuilder::fromRelocatableData(&mo, 0, metadata); - const QmlVMEMetaData *data = (const QmlVMEMetaData *)datas.at(instr.storeMeta.aliasData).constData(); + const QmlVMEMetaData *data = + (const QmlVMEMetaData *)datas.at(instr.storeMeta.aliasData).constData(); (void)new QmlVMEMetaObject(target, &mo, data, comp); + + QmlDeclarativeData *ddata = QmlDeclarativeData::get(target, true); + if (ddata->propertyCache) ddata->propertyCache->release(); + ddata->propertyCache = propertyCaches.at(instr.storeMeta.propertyCache); + ddata->propertyCache->addref(); } break; -- cgit v0.12