diff options
author | Simon Hausmann <simon.hausmann@qt.io> | 2017-06-23 17:19:26 +0200 |
---|---|---|
committer | Simon Hausmann <simon.hausmann@qt.io> | 2017-08-02 16:32:53 +0000 |
commit | aa6120cc3524b8d603e92e952aece7494a5d8f02 (patch) | |
tree | c391e271f232d4174f6ef1c22e4a0442f8f57ba9 /src/qml | |
parent | c6b2dd879d02b21b18f80faab541f8f04286685a (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.cpp | 105 | ||||
-rw-r--r-- | src/qml/qml/qqmlengine_p.h | 8 | ||||
-rw-r--r-- | src/qml/qml/qqmlmetatype.cpp | 143 | ||||
-rw-r--r-- | src/qml/qml/qqmlmetatype_p.h | 1 | ||||
-rw-r--r-- | src/qml/qml/qqmlpropertycache_p.h | 1 |
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); |