diff options
author | Aaron Kennedy <aaron.kennedy@nokia.com> | 2011-01-27 03:49:12 (GMT) |
---|---|---|
committer | Aaron Kennedy <aaron.kennedy@nokia.com> | 2011-01-27 03:49:12 (GMT) |
commit | d9e4393ef212dba9eeba68277b270d68bcdbc733 (patch) | |
tree | d65ff0df673db66478b081d672f3fe383ae6e5a5 /src/declarative | |
parent | f15778e60ba538b8715f6433a472ffe08a21d934 (diff) | |
download | Qt-d9e4393ef212dba9eeba68277b270d68bcdbc733.zip Qt-d9e4393ef212dba9eeba68277b270d68bcdbc733.tar.gz Qt-d9e4393ef212dba9eeba68277b270d68bcdbc733.tar.bz2 |
Implement property versioning inside the declarative engine
Task-number: QTBUG-13451
Diffstat (limited to 'src/declarative')
-rw-r--r-- | src/declarative/qml/qdeclarativecompileddata.cpp | 30 | ||||
-rw-r--r-- | src/declarative/qml/qdeclarativecompiler.cpp | 174 | ||||
-rw-r--r-- | src/declarative/qml/qdeclarativecompiler_p.h | 7 | ||||
-rw-r--r-- | src/declarative/qml/qdeclarativeengine.cpp | 121 | ||||
-rw-r--r-- | src/declarative/qml/qdeclarativeengine_p.h | 37 | ||||
-rw-r--r-- | src/declarative/qml/qdeclarativemetatype.cpp | 76 | ||||
-rw-r--r-- | src/declarative/qml/qdeclarativemetatype_p.h | 6 | ||||
-rw-r--r-- | src/declarative/qml/qdeclarativeobjectscriptclass.cpp | 21 | ||||
-rw-r--r-- | src/declarative/qml/qdeclarativeparser.cpp | 3 | ||||
-rw-r--r-- | src/declarative/qml/qdeclarativeparser_p.h | 2 | ||||
-rw-r--r-- | src/declarative/qml/qdeclarativepropertycache.cpp | 21 | ||||
-rw-r--r-- | src/declarative/qml/qdeclarativepropertycache_p.h | 37 | ||||
-rw-r--r-- | src/declarative/qml/qdeclarativetypeloader.cpp | 2 | ||||
-rw-r--r-- | src/declarative/qml/qdeclarativetypeloader_p.h | 4 | ||||
-rw-r--r-- | src/declarative/qml/qdeclarativevme.cpp | 15 |
15 files changed, 435 insertions, 121 deletions
diff --git a/src/declarative/qml/qdeclarativecompileddata.cpp b/src/declarative/qml/qdeclarativecompileddata.cpp index 70cace4..03deea1 100644 --- a/src/declarative/qml/qdeclarativecompileddata.cpp +++ b/src/declarative/qml/qdeclarativecompileddata.cpp @@ -171,6 +171,8 @@ QDeclarativeCompiledData::~QDeclarativeCompiledData() for (int ii = 0; ii < types.count(); ++ii) { if (types.at(ii).component) types.at(ii).component->release(); + if (types.at(ii).typePropertyCache) + types.at(ii).typePropertyCache->release(); } for (int ii = 0; ii < propertyCaches.count(); ++ii) @@ -209,6 +211,34 @@ const QMetaObject *QDeclarativeCompiledData::TypeReference::metaObject() const } } +/*! +Returns the property cache, if one alread exists. The cache is not referenced. +*/ +QDeclarativePropertyCache *QDeclarativeCompiledData::TypeReference::propertyCache() const +{ + if (type) + return typePropertyCache; + else + return component->rootPropertyCache; +} + +/*! +Returns the property cache, creating one if it doesn't already exist. The cache is not referenced. +*/ +QDeclarativePropertyCache *QDeclarativeCompiledData::TypeReference::createPropertyCache(QDeclarativeEngine *engine) +{ + if (typePropertyCache) { + return typePropertyCache; + } else if (type) { + typePropertyCache = QDeclarativeEnginePrivate::get(engine)->cache(type->metaObject()); + typePropertyCache->addref(); + return typePropertyCache; + } else { + return component->rootPropertyCache; + } +} + + void QDeclarativeCompiledData::dumpInstructions() { if (!name.isEmpty()) diff --git a/src/declarative/qml/qdeclarativecompiler.cpp b/src/declarative/qml/qdeclarativecompiler.cpp index 8bfc260..a0236c0 100644 --- a/src/declarative/qml/qdeclarativecompiler.cpp +++ b/src/declarative/qml/qdeclarativecompiler.cpp @@ -589,6 +589,18 @@ bool QDeclarativeCompiler::compile(QDeclarativeEngine *engine, err = tr( "Element is not creatable."); COMPILE_EXCEPTION(parserRef->refObjects.first(), err); } + + if (ref.type->containsRevisionedAttributes()) { + QDeclarativeError cacheError; + ref.typePropertyCache = + QDeclarativeEnginePrivate::get(engine)->cache(ref.type, resolvedTypes.at(ii).minorVersion, cacheError); + + if (!ref.typePropertyCache) { + COMPILE_EXCEPTION(parserRef->refObjects.first(), cacheError.description()); + } + ref.typePropertyCache->addref(); + } + } else if (tref.typeData) { ref.component = tref.typeData->compiledData(); } @@ -886,8 +898,7 @@ bool QDeclarativeCompiler::buildObject(Object *obj, const BindingContext &ctxt) void QDeclarativeCompiler::genObject(QDeclarativeParser::Object *obj) { - const QDeclarativeCompiledData::TypeReference &tr = - output->types.at(obj->type); + QDeclarativeCompiledData::TypeReference &tr = output->types[obj->type]; if (tr.type && obj->metatype == &QDeclarativeComponent::staticMetaObject) { genComponent(obj); return; @@ -936,16 +947,10 @@ void QDeclarativeCompiler::genObject(QDeclarativeParser::Object *obj) meta.storeMeta.data = output->indexForByteArray(obj->metadata); meta.storeMeta.aliasData = output->indexForByteArray(obj->synthdata); meta.storeMeta.propertyCache = output->propertyCaches.count(); - // ### Surely the creation of this property cache could be more efficient - QDeclarativePropertyCache *propertyCache = 0; - if (tr.component) - propertyCache = tr.component->rootPropertyCache->copy(); - else - propertyCache = enginePrivate->cache(obj->metaObject()->superClass())->copy(); - propertyCache->append(engine, obj->metaObject(), QDeclarativePropertyCache::Data::NoFlags, - QDeclarativePropertyCache::Data::IsVMEFunction, - QDeclarativePropertyCache::Data::IsVMESignal); + QDeclarativePropertyCache *propertyCache = obj->synthCache; + Q_ASSERT(propertyCache); + propertyCache->addref(); // Add flag for alias properties if (!obj->synthdata.isEmpty()) { @@ -965,11 +970,7 @@ void QDeclarativeCompiler::genObject(QDeclarativeParser::Object *obj) output->propertyCaches << propertyCache; output->bytecode << meta; } else if (obj == unitRoot) { - if (tr.component) - output->rootPropertyCache = tr.component->rootPropertyCache; - else - output->rootPropertyCache = enginePrivate->cache(obj->metaObject()); - + output->rootPropertyCache = tr.createPropertyCache(engine); output->rootPropertyCache->addref(); } @@ -1104,15 +1105,7 @@ void QDeclarativeCompiler::genObjectBody(QDeclarativeParser::Object *obj) meta.line = 0; meta.storeMeta.data = output->indexForByteArray(prop->value->metadata); meta.storeMeta.aliasData = output->indexForByteArray(prop->value->synthdata); - meta.storeMeta.propertyCache = output->propertyCaches.count(); - // ### Surely the creation of this property cache could be more efficient - QDeclarativePropertyCache *propertyCache = - enginePrivate->cache(prop->value->metaObject()->superClass())->copy(); - propertyCache->append(engine, prop->value->metaObject(), QDeclarativePropertyCache::Data::NoFlags, - QDeclarativePropertyCache::Data::IsVMEFunction, - QDeclarativePropertyCache::Data::IsVMESignal); - - output->propertyCaches << propertyCache; + meta.storeMeta.propertyCache = -1; output->bytecode << meta; } @@ -1352,11 +1345,18 @@ bool QDeclarativeCompiler::buildSignal(QDeclarativeParser::Property *prop, QDecl if(name[0] >= 'A' && name[0] <= 'Z') name[0] = name[0] - 'A' + 'a'; - QMetaMethod method = QDeclarativePropertyPrivate::findSignalByName(obj->metaObject(), name); - int sigIdx = method.methodIndex(); + bool notInRevision = false; + int sigIdx = indexOfSignal(obj, name, ¬InRevision); if (sigIdx == -1) { + if (notInRevision && -1 == indexOfProperty(obj, prop->name, 0)) { + Q_ASSERT(obj->type != -1); + const QList<QDeclarativeTypeData::TypeReference> &resolvedTypes = unit->resolvedTypes(); + const QDeclarativeTypeData::TypeReference &type = resolvedTypes.at(obj->type); + COMPILE_EXCEPTION(prop, tr("\"%1.%2\" is not available in %3 %4.%5.").arg(QString::fromUtf8(obj->className)).arg(QString::fromUtf8(prop->name)).arg(QString::fromUtf8(type.type->module())).arg(type.majorVersion).arg(type.minorVersion)); + } + // If the "on<Signal>" name doesn't resolve into a signal, try it as a // property. COMPILE_CHECK(buildProperty(prop, obj, ctxt)); @@ -1366,13 +1366,6 @@ bool QDeclarativeCompiler::buildSignal(QDeclarativeParser::Property *prop, QDecl if (prop->value || prop->values.count() != 1) COMPILE_EXCEPTION(prop, tr("Incorrectly specified signal assignment")); - if (method.revision() > 0) { - QDeclarativeType *type = output->types.at(obj->type).type; - if (!type->isMethodAvailable(sigIdx, method.revision())) { - COMPILE_EXCEPTION(prop, tr("Signal \"%1\" not available in %2 %3.%4").arg(QString::fromUtf8(prop->name)).arg(QString::fromUtf8(type->qmlTypeName())).arg(obj->majorVersion).arg(obj->minorVersion)); - } - } - prop->index = sigIdx; obj->addSignalProperty(prop); @@ -1412,7 +1405,7 @@ bool QDeclarativeCompiler::doesPropertyExist(QDeclarativeParser::Property *prop, QMetaProperty p = QDeclarativeMetaType::defaultProperty(mo); return p.name() != 0; } else { - int idx = mo->indexOfProperty(prop->name.constData()); + int idx = indexOfProperty(obj, prop->name); return idx != -1 && mo->property(idx).isScriptable(); } } @@ -1473,7 +1466,13 @@ bool QDeclarativeCompiler::buildProperty(QDeclarativeParser::Property *prop, } } else { - prop->index = metaObject->indexOfProperty(prop->name.constData()); + bool notInRevision = false; + prop->index = indexOfProperty(obj, prop->name, ¬InRevision); + if (prop->index == -1 && notInRevision) { + const QList<QDeclarativeTypeData::TypeReference> &resolvedTypes = unit->resolvedTypes(); + const QDeclarativeTypeData::TypeReference &type = resolvedTypes.at(obj->type); + COMPILE_EXCEPTION(prop, tr("\"%1.%2\" is not available in %3 %4.%5.").arg(QString::fromUtf8(obj->className)).arg(QString::fromUtf8(prop->name)).arg(QString::fromUtf8(type.type->module())).arg(type.majorVersion).arg(type.minorVersion)); + } if (prop->index != -1) { p = metaObject->property(prop->index); @@ -1488,15 +1487,8 @@ bool QDeclarativeCompiler::buildProperty(QDeclarativeParser::Property *prop, // We can't error here as the "id" property does not require a // successful index resolution - if (p.name()) { + if (p.name()) prop->type = p.userType(); - if (p.revision() > 0) { - QDeclarativeType *type = output->types.at(obj->type).type; - if (!type->isPropertyAvailable(prop->index, p.revision())) { - COMPILE_EXCEPTION(prop, tr("Property \"%1\" not available in %2 %3.%4").arg(QString::fromUtf8(prop->name)).arg(QString::fromUtf8(type->qmlTypeName())).arg(obj->majorVersion).arg(obj->minorVersion)); - } - } - } // Check if this is an alias if (prop->index != -1 && @@ -2430,8 +2422,7 @@ bool QDeclarativeCompiler::buildDynamicMeta(QDeclarativeParser::Object *obj, Dyn for (int ii = 0; ii < obj->dynamicProperties.count(); ++ii) { const Object::DynamicProperty &p = obj->dynamicProperties.at(ii); - int propIdx = - obj->metaObject()->indexOfProperty(p.name.constData()); + int propIdx = obj->metaObject()->indexOfProperty(p.name.constData()); if (-1 != propIdx) { QMetaProperty prop = obj->metaObject()->property(propIdx); if (prop.isFinal()) @@ -2616,6 +2607,19 @@ bool QDeclarativeCompiler::buildDynamicMeta(QDeclarativeParser::Object *obj, Dyn obj->synthdata = dynamicData; + if (obj->synthCache) { + obj->synthCache->release(); + obj->synthCache = 0; + } + + if (obj->type != -1) { + QDeclarativePropertyCache *cache = output->types[obj->type].createPropertyCache(engine)->copy(); + cache->append(engine, &obj->extObject, QDeclarativePropertyCache::Data::NoFlags, + QDeclarativePropertyCache::Data::IsVMEFunction, + QDeclarativePropertyCache::Data::IsVMESignal); + obj->synthCache = cache; + } + return true; } @@ -2665,9 +2669,9 @@ static QStringList astNodeToStringList(QDeclarativeJS::AST::Node *node) } bool QDeclarativeCompiler::compileAlias(QMetaObjectBuilder &builder, - QByteArray &data, - Object *obj, - const Object::DynamicProperty &prop) + QByteArray &data, + Object *obj, + const Object::DynamicProperty &prop) { if (!prop.defaultValue) COMPILE_EXCEPTION(obj, tr("No property alias location")); @@ -2697,7 +2701,7 @@ bool QDeclarativeCompiler::compileAlias(QMetaObjectBuilder &builder, int flags = 0; bool writable = false; if (alias.count() == 2 || alias.count() == 3) { - propIdx = idObject->metaObject()->indexOfProperty(alias.at(1).toUtf8().constData()); + propIdx = indexOfProperty(idObject, alias.at(1).toUtf8()); if (-1 == propIdx) { COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location")); @@ -3038,4 +3042,74 @@ QStringList QDeclarativeCompiler::deferredProperties(QDeclarativeParser::Object return rv; } +// This code must match the semantics of QDeclarativePropertyPrivate::findSignalByName +int QDeclarativeCompiler::indexOfSignal(QDeclarativeParser::Object *object, const QByteArray &name, + bool *notInRevision) +{ + if (notInRevision) *notInRevision = false; + + if (object->synthCache || (object->type != -1 && output->types.at(object->type).propertyCache())) { + // XXX fromUtf8 + QString strName(QString::fromUtf8(name)); + QDeclarativePropertyCache *cache = + object->synthCache?object->synthCache:output->types.at(object->type).propertyCache(); + + QDeclarativePropertyCache::Data *d = cache->property(strName); + if (notInRevision) *notInRevision = false; + + while (d && !(d->flags & QDeclarativePropertyCache::Data::IsFunction)) + d = cache->overrideData(d); + + if (d && !cache->isAllowedInRevision(d)) { + if (notInRevision) *notInRevision = true; + return -1; + } else if (d) { + return d->coreIndex; + } + + if (name.endsWith("Changed")) { + QByteArray propName = name.mid(0, name.length() - 7); + + int propIndex = indexOfProperty(object, propName, notInRevision); + if (propIndex != -1) { + d = cache->property(propIndex); + return d->notifyIndex; + } + } + + return -1; + } else { + return QDeclarativePropertyPrivate::findSignalByName(object->metaObject(), name).methodIndex(); + } + +} + +int QDeclarativeCompiler::indexOfProperty(QDeclarativeParser::Object *object, const QByteArray &name, + bool *notInRevision) +{ + if (notInRevision) *notInRevision = false; + + if (object->synthCache || (object->type != -1 && output->types.at(object->type).propertyCache())) { + // XXX fromUtf8 + QString strName(QString::fromUtf8(name)); + QDeclarativePropertyCache *cache = + object->synthCache?object->synthCache:output->types.at(object->type).propertyCache(); + + QDeclarativePropertyCache::Data *d = cache->property(strName); + // Find the first property + while (d && d->flags & QDeclarativePropertyCache::Data::IsFunction) + d = cache->overrideData(d); + + if (d && !cache->isAllowedInRevision(d)) { + if (notInRevision) *notInRevision = true; + return -1; + } else { + return d?d->coreIndex:-1; + } + } else { + const QMetaObject *mo = object->metaObject(); + return mo->indexOfProperty(name.constData()); + } +} + QT_END_NAMESPACE diff --git a/src/declarative/qml/qdeclarativecompiler_p.h b/src/declarative/qml/qdeclarativecompiler_p.h index 5e990e7..93b6a09 100644 --- a/src/declarative/qml/qdeclarativecompiler_p.h +++ b/src/declarative/qml/qdeclarativecompiler_p.h @@ -89,14 +89,17 @@ public: struct TypeReference { TypeReference() - : type(0), component(0) {} + : type(0), typePropertyCache(0), component(0) {} QByteArray className; QDeclarativeType *type; + QDeclarativePropertyCache *typePropertyCache; QDeclarativeCompiledData *component; QObject *createInstance(QDeclarativeContextData *, const QBitField &, QList<QDeclarativeError> *) const; const QMetaObject *metaObject() const; + QDeclarativePropertyCache *propertyCache() const; + QDeclarativePropertyCache *createPropertyCache(QDeclarativeEngine *); }; QList<TypeReference> types; struct CustomTypeData @@ -277,6 +280,8 @@ private: bool canCoerce(int to, QDeclarativeParser::Object *from); QStringList deferredProperties(QDeclarativeParser::Object *); + int indexOfProperty(QDeclarativeParser::Object *, const QByteArray &, bool *notInRevision = 0); + int indexOfSignal(QDeclarativeParser::Object *, const QByteArray &, bool *notInRevision = 0); void addId(const QString &, QDeclarativeParser::Object *); diff --git a/src/declarative/qml/qdeclarativeengine.cpp b/src/declarative/qml/qdeclarativeengine.cpp index 99a098e..e3be599 100644 --- a/src/declarative/qml/qdeclarativeengine.cpp +++ b/src/declarative/qml/qdeclarativeengine.cpp @@ -460,6 +460,8 @@ QDeclarativeEnginePrivate::~QDeclarativeEnginePrivate() (*iter)->release(); for(QHash<const QMetaObject *, QDeclarativePropertyCache *>::Iterator iter = propertyCache.begin(); iter != propertyCache.end(); ++iter) (*iter)->release(); + for(QHash<QPair<QDeclarativeType *, int>, QDeclarativePropertyCache *>::Iterator iter = typePropertyCache.begin(); iter != typePropertyCache.end(); ++iter) + (*iter)->release(); } @@ -2207,6 +2209,125 @@ static void *voidptr_constructor(const void *v) } } +QDeclarativePropertyCache *QDeclarativeEnginePrivate::createCache(const QMetaObject *mo) +{ + Q_Q(QDeclarativeEngine); + + if (!mo->superClass()) { + QDeclarativePropertyCache *rv = new QDeclarativePropertyCache(q, mo); + propertyCache.insert(mo, rv); + return rv; + } else { + QDeclarativePropertyCache *super = cache(mo->superClass()); + QDeclarativePropertyCache *rv = super->copy(); + rv->append(q, mo); + propertyCache.insert(mo, rv); + return rv; + } +} + +QDeclarativePropertyCache *QDeclarativeEnginePrivate::createCache(QDeclarativeType *type, int minorVersion, + QDeclarativeError &error) +{ + QList<QDeclarativeType *> types; + + int maxMinorVersion = 0; + + const QMetaObject *metaObject = type->metaObject(); + while (metaObject) { + QDeclarativeType *t = QDeclarativeMetaType::qmlType(metaObject, type->module(), + type->majorVersion(), minorVersion); + if (t) { + maxMinorVersion = qMax(maxMinorVersion, t->minorVersion()); + types << t; + } else { + types << 0; + } + + metaObject = metaObject->superClass(); + } + + if (QDeclarativePropertyCache *c = typePropertyCache.value(qMakePair(type, maxMinorVersion))) { + c->addref(); + typePropertyCache.insert(qMakePair(type, minorVersion), c); + return c; + } + + QDeclarativePropertyCache *raw = cache(type->metaObject()); + + bool hasCopied = false; + + for (int ii = 0; ii < types.count(); ++ii) { + QDeclarativeType *currentType = types.at(ii); + if (!currentType) + continue; + + int rev = currentType->metaObjectRevision(); + int moIndex = types.count() - 1 - ii; + + if (raw->allowedRevisionCache[moIndex] != rev) { + if (!hasCopied) { + raw = raw->copy(); + hasCopied = true; + } + raw->allowedRevisionCache[moIndex] = rev; + } + } + + // Test revision compatibility - the basic rule is: + // * Anything that is excluded, cannot overload something that is not excluded * + + // Signals override: + // * other signals and methods of the same name. + // * properties named on<Signal Name> + // * automatic <property name>Changed notify signals + + // Methods override: + // * other methods of the same name + + // Properties override: + // * other elements of the same name + + bool overloadError = false; + QString overloadName; + +#if 0 + for (QDeclarativePropertyCache::StringCache::ConstIterator iter = raw->stringCache.begin(); + !overloadError && iter != raw->stringCache.end(); + ++iter) { + + QDeclarativePropertyCache::Data *d = *iter; + if (raw->isAllowedInRevision(d)) + continue; // Not excluded - no problems + + // check that a regular "name" overload isn't happening + QDeclarativePropertyCache::Data *current = d; + while (!overloadError && current) { + current = d->overrideData(current); + if (current && raw->isAllowedInRevision(current)) + overloadError = true; + } + } +#endif + + if (overloadError) { + if (hasCopied) raw->release(); + + error.setDescription(QLatin1String("Type ") + QString::fromUtf8(type->qmlTypeName()) + QLatin1String(" ") + QString::number(type->majorVersion()) + QLatin1String(".") + QString::number(minorVersion) + QLatin1String(" contains an illegal property \"") + overloadName + QLatin1String("\". This is an error in the type's implementation.")); + return 0; + } + + if (!hasCopied) raw->addref(); + typePropertyCache.insert(qMakePair(type, minorVersion), raw); + + if (minorVersion != maxMinorVersion) { + raw->addref(); + typePropertyCache.insert(qMakePair(type, maxMinorVersion), raw); + } + + return raw; +} + void QDeclarativeEnginePrivate::registerCompositeType(QDeclarativeCompiledData *data) { QByteArray name = data->root->className(); diff --git a/src/declarative/qml/qdeclarativeengine_p.h b/src/declarative/qml/qdeclarativeengine_p.h index fc996b5..1cc9dc5 100644 --- a/src/declarative/qml/qdeclarativeengine_p.h +++ b/src/declarative/qml/qdeclarativeengine_p.h @@ -251,8 +251,12 @@ public: QDeclarativeValueTypeFactory valueTypes; QHash<const QMetaObject *, QDeclarativePropertyCache *> propertyCache; + QHash<QPair<QDeclarativeType *, int>, QDeclarativePropertyCache *> typePropertyCache; inline QDeclarativePropertyCache *cache(QObject *obj); inline QDeclarativePropertyCache *cache(const QMetaObject *); + inline QDeclarativePropertyCache *cache(QDeclarativeType *, int, QDeclarativeError &error); + QDeclarativePropertyCache *createCache(const QMetaObject *); + QDeclarativePropertyCache *createCache(QDeclarativeType *, int, QDeclarativeError &error); void registerCompositeType(QDeclarativeCompiledData *); @@ -330,19 +334,17 @@ Returns a QDeclarativePropertyCache for \a obj if one is available. If \a obj is null, being deleted or contains a dynamic meta object 0 is returned. + +The returned cache is not referenced, so if it is to be stored, call addref(). */ QDeclarativePropertyCache *QDeclarativeEnginePrivate::cache(QObject *obj) { - Q_Q(QDeclarativeEngine); if (!obj || QObjectPrivate::get(obj)->metaObject || QObjectPrivate::get(obj)->wasDeleted) return 0; const QMetaObject *mo = obj->metaObject(); QDeclarativePropertyCache *rv = propertyCache.value(mo); - if (!rv) { - rv = new QDeclarativePropertyCache(q, mo); - propertyCache.insert(mo, rv); - } + if (!rv) rv = createCache(mo); return rv; } @@ -352,18 +354,33 @@ Returns a QDeclarativePropertyCache for \a metaObject. As the cache is persisted for the life of the engine, \a metaObject must be a static "compile time" meta-object, or a meta-object that is otherwise known to exist for the lifetime of the QDeclarativeEngine. + +The returned cache is not referenced, so if it is to be stored, call addref(). */ QDeclarativePropertyCache *QDeclarativeEnginePrivate::cache(const QMetaObject *metaObject) { - Q_Q(QDeclarativeEngine); Q_ASSERT(metaObject); QDeclarativePropertyCache *rv = propertyCache.value(metaObject); - if (!rv) { - rv = new QDeclarativePropertyCache(q, metaObject); - propertyCache.insert(metaObject, rv); - } + if (!rv) rv = createCache(metaObject); + return rv; +} + +/*! +Returns a QDeclarativePropertyCache for \a type with \a minorVersion. + +The returned cache is not referenced, so if it is to be stored, call addref(). +*/ +QDeclarativePropertyCache *QDeclarativeEnginePrivate::cache(QDeclarativeType *type, int minorVersion, QDeclarativeError &error) +{ + Q_ASSERT(type); + Q_ASSERT(minorVersion >= 0); + + if (!type->containsRevisionedAttributes()) + return cache(type->metaObject()); + QDeclarativePropertyCache *rv = typePropertyCache.value(qMakePair(type, minorVersion)); + if (!rv) rv = createCache(type, minorVersion, error); return rv; } diff --git a/src/declarative/qml/qdeclarativemetatype.cpp b/src/declarative/qml/qdeclarativemetatype.cpp index bdac3d0..4867cc5 100644 --- a/src/declarative/qml/qdeclarativemetatype.cpp +++ b/src/declarative/qml/qdeclarativemetatype.cpp @@ -140,6 +140,7 @@ public: int m_version_min; int m_typeId; int m_listId; int m_revision; + mutable bool m_containsRevisionedAttributes; mutable QDeclarativeType *m_superType; int m_allocationSize; @@ -167,10 +168,11 @@ public: QHash<const QMetaObject *, int> QDeclarativeTypePrivate::m_attachedPropertyIds; QDeclarativeTypePrivate::QDeclarativeTypePrivate() -: m_isInterface(false), m_iid(0), m_typeId(0), m_listId(0), m_revision(0), m_superType(0), - m_allocationSize(0), m_newFunc(0), m_baseMetaObject(0), m_attachedPropertiesFunc(0), m_attachedPropertiesType(0), - m_parserStatusCast(-1), m_propertyValueSourceCast(-1), m_propertyValueInterceptorCast(-1), - m_extFunc(0), m_extMetaObject(0), m_index(-1), m_customParser(0), m_isSetup(false), m_haveSuperType(false) +: m_isInterface(false), m_iid(0), m_typeId(0), m_listId(0), m_revision(0), m_containsRevisionedAttributes(false), + m_superType(0), m_allocationSize(0), m_newFunc(0), m_baseMetaObject(0), m_attachedPropertiesFunc(0), + m_attachedPropertiesType(0), m_parserStatusCast(-1), m_propertyValueSourceCast(-1), + m_propertyValueInterceptorCast(-1), m_extFunc(0), m_extMetaObject(0), m_index(-1), m_customParser(0), + m_isSetup(false), m_haveSuperType(false) { } @@ -235,6 +237,11 @@ QDeclarativeType::~QDeclarativeType() delete d; } +QByteArray QDeclarativeType::module() const +{ + return d->m_module; +} + int QDeclarativeType::majorVersion() const { return d->m_version_maj; @@ -270,36 +277,6 @@ QDeclarativeType *QDeclarativeType::superType() const return d->m_superType; } -bool QDeclarativeType::isPropertyAvailable(int index, int revision) const -{ - if (revision == 0) - return true; - - if (index < d->m_baseMetaObject->propertyOffset()) { - if (QDeclarativeType *super = superType()) - return super->isPropertyAvailable(index, revision); - } else if (index < d->m_baseMetaObject->propertyOffset() + d->m_baseMetaObject->propertyCount()) { - return d->m_revision >= revision; - } - - return false; -} - -bool QDeclarativeType::isMethodAvailable(int index, int revision) const -{ - if (revision == 0) - return true; - - if (index < d->m_baseMetaObject->methodOffset()) { - if (QDeclarativeType *super = superType()) - return super->isMethodAvailable(index, revision); - } else if (index < d->m_baseMetaObject->methodOffset() + d->m_baseMetaObject->methodCount()) { - return d->m_revision >= revision; - } - - return false; -} - static void clone(QMetaObjectBuilder &builder, const QMetaObject *mo, const QMetaObject *ignoreStart, const QMetaObject *ignoreEnd) { @@ -413,6 +390,25 @@ void QDeclarativeTypePrivate::init() const m_metaObjects[ii].methodOffset = m_metaObjects.at(ii).metaObject->methodOffset(); } + + // Check for revisioned details + { + const QMetaObject *mo = 0; + if (m_metaObjects.isEmpty()) + mo = m_baseMetaObject; + else + mo = m_metaObjects.first().metaObject; + + for (int ii = 0; !m_containsRevisionedAttributes && ii < mo->propertyCount(); ++ii) { + if (mo->property(ii).revision() != 0) + m_containsRevisionedAttributes = true; + } + + for (int ii = 0; !m_containsRevisionedAttributes && ii < mo->methodCount(); ++ii) { + if (mo->method(ii).revision() != 0) + m_containsRevisionedAttributes = true; + } + } m_isSetup = true; lock.unlock(); @@ -521,6 +517,18 @@ const QMetaObject *QDeclarativeType::baseMetaObject() const return d->m_baseMetaObject; } +bool QDeclarativeType::containsRevisionedAttributes() const +{ + d->init(); + + return d->m_containsRevisionedAttributes; +} + +int QDeclarativeType::metaObjectRevision() const +{ + return d->m_revision; +} + QDeclarativeAttachedPropertiesFunc QDeclarativeType::attachedPropertiesFunction() const { return d->m_attachedPropertiesFunc; diff --git a/src/declarative/qml/qdeclarativemetatype_p.h b/src/declarative/qml/qdeclarativemetatype_p.h index 564218f..0e4d61c 100644 --- a/src/declarative/qml/qdeclarativemetatype_p.h +++ b/src/declarative/qml/qdeclarativemetatype_p.h @@ -113,12 +113,12 @@ public: QByteArray typeName() const; QByteArray qmlTypeName() const; + QByteArray module() const; int majorVersion() const; int minorVersion() const; + bool availableInVersion(int vmajor, int vminor) const; bool availableInVersion(const QByteArray &module, int vmajor, int vminor) const; - bool isPropertyAvailable(int index, int revision) const; - bool isMethodAvailable(int index, int revision) const; QObject *create() const; void create(QObject **, void **, size_t) const; @@ -139,6 +139,8 @@ public: const QMetaObject *metaObject() const; const QMetaObject *baseMetaObject() const; + int metaObjectRevision() const; + bool containsRevisionedAttributes() const; QDeclarativeAttachedPropertiesFunc attachedPropertiesFunction() const; const QMetaObject *attachedPropertiesType() const; diff --git a/src/declarative/qml/qdeclarativeobjectscriptclass.cpp b/src/declarative/qml/qdeclarativeobjectscriptclass.cpp index 1c2aec9..cbbf2b9 100644 --- a/src/declarative/qml/qdeclarativeobjectscriptclass.cpp +++ b/src/declarative/qml/qdeclarativeobjectscriptclass.cpp @@ -149,8 +149,8 @@ QDeclarativeObjectScriptClass::queryProperty(Object *object, const Identifier &n QScriptClass::QueryFlags QDeclarativeObjectScriptClass::queryProperty(QObject *obj, const Identifier &name, - QScriptClass::QueryFlags flags, QDeclarativeContextData *evalContext, - QueryHints hints) + QScriptClass::QueryFlags flags, QDeclarativeContextData *evalContext, + QueryHints hints) { Q_UNUSED(flags); lastData = 0; @@ -165,19 +165,10 @@ QDeclarativeObjectScriptClass::queryProperty(QObject *obj, const Identifier &nam QDeclarativeEnginePrivate *enginePrivate = QDeclarativeEnginePrivate::get(engine); lastData = QDeclarativePropertyCache::property(engine, obj, name, local); - - if (lastData && lastData->revision > 0 && (hints & ImplicitObject)) { - QDeclarativeData *data = QDeclarativeData::get(obj); - if (data) { - if (!data->type) { - lastData = 0; - } else if (lastData->flags & QDeclarativePropertyCache::Data::IsFunction) { - if (!data->type->isMethodAvailable(lastData->coreIndex, lastData->revision)) - lastData = 0; - } else if (!data->type->isPropertyAvailable(lastData->coreIndex, lastData->revision)) { - lastData = 0; - } - } + if ((hints & ImplicitObject) && lastData && lastData->revision != 0) { + QDeclarativeData *ddata = QDeclarativeData::get(obj); + if (ddata && ddata->propertyCache && !ddata->propertyCache->isAllowedInRevision(lastData)) + return 0; } if (lastData) diff --git a/src/declarative/qml/qdeclarativeparser.cpp b/src/declarative/qml/qdeclarativeparser.cpp index da4016e..35bb0f1 100644 --- a/src/declarative/qml/qdeclarativeparser.cpp +++ b/src/declarative/qml/qdeclarativeparser.cpp @@ -66,13 +66,14 @@ using namespace QDeclarativeJS; using namespace QDeclarativeParser; QDeclarativeParser::Object::Object() -: type(-1), majorVersion(-1), minorVersion(-1), idIndex(-1), metatype(0), defaultProperty(0), parserStatusCast(-1) +: type(-1), majorVersion(-1), minorVersion(-1), idIndex(-1), metatype(0), synthCache(0), defaultProperty(0), parserStatusCast(-1) { } QDeclarativeParser::Object::~Object() { if (defaultProperty) defaultProperty->release(); + if (synthCache) synthCache->release(); foreach(Property *prop, properties) prop->release(); foreach(Property *prop, valueProperties) diff --git a/src/declarative/qml/qdeclarativeparser_p.h b/src/declarative/qml/qdeclarativeparser_p.h index 6ef2811..8f41a91 100644 --- a/src/declarative/qml/qdeclarativeparser_p.h +++ b/src/declarative/qml/qdeclarativeparser_p.h @@ -71,6 +71,7 @@ QT_BEGIN_NAMESPACE QT_MODULE(Declarative) +class QDeclarativePropertyCache; namespace QDeclarativeJS { namespace AST { class Node; } } /* @@ -154,6 +155,7 @@ namespace QDeclarativeParser QAbstractDynamicMetaObject extObject; QByteArray metadata; // Generated by compiler QByteArray synthdata; // Generated by compiler + QDeclarativePropertyCache *synthCache; // Generated by compiler Property *getDefaultProperty(); Property *getProperty(const QByteArray &name, bool create=true); diff --git a/src/declarative/qml/qdeclarativepropertycache.cpp b/src/declarative/qml/qdeclarativepropertycache.cpp index 5397694..6a39a65 100644 --- a/src/declarative/qml/qdeclarativepropertycache.cpp +++ b/src/declarative/qml/qdeclarativepropertycache.cpp @@ -218,6 +218,7 @@ QDeclarativePropertyCache *QDeclarativePropertyCache::copy() const cache->methodIndexCache = methodIndexCache; cache->stringCache = stringCache; cache->identifierCache = identifierCache; + cache->allowedRevisionCache = allowedRevisionCache; for (int ii = 0; ii < indexCache.count(); ++ii) { if (indexCache.at(ii)) indexCache.at(ii)->addref(); @@ -236,6 +237,17 @@ QDeclarativePropertyCache *QDeclarativePropertyCache::copy() const void QDeclarativePropertyCache::append(QDeclarativeEngine *engine, const QMetaObject *metaObject, Data::Flag propertyFlags, Data::Flag methodFlags, Data::Flag signalFlags) { + append(engine, metaObject, -1, propertyFlags, methodFlags, signalFlags); +} + +void QDeclarativePropertyCache::append(QDeclarativeEngine *engine, const QMetaObject *metaObject, + int revision, + Data::Flag propertyFlags, Data::Flag methodFlags, Data::Flag signalFlags) +{ + Q_UNUSED(revision); + + allowedRevisionCache.append(0); + QDeclarativeEnginePrivate *enginePriv = QDeclarativeEnginePrivate::get(engine); int methodCount = metaObject->methodCount(); // 3 to block the destroyed signal and the deleteLater() slot @@ -262,11 +274,15 @@ void QDeclarativePropertyCache::append(QDeclarativeEngine *engine, const QMetaOb else if (m.methodType() == QMetaMethod::Signal) data->flags |= signalFlags; + data->metaObjectOffset = allowedRevisionCache.count() - 1; + if (stringCache.contains(methodName)) { RData *old = stringCache[methodName]; // We only overload methods in the same class, exactly like C++ if (old->flags & Data::IsFunction && old->coreIndex >= methodOffset) data->relatedIndex = old->coreIndex; + data->overrideIndexIsProperty = !bool(old->flags & Data::IsFunction); + data->overrideIndex = old->coreIndex; stringCache[methodName]->release(); identifierCache[data->identifier.identifier]->release(); } @@ -295,7 +311,12 @@ void QDeclarativePropertyCache::append(QDeclarativeEngine *engine, const QMetaOb data->load(p, engine); data->flags |= propertyFlags; + data->metaObjectOffset = allowedRevisionCache.count() - 1; + if (stringCache.contains(propName)) { + RData *old = stringCache[propName]; + data->overrideIndexIsProperty = !bool(old->flags & Data::IsFunction); + data->overrideIndex = old->coreIndex; stringCache[propName]->release(); identifierCache[data->identifier.identifier]->release(); } diff --git a/src/declarative/qml/qdeclarativepropertycache_p.h b/src/declarative/qml/qdeclarativepropertycache_p.h index 2f02c98..eeeff1a 100644 --- a/src/declarative/qml/qdeclarativepropertycache_p.h +++ b/src/declarative/qml/qdeclarativepropertycache_p.h @@ -110,7 +110,10 @@ public: int notifyIndex; // When !IsFunction int relatedIndex; // When IsFunction }; - int revision; + uint overrideIndexIsProperty : 1; + int overrideIndex : 31; + int revision; + int metaObjectOffset; static Flags flagsForProperty(const QMetaProperty &, QDeclarativeEngine *engine = 0); void load(const QMetaProperty &, QDeclarativeEngine *engine = 0); @@ -132,8 +135,9 @@ public: QDeclarativePropertyCache *copy() const; void append(QDeclarativeEngine *, const QMetaObject *, Data::Flag propertyFlags = Data::NoFlags, Data::Flag methodFlags = Data::NoFlags, Data::Flag signalFlags = Data::NoFlags); + void append(QDeclarativeEngine *, const QMetaObject *, int revision, Data::Flag propertyFlags = Data::NoFlags, + Data::Flag methodFlags = Data::NoFlags, Data::Flag signalFlags = Data::NoFlags); - static QDeclarativePropertyCache *create(QDeclarativeEngine *, const QMetaObject *); static Data create(const QMetaObject *, const QString &); inline Data *property(const QScriptDeclarativeClass::Identifier &id) const; @@ -142,13 +146,19 @@ public: Data *method(int) const; QStringList propertyNames() const; + inline Data *overrideData(Data *) const; + inline bool isAllowedInRevision(Data *) const; + inline QDeclarativeEngine *qmlEngine() const; static Data *property(QDeclarativeEngine *, QObject *, const QScriptDeclarativeClass::Identifier &, Data &); static Data *property(QDeclarativeEngine *, QObject *, const QString &, Data &); + protected: virtual void clear(); private: + friend class QDeclarativeEnginePrivate; + struct RData : public Data, public QDeclarativeRefCount { QScriptDeclarativeClass::PersistentIdentifier identifier; }; @@ -156,6 +166,7 @@ private: typedef QVector<RData *> IndexCache; typedef QHash<QString, RData *> StringCache; typedef QHash<QScriptDeclarativeClass::Identifier, RData *> IdentifierCache; + typedef QVector<int> AllowedRevisionCache; void updateRecur(QDeclarativeEngine *, const QMetaObject *); @@ -164,11 +175,13 @@ private: IndexCache methodIndexCache; StringCache stringCache; IdentifierCache identifierCache; + AllowedRevisionCache allowedRevisionCache; }; Q_DECLARE_OPERATORS_FOR_FLAGS(QDeclarativePropertyCache::Data::Flags); QDeclarativePropertyCache::Data::Data() -: flags(0), propType(0), coreIndex(-1), notifyIndex(-1) +: flags(0), propType(0), coreIndex(-1), notifyIndex(-1), overrideIndexIsProperty(false), overrideIndex(-1), + revision(0), metaObjectOffset(-1) { } @@ -182,6 +195,18 @@ bool QDeclarativePropertyCache::Data::operator==(const QDeclarativePropertyCache } QDeclarativePropertyCache::Data * +QDeclarativePropertyCache::overrideData(Data *data) const +{ + if (data->overrideIndex < 0) + return 0; + + if (data->overrideIndexIsProperty) + return indexCache.at(data->overrideIndex); + else + return methodIndexCache.at(data->overrideIndex); +} + +QDeclarativePropertyCache::Data * QDeclarativePropertyCache::property(const QScriptDeclarativeClass::Identifier &id) const { return identifierCache.value(id); @@ -199,6 +224,12 @@ bool QDeclarativePropertyCache::ValueTypeData::operator==(const ValueTypeData &o valueTypePropType == o.valueTypePropType; } +bool QDeclarativePropertyCache::isAllowedInRevision(Data *data) const +{ + return (data->metaObjectOffset == -1 && data->revision == 0) || + (allowedRevisionCache[data->metaObjectOffset] >= data->revision); +} + QDeclarativeEngine *QDeclarativePropertyCache::qmlEngine() const { return engine; diff --git a/src/declarative/qml/qdeclarativetypeloader.cpp b/src/declarative/qml/qdeclarativetypeloader.cpp index 302cdcc..36cdde9 100644 --- a/src/declarative/qml/qdeclarativetypeloader.cpp +++ b/src/declarative/qml/qdeclarativetypeloader.cpp @@ -1005,6 +1005,8 @@ void QDeclarativeTypeData::resolveTypes() } if (ref.type) { + ref.majorVersion = majorVersion; + ref.minorVersion = minorVersion; foreach (QDeclarativeParser::Object *obj, parserRef->refObjects) { // store namespace for DOM obj->majorVersion = majorVersion; diff --git a/src/declarative/qml/qdeclarativetypeloader_p.h b/src/declarative/qml/qdeclarativetypeloader_p.h index beee358..6938892 100644 --- a/src/declarative/qml/qdeclarativetypeloader_p.h +++ b/src/declarative/qml/qdeclarativetypeloader_p.h @@ -215,10 +215,12 @@ class Q_AUTOTEST_EXPORT QDeclarativeTypeData : public QDeclarativeDataBlob public: struct TypeReference { - TypeReference() : type(0), typeData(0) {} + TypeReference() : type(0), majorVersion(0), minorVersion(0), typeData(0) {} QDeclarativeParser::Location location; QDeclarativeType *type; + int majorVersion; + int minorVersion; QDeclarativeTypeData *typeData; }; diff --git a/src/declarative/qml/qdeclarativevme.cpp b/src/declarative/qml/qdeclarativevme.cpp index f3e7809..657b10d 100644 --- a/src/declarative/qml/qdeclarativevme.cpp +++ b/src/declarative/qml/qdeclarativevme.cpp @@ -324,10 +324,12 @@ QObject *QDeclarativeVME::run(QDeclarativeVMEStack<QObject *> &stack, (void)new QDeclarativeVMEMetaObject(target, &mo, data, comp); - QDeclarativeData *ddata = QDeclarativeData::get(target, true); - if (ddata->propertyCache) ddata->propertyCache->release(); - ddata->propertyCache = propertyCaches.at(instr.storeMeta.propertyCache); - ddata->propertyCache->addref(); + if (instr.storeMeta.propertyCache != -1) { + QDeclarativeData *ddata = QDeclarativeData::get(target, true); + if (ddata->propertyCache) ddata->propertyCache->release(); + ddata->propertyCache = propertyCaches.at(instr.storeMeta.propertyCache); + ddata->propertyCache->addref(); + } } break; @@ -978,6 +980,11 @@ QDeclarativeCompiledData::TypeReference::createInstance(QDeclarativeContextData ddata->ownMemory = false; QObjectPrivate::get(rv)->declarativeData = ddata; + if (typePropertyCache && !ddata->propertyCache) { + ddata->propertyCache = typePropertyCache; + ddata->propertyCache->addref(); + } + return rv; } else { Q_ASSERT(component); |