aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml
diff options
context:
space:
mode:
authorSimon Hausmann <simon.hausmann@qt.io>2017-06-23 17:19:26 +0200
committerSimon Hausmann <simon.hausmann@qt.io>2017-08-02 16:32:53 +0000
commitaa6120cc3524b8d603e92e952aece7494a5d8f02 (patch)
treec391e271f232d4174f6ef1c22e4a0442f8f57ba9 /src/qml
parentc6b2dd879d02b21b18f80faab541f8f04286685a (diff)
Remove QQmlEnginePrivate::typePropertyCache
Instead of maintaining a hash per QQmlType and minor version, move the version specific property caches into QQmlType. Task-number: QTBUG-61536 Change-Id: I72f3990cb93e64ac5074060b4ff327043eab7966 Reviewed-by: Lars Knoll <lars.knoll@qt.io>
Diffstat (limited to 'src/qml')
-rw-r--r--src/qml/qml/qqmlengine.cpp105
-rw-r--r--src/qml/qml/qqmlengine_p.h8
-rw-r--r--src/qml/qml/qqmlmetatype.cpp143
-rw-r--r--src/qml/qml/qqmlmetatype_p.h1
-rw-r--r--src/qml/qml/qqmlpropertycache_p.h1
5 files changed, 146 insertions, 112 deletions
diff --git a/src/qml/qml/qqmlengine.cpp b/src/qml/qml/qqmlengine.cpp
index 7aae994c29..6f5dcc0746 100644
--- a/src/qml/qml/qqmlengine.cpp
+++ b/src/qml/qml/qqmlengine.cpp
@@ -677,8 +677,6 @@ QQmlEnginePrivate::QQmlEnginePrivate(QQmlEngine *e)
QQmlEnginePrivate::~QQmlEnginePrivate()
{
- typedef QHash<QPair<QQmlType, int>, QQmlPropertyCache *>::const_iterator TypePropertyCacheIt;
-
if (inProgressCreations)
qWarning() << QQmlEngine::tr("There are still \"%1\" items in the process of being created at engine destruction.").arg(inProgressCreations);
@@ -696,8 +694,6 @@ QQmlEnginePrivate::~QQmlEnginePrivate()
if (incubationController) incubationController->d = 0;
incubationController = 0;
- for (TypePropertyCacheIt iter = typePropertyCache.cbegin(), end = typePropertyCache.cend(); iter != end; ++iter)
- (*iter)->release();
for (auto iter = m_compositeTypes.cbegin(), end = m_compositeTypes.cend(); iter != end; ++iter) {
iter.value()->isRegisteredWithEngine = false;
@@ -2194,107 +2190,6 @@ QString QQmlEnginePrivate::offlineStorageDatabaseDirectory() const
return q->offlineStoragePath() + QDir::separator() + QLatin1String("Databases") + QDir::separator();
}
-QQmlPropertyCache *QQmlEnginePrivate::createCache(const QQmlType &type, int minorVersion)
-{
- QVector<QQmlType> types;
-
- int maxMinorVersion = 0;
-
- const QMetaObject *metaObject = type.metaObject();
-
- while (metaObject) {
- QQmlType t = QQmlMetaType::qmlType(metaObject, type.module(), type.majorVersion(), minorVersion);
- if (t.isValid()) {
- maxMinorVersion = qMax(maxMinorVersion, t.minorVersion());
- types << t;
- } else {
- types << 0;
- }
-
- metaObject = metaObject->superClass();
- }
-
- if (QQmlPropertyCache *c = typePropertyCache.value(qMakePair(type, maxMinorVersion))) {
- c->addref();
- typePropertyCache.insert(qMakePair(type, minorVersion), c);
- return c;
- }
-
- QQmlPropertyCache *raw = cache(type.metaObject());
-
- bool hasCopied = false;
-
- for (int ii = 0; ii < types.count(); ++ii) {
- QQmlType currentType = types.at(ii);
- if (!currentType.isValid())
- 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
-
-#if 0
- bool overloadError = false;
- QString overloadName;
-
- for (QQmlPropertyCache::StringCache::ConstIterator iter = raw->stringCache.begin();
- !overloadError && iter != raw->stringCache.end();
- ++iter) {
-
- QQmlPropertyData *d = *iter;
- if (raw->isAllowedInRevision(d))
- continue; // Not excluded - no problems
-
- // check that a regular "name" overload isn't happening
- QQmlPropertyData *current = d;
- while (!overloadError && current) {
- current = d->overrideData(current);
- if (current && raw->isAllowedInRevision(current))
- overloadError = true;
- }
- }
-
- if (overloadError) {
- if (hasCopied) raw->release();
-
- error.setDescription(QLatin1String("Type ") + type.qmlTypeName() + QLatin1Char(' ') + QString::number(type.majorVersion()) + QLatin1Char('.') + QString::number(minorVersion) + QLatin1String(" contains an illegal property \"") + overloadName + QLatin1String("\". This is an error in the type's implementation."));
- return 0;
- }
-#endif
-
- if (!hasCopied) raw->addref();
- typePropertyCache.insert(qMakePair(type, minorVersion), raw);
-
- if (minorVersion != maxMinorVersion) {
- raw->addref();
- typePropertyCache.insert(qMakePair(type, maxMinorVersion), raw);
- }
-
- return raw;
-}
-
bool QQmlEnginePrivate::isQObject(int t)
{
Locker locker(this);
diff --git a/src/qml/qml/qqmlengine_p.h b/src/qml/qml/qqmlengine_p.h
index 3ed8dbccff..48c865abe5 100644
--- a/src/qml/qml/qqmlengine_p.h
+++ b/src/qml/qml/qqmlengine_p.h
@@ -259,12 +259,8 @@ public:
mutable QMutex networkAccessManagerMutex;
private:
- // Must be called locked
- QQmlPropertyCache *createCache(const QQmlType &, int);
-
// These members must be protected by a QQmlEnginePrivate::Locker as they are required by
// the threaded loader. Only access them through their respective accessor methods.
- QHash<QPair<QQmlType, int>, QQmlPropertyCache *> typePropertyCache;
QHash<int, int> m_qmlLists;
QHash<int, QV4::CompiledData::CompilationUnit *> m_compositeTypes;
static bool s_designerMode;
@@ -383,9 +379,7 @@ QQmlPropertyCache *QQmlEnginePrivate::cache(const QQmlType &type, int minorVersi
return cache(type.metaObject());
Locker locker(this);
- QQmlPropertyCache *rv = typePropertyCache.value(qMakePair(type, minorVersion));
- if (!rv) rv = createCache(type, minorVersion);
- return rv;
+ return QQmlMetaType::propertyCache(type, minorVersion);
}
QV8Engine *QQmlEnginePrivate::getV8Engine(QQmlEngine *e)
diff --git a/src/qml/qml/qqmlmetatype.cpp b/src/qml/qml/qqmlmetatype.cpp
index a2b6913943..9dd0c14723 100644
--- a/src/qml/qml/qqmlmetatype.cpp
+++ b/src/qml/qml/qqmlmetatype.cpp
@@ -113,6 +113,7 @@ struct QQmlMetaTypeData
QHash<const QMetaObject *, QQmlPropertyCache *> propertyCaches;
QQmlPropertyCache *propertyCache(const QMetaObject *metaObject);
+ QQmlPropertyCache *propertyCache(const QQmlType &type, int minorVersion);
};
class QQmlTypeModulePrivate
@@ -226,6 +227,17 @@ public:
mutable QStringHash<int> enums;
static QHash<const QMetaObject *, int> attachedPropertyIds;
+
+ struct PropertyCacheByMinorVersion
+ {
+ PropertyCacheByMinorVersion() : cache(nullptr), minorVersion(-1) {}
+ explicit PropertyCacheByMinorVersion(QQmlPropertyCache *pc, int ver) : cache(pc), minorVersion(ver) {}
+ QQmlPropertyCachePtr cache;
+ int minorVersion;
+ };
+ QVector<PropertyCacheByMinorVersion> propertyCaches;
+ QQmlPropertyCache *propertyCacheForMinorVersion(int minorVersion) const;
+ void setPropertyCacheForMinorVersion(int minorVersion, QQmlPropertyCache *cache);
};
void QQmlType::SingletonInstanceInfo::init(QQmlEngine *e)
@@ -780,6 +792,25 @@ void QQmlTypePrivate::insertEnums(const QMetaObject *metaObject) const
}
}
+QQmlPropertyCache *QQmlTypePrivate::propertyCacheForMinorVersion(int minorVersion) const
+{
+ for (int i = 0; i < propertyCaches.count(); ++i)
+ if (propertyCaches.at(i).minorVersion == minorVersion)
+ return propertyCaches.at(i).cache;
+ return nullptr;
+}
+
+void QQmlTypePrivate::setPropertyCacheForMinorVersion(int minorVersion, QQmlPropertyCache *cache)
+{
+ for (int i = 0; i < propertyCaches.count(); ++i) {
+ if (propertyCaches.at(i).minorVersion == minorVersion) {
+ propertyCaches[i].cache = cache;
+ return;
+ }
+ }
+ propertyCaches.append(PropertyCacheByMinorVersion(cache, minorVersion));
+}
+
QByteArray QQmlType::typeName() const
{
if (d) {
@@ -2010,6 +2041,118 @@ QQmlPropertyCache *QQmlMetaType::propertyCache(const QMetaObject *metaObject)
return data->propertyCache(metaObject);
}
+QQmlPropertyCache *QQmlMetaTypeData::propertyCache(const QQmlType &type, int minorVersion)
+{
+ Q_ASSERT(type.isValid());
+
+ if (QQmlPropertyCache *pc = type.key()->propertyCacheForMinorVersion(minorVersion))
+ return pc;
+
+ QVector<QQmlType> types;
+
+ int maxMinorVersion = 0;
+
+ const QMetaObject *metaObject = type.metaObject();
+
+ while (metaObject) {
+ QQmlType t = QQmlMetaType::qmlType(metaObject, type.module(), type.majorVersion(), minorVersion);
+ if (t.isValid()) {
+ maxMinorVersion = qMax(maxMinorVersion, t.minorVersion());
+ types << t;
+ } else {
+ types << 0;
+ }
+
+ metaObject = metaObject->superClass();
+ }
+
+ if (QQmlPropertyCache *pc = type.key()->propertyCacheForMinorVersion(maxMinorVersion)) {
+ const_cast<QQmlTypePrivate*>(type.key())->setPropertyCacheForMinorVersion(minorVersion, pc);
+ return pc;
+ }
+
+ QQmlPropertyCache *raw = propertyCache(type.metaObject());
+
+ bool hasCopied = false;
+
+ for (int ii = 0; ii < types.count(); ++ii) {
+ QQmlType currentType = types.at(ii);
+ if (!currentType.isValid())
+ 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
+
+#if 0
+ bool overloadError = false;
+ QString overloadName;
+
+ for (QQmlPropertyCache::StringCache::ConstIterator iter = raw->stringCache.begin();
+ !overloadError && iter != raw->stringCache.end();
+ ++iter) {
+
+ QQmlPropertyData *d = *iter;
+ if (raw->isAllowedInRevision(d))
+ continue; // Not excluded - no problems
+
+ // check that a regular "name" overload isn't happening
+ QQmlPropertyData *current = d;
+ while (!overloadError && current) {
+ current = d->overrideData(current);
+ if (current && raw->isAllowedInRevision(current))
+ overloadError = true;
+ }
+ }
+
+ if (overloadError) {
+ if (hasCopied) raw->release();
+
+ error.setDescription(QLatin1String("Type ") + type.qmlTypeName() + QLatin1Char(' ') + QString::number(type.majorVersion()) + QLatin1Char('.') + QString::number(minorVersion) + QLatin1String(" contains an illegal property \"") + overloadName + QLatin1String("\". This is an error in the type's implementation."));
+ return 0;
+ }
+#endif
+
+ const_cast<QQmlTypePrivate*>(type.key())->setPropertyCacheForMinorVersion(minorVersion, raw);
+
+ if (hasCopied)
+ raw->release();
+
+ if (minorVersion != maxMinorVersion)
+ const_cast<QQmlTypePrivate*>(type.key())->setPropertyCacheForMinorVersion(maxMinorVersion, raw);
+
+ return raw;
+}
+
+QQmlPropertyCache *QQmlMetaType::propertyCache(const QQmlType &type, int minorVersion)
+{
+ QMutexLocker lock(metaTypeDataLock());
+ QQmlMetaTypeData *data = metaTypeData();
+ return data->propertyCache(type, minorVersion);
+}
+
/*!
Returns the list of registered QML type names.
*/
diff --git a/src/qml/qml/qqmlmetatype_p.h b/src/qml/qml/qqmlmetatype_p.h
index c577a9cc18..43eda2b4f1 100644
--- a/src/qml/qml/qqmlmetatype_p.h
+++ b/src/qml/qml/qqmlmetatype_p.h
@@ -91,6 +91,7 @@ public:
static QQmlType qmlTypeFromIndex(int);
static QQmlPropertyCache *propertyCache(const QMetaObject *metaObject);
+ static QQmlPropertyCache *propertyCache(const QQmlType &type, int minorVersion);
static QMetaProperty defaultProperty(const QMetaObject *);
static QMetaProperty defaultProperty(QObject *);
diff --git a/src/qml/qml/qqmlpropertycache_p.h b/src/qml/qml/qqmlpropertycache_p.h
index 8fdc95af3a..a841570f1d 100644
--- a/src/qml/qml/qqmlpropertycache_p.h
+++ b/src/qml/qml/qqmlpropertycache_p.h
@@ -452,6 +452,7 @@ private:
template <typename T> friend class QQmlPropertyCacheAliasCreator;
friend class QQmlComponentAndAliasResolver;
friend class QQmlMetaObject;
+ friend struct QQmlMetaTypeData;
inline QQmlPropertyCache *copy(int reserve);