summaryrefslogtreecommitdiffstats
path: root/src/declarative
diff options
context:
space:
mode:
authorAaron Kennedy <aaron.kennedy@nokia.com>2011-01-27 03:49:12 (GMT)
committerAaron Kennedy <aaron.kennedy@nokia.com>2011-01-27 03:49:12 (GMT)
commitd9e4393ef212dba9eeba68277b270d68bcdbc733 (patch)
treed65ff0df673db66478b081d672f3fe383ae6e5a5 /src/declarative
parentf15778e60ba538b8715f6433a472ffe08a21d934 (diff)
downloadQt-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.cpp30
-rw-r--r--src/declarative/qml/qdeclarativecompiler.cpp174
-rw-r--r--src/declarative/qml/qdeclarativecompiler_p.h7
-rw-r--r--src/declarative/qml/qdeclarativeengine.cpp121
-rw-r--r--src/declarative/qml/qdeclarativeengine_p.h37
-rw-r--r--src/declarative/qml/qdeclarativemetatype.cpp76
-rw-r--r--src/declarative/qml/qdeclarativemetatype_p.h6
-rw-r--r--src/declarative/qml/qdeclarativeobjectscriptclass.cpp21
-rw-r--r--src/declarative/qml/qdeclarativeparser.cpp3
-rw-r--r--src/declarative/qml/qdeclarativeparser_p.h2
-rw-r--r--src/declarative/qml/qdeclarativepropertycache.cpp21
-rw-r--r--src/declarative/qml/qdeclarativepropertycache_p.h37
-rw-r--r--src/declarative/qml/qdeclarativetypeloader.cpp2
-rw-r--r--src/declarative/qml/qdeclarativetypeloader_p.h4
-rw-r--r--src/declarative/qml/qdeclarativevme.cpp15
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, &notInRevision);
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, &notInRevision);
+ 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);