diff options
author | Ulf Hermann <ulf.hermann@qt.io> | 2022-03-10 12:49:35 +0100 |
---|---|---|
committer | Ulf Hermann <ulf.hermann@qt.io> | 2022-03-18 22:56:54 +0100 |
commit | b5b5782088c25c67f090500d71fa1ae655383553 (patch) | |
tree | d14d054d570eefa303f80e6ce59ea076f43c1bb1 /src/qml/qml | |
parent | 7b8e6714e1e9707091898eba92f099c664879e80 (diff) |
QML: Add more safety to QQmlPropertyCache usages
We can almost always use QQmlPropertyCache::ConstPtr. The property cache
creator needs mutable property caches for a while, but it can seal them
when done. The designer integration does ugly stuff, but that should be
limited to a specific environment. And the QQmlOpenMetaObject is rather
wrong (again). This needs to be addresses in a later change.
Task-number: QTBUG-73271
Change-Id: I1c31fd5936c745029d25b909c30b8d14a30f25d3
Reviewed-by: Andrei Golubev <andrei.golubev@qt.io>
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
Diffstat (limited to 'src/qml/qml')
-rw-r--r-- | src/qml/qml/qqmlmetatype.cpp | 31 | ||||
-rw-r--r-- | src/qml/qml/qqmlmetatype_p.h | 31 | ||||
-rw-r--r-- | src/qml/qml/qqmlmetatypedata.cpp | 52 | ||||
-rw-r--r-- | src/qml/qml/qqmlmetatypedata_p.h | 16 | ||||
-rw-r--r-- | src/qml/qml/qqmlopenmetaobject.cpp | 8 | ||||
-rw-r--r-- | src/qml/qml/qqmlpropertycachecreator.cpp | 5 | ||||
-rw-r--r-- | src/qml/qml/qqmlpropertycachecreator_p.h | 13 | ||||
-rw-r--r-- | src/qml/qml/qqmlpropertycachevector_p.h | 81 | ||||
-rw-r--r-- | src/qml/qml/qqmltypecompiler.cpp | 2 | ||||
-rw-r--r-- | src/qml/qml/qqmltypedata.cpp | 8 |
10 files changed, 169 insertions, 78 deletions
diff --git a/src/qml/qml/qqmlmetatype.cpp b/src/qml/qml/qqmlmetatype.cpp index 125693f3b6..ea9f325deb 100644 --- a/src/qml/qml/qqmlmetatype.cpp +++ b/src/qml/qml/qqmlmetatype.cpp @@ -1294,21 +1294,28 @@ Returns a QQmlPropertyCache for \a obj if one is available. If \a obj is null, being deleted or contains a dynamic meta object, nullptr is returned. */ -QQmlRefPointer<QQmlPropertyCache> QQmlMetaType::propertyCache(QObject *obj, QTypeRevision version) +QQmlPropertyCache::ConstPtr QQmlMetaType::propertyCache(QObject *obj, QTypeRevision version) { if (!obj || QObjectPrivate::get(obj)->metaObject || QObjectPrivate::get(obj)->wasDeleted) - return QQmlRefPointer<QQmlPropertyCache>(); + return QQmlPropertyCache::ConstPtr(); return QQmlMetaType::propertyCache(obj->metaObject(), version); } -QQmlRefPointer<QQmlPropertyCache> QQmlMetaType::propertyCache( +QQmlPropertyCache::ConstPtr QQmlMetaType::propertyCache( const QMetaObject *metaObject, QTypeRevision version) { QQmlMetaTypeDataPtr data; // not const: the cache is created on demand return data->propertyCache(metaObject, version); } -QQmlRefPointer<QQmlPropertyCache> QQmlMetaType::propertyCache( +QQmlPropertyCache::Ptr QQmlMetaType::createPropertyCache( + const QMetaObject *metaObject) +{ + QQmlMetaTypeDataPtr data; // not const: the cache is created + return data->createPropertyCache(metaObject); +} + +QQmlPropertyCache::ConstPtr QQmlMetaType::propertyCache( const QQmlType &type, QTypeRevision version) { QQmlMetaTypeDataPtr data; // not const: the cache is created on demand @@ -1352,7 +1359,7 @@ QQmlMetaObject QQmlMetaType::metaObjectForType(QMetaType metaType) * * Look up by type's metaObject and version. */ -QQmlRefPointer<QQmlPropertyCache> QQmlMetaType::propertyCacheForType(QMetaType metaType) +QQmlPropertyCache::ConstPtr QQmlMetaType::propertyCacheForType(QMetaType metaType) { QQmlMetaTypeDataPtr data; if (auto composite = data->findPropertyCacheInCompositeTypes(metaType)) @@ -1361,7 +1368,7 @@ QQmlRefPointer<QQmlPropertyCache> QQmlMetaType::propertyCacheForType(QMetaType m const QQmlTypePrivate *type = data->idToType.value(metaType.id()); return (type && type->typeId == metaType) ? data->propertyCache(QQmlType(type).metaObject(), type->version) - : QQmlRefPointer<QQmlPropertyCache>(); + : QQmlPropertyCache::ConstPtr(); } /*! @@ -1371,7 +1378,7 @@ QQmlRefPointer<QQmlPropertyCache> QQmlMetaType::propertyCacheForType(QMetaType m * TODO: Is this correct? Passing a plain QTypeRevision() rather than QTypeRevision::zero() or * the actual type's version seems strange. The behavior has been in place for a while. */ -QQmlRefPointer<QQmlPropertyCache> QQmlMetaType::rawPropertyCacheForType(QMetaType metaType) +QQmlPropertyCache::ConstPtr QQmlMetaType::rawPropertyCacheForType(QMetaType metaType) { QQmlMetaTypeDataPtr data; if (auto composite = QQmlMetaType::findPropertyCacheInCompositeTypes(metaType)) @@ -1380,7 +1387,7 @@ QQmlRefPointer<QQmlPropertyCache> QQmlMetaType::rawPropertyCacheForType(QMetaTyp const QQmlTypePrivate *type = data->idToType.value(metaType.id()); return (type && type->typeId == metaType) ? data->propertyCache(type->baseMetaObject, QTypeRevision()) - : QQmlRefPointer<QQmlPropertyCache>(); + : QQmlPropertyCache::ConstPtr(); } /*! @@ -1389,7 +1396,7 @@ QQmlRefPointer<QQmlPropertyCache> QQmlMetaType::rawPropertyCacheForType(QMetaTyp * Look up by QQmlType and version. We only fall back to lookup by metaobject if the type * has no revisiononed attributes here. Unspecified versions are interpreted as "any". */ -QQmlRefPointer<QQmlPropertyCache> QQmlMetaType::rawPropertyCacheForType( +QQmlPropertyCache::ConstPtr QQmlMetaType::rawPropertyCacheForType( QMetaType metaType, QTypeRevision version) { QQmlMetaTypeDataPtr data; @@ -1398,7 +1405,7 @@ QQmlRefPointer<QQmlPropertyCache> QQmlMetaType::rawPropertyCacheForType( const QQmlTypePrivate *typePriv = data->idToType.value(metaType.id()); if (!typePriv || typePriv->typeId != metaType) - return QQmlRefPointer<QQmlPropertyCache>(); + return QQmlPropertyCache::ConstPtr(); const QQmlType type(typePriv); if (type.containsRevisionedAttributes()) @@ -1407,7 +1414,7 @@ QQmlRefPointer<QQmlPropertyCache> QQmlMetaType::rawPropertyCacheForType( if (const QMetaObject *metaObject = type.metaObject()) return data->propertyCache(metaObject, version); - return QQmlRefPointer<QQmlPropertyCache>(); + return QQmlPropertyCache::ConstPtr(); } void QQmlMetaType::unregisterType(int typeIndex) @@ -1761,7 +1768,7 @@ QQmlValueType *QQmlMetaType::valueType(QMetaType type) return *data->metaTypeToValueType.insert(type.id(), nullptr); } -QQmlRefPointer<QQmlPropertyCache> QQmlMetaType::findPropertyCacheInCompositeTypes(QMetaType t) +QQmlPropertyCache::ConstPtr QQmlMetaType::findPropertyCacheInCompositeTypes(QMetaType t) { const QQmlMetaTypeDataPtr data; return data->findPropertyCacheInCompositeTypes(t); diff --git a/src/qml/qml/qqmlmetatype_p.h b/src/qml/qml/qqmlmetatype_p.h index 1fb4d915da..3c71e2c583 100644 --- a/src/qml/qml/qqmlmetatype_p.h +++ b/src/qml/qml/qqmlmetatype_p.h @@ -122,6 +122,8 @@ public: class Q_QML_PRIVATE_EXPORT QQmlMetaType { friend struct CompositeMetaTypeIds; + friend class QQmlDesignerMetaObject; + static CompositeMetaTypeIds registerInternalCompositeType(const QByteArray &className); static void unregisterInternalCompositeType(const CompositeMetaTypeIds &typeIds); @@ -176,19 +178,34 @@ public: static QQmlType qmlType(const QUrl &unNormalizedUrl, bool includeNonFileImports = false); - static QQmlRefPointer<QQmlPropertyCache> propertyCache( + static QQmlPropertyCache::ConstPtr propertyCache( QObject *object, QTypeRevision version = QTypeRevision()); - static QQmlRefPointer<QQmlPropertyCache> propertyCache( + static QQmlPropertyCache::ConstPtr propertyCache( const QMetaObject *metaObject, QTypeRevision version = QTypeRevision()); - static QQmlRefPointer<QQmlPropertyCache> propertyCache( + static QQmlPropertyCache::ConstPtr propertyCache( const QQmlType &type, QTypeRevision version); + // This only works for a new metaObject that doesn't have an associated property cache, yet. + // Do not call it more than once for the same metaObject! + // + // ------------------------------------------------------------------------------------ + // --> The caller has to uphold the immutability guarantees for the returned property cache <-- + // ------------------------------------------------------------------------------------ + // + // This means: You cannot expose the metaObject, any objects created from it, or the property + // cache to _anything_ that allows concurrent access before you are done changing the property + // cache! + // + // In general, don't use this method. It's only for the designer integration. The designer + // assumes that there is only one QML engine running in a single thread. + static QQmlPropertyCache::Ptr createPropertyCache(const QMetaObject *metaObject); + // These methods may be called from the loader thread static QQmlMetaObject rawMetaObjectForType(QMetaType metaType); static QQmlMetaObject metaObjectForType(QMetaType metaType); - static QQmlRefPointer<QQmlPropertyCache> propertyCacheForType(QMetaType metaType); - static QQmlRefPointer<QQmlPropertyCache> rawPropertyCacheForType(QMetaType metaType); - static QQmlRefPointer<QQmlPropertyCache> rawPropertyCacheForType( + static QQmlPropertyCache::ConstPtr propertyCacheForType(QMetaType metaType); + static QQmlPropertyCache::ConstPtr rawPropertyCacheForType(QMetaType metaType); + static QQmlPropertyCache::ConstPtr rawPropertyCacheForType( QMetaType metaType, QTypeRevision version); static void freeUnusedTypesAndCaches(); @@ -268,7 +285,7 @@ public: static QQmlValueType *valueType(QMetaType metaType); static const QMetaObject *metaObjectForValueType(QMetaType type); - static QQmlRefPointer<QQmlPropertyCache> findPropertyCacheInCompositeTypes(QMetaType t); + static QQmlPropertyCache::ConstPtr findPropertyCacheInCompositeTypes(QMetaType t); static void registerInternalCompositeType(QV4::ExecutableCompilationUnit *compilationUnit); static void unregisterInternalCompositeType(QV4::ExecutableCompilationUnit *compilationUnit); static QV4::ExecutableCompilationUnit *obtainExecutableCompilationUnit(QMetaType type); diff --git a/src/qml/qml/qqmlmetatypedata.cpp b/src/qml/qml/qqmlmetatypedata.cpp index aafe4490fb..8f804dce86 100644 --- a/src/qml/qml/qqmlmetatypedata.cpp +++ b/src/qml/qml/qqmlmetatypedata.cpp @@ -119,16 +119,16 @@ bool QQmlMetaTypeData::registerModuleTypes(const QString &uri) return false; } -QQmlRefPointer<QQmlPropertyCache> QQmlMetaTypeData::propertyCacheForVersion( +QQmlPropertyCache::ConstPtr QQmlMetaTypeData::propertyCacheForVersion( int index, QTypeRevision version) const { return (index < typePropertyCaches.length()) ? typePropertyCaches.at(index).value(version) - : QQmlRefPointer<QQmlPropertyCache>(); + : QQmlPropertyCache::ConstPtr(); } void QQmlMetaTypeData::setPropertyCacheForVersion(int index, QTypeRevision version, - const QQmlRefPointer<QQmlPropertyCache> &cache) + const QQmlPropertyCache::ConstPtr &cache) { if (index >= typePropertyCaches.length()) typePropertyCaches.resize(index + 1); @@ -141,13 +141,13 @@ void QQmlMetaTypeData::clearPropertyCachesForVersion(int index) typePropertyCaches[index].clear(); } -QQmlRefPointer<QQmlPropertyCache> QQmlMetaTypeData::propertyCache( +QQmlPropertyCache::ConstPtr QQmlMetaTypeData::propertyCache( const QMetaObject *metaObject, QTypeRevision version) { - if (QQmlRefPointer<QQmlPropertyCache> rv = propertyCaches.value(metaObject)) + if (QQmlPropertyCache::ConstPtr rv = propertyCaches.value(metaObject)) return rv; - QQmlRefPointer<QQmlPropertyCache> rv; + QQmlPropertyCache::ConstPtr rv; if (const QMetaObject *superMeta = metaObject->superClass()) rv = propertyCache(superMeta, version)->copyAndAppend(metaObject, version); else @@ -160,7 +160,22 @@ QQmlRefPointer<QQmlPropertyCache> QQmlMetaTypeData::propertyCache( return rv; } -QQmlRefPointer<QQmlPropertyCache> QQmlMetaTypeData::propertyCache( +QQmlPropertyCache::Ptr QQmlMetaTypeData::createPropertyCache(const QMetaObject *metaObject) +{ + QQmlPropertyCache::Ptr rv; + if (const QMetaObject *superMeta = metaObject->superClass()) + rv = propertyCache(superMeta, QTypeRevision())->copyAndAppend(metaObject, QTypeRevision()); + else + rv.adopt(new QQmlPropertyCache(metaObject)); + + const auto *mop = reinterpret_cast<const QMetaObjectPrivate *>(metaObject->d.data); + if (!(mop->flags & DynamicMetaObject)) + propertyCaches.insert(metaObject, rv); + + return rv; +} + +QQmlPropertyCache::ConstPtr QQmlMetaTypeData::propertyCache( const QQmlType &type, QTypeRevision version) { Q_ASSERT(type.isValid()); @@ -200,9 +215,8 @@ QQmlRefPointer<QQmlPropertyCache> QQmlMetaTypeData::propertyCache( return pc; } - QQmlRefPointer<QQmlPropertyCache> raw = propertyCache(type.metaObject(), combinedVersion); - - bool hasCopied = false; + QQmlPropertyCache::ConstPtr raw = propertyCache(type.metaObject(), combinedVersion); + QQmlPropertyCache::Ptr copied; for (int ii = 0; ii < types.count(); ++ii) { const QQmlType ¤tType = types.at(ii); @@ -213,14 +227,11 @@ QQmlRefPointer<QQmlPropertyCache> QQmlMetaTypeData::propertyCache( int moIndex = types.count() - 1 - ii; if (raw->allowedRevision(moIndex) != rev) { - if (!hasCopied) { - // TODO: The copy should be mutable, and the original should be const - // Considering this, the setAllowedRevision() below does not violate - // the immutability of already published property caches. - raw = raw->copy(); - hasCopied = true; + if (copied.isNull()) { + copied = raw->copy(); + raw = copied; } - raw->setAllowedRevision(moIndex, rev); + copied->setAllowedRevision(moIndex, rev); } } @@ -275,7 +286,7 @@ QQmlRefPointer<QQmlPropertyCache> QQmlMetaTypeData::propertyCache( return raw; } -static QQmlRefPointer<QQmlPropertyCache> propertyCacheForPotentialInlineComponentType( +static QQmlPropertyCache::ConstPtr propertyCacheForPotentialInlineComponentType( QMetaType t, const QHash<const QtPrivate::QMetaTypeInterface *, QV4::ExecutableCompilationUnit *>::const_iterator &iter) { @@ -288,12 +299,11 @@ static QQmlRefPointer<QQmlPropertyCache> propertyCacheForPotentialInlineComponen return (*iter)->rootPropertyCache(); } -QQmlRefPointer<QQmlPropertyCache> QQmlMetaTypeData::findPropertyCacheInCompositeTypes( - QMetaType t) const +QQmlPropertyCache::ConstPtr QQmlMetaTypeData::findPropertyCacheInCompositeTypes(QMetaType t) const { auto iter = compositeTypes.constFind(t.iface()); return (iter == compositeTypes.constEnd()) - ? QQmlRefPointer<QQmlPropertyCache>() + ? QQmlPropertyCache::ConstPtr() : propertyCacheForPotentialInlineComponentType(t, iter); } diff --git a/src/qml/qml/qqmlmetatypedata_p.h b/src/qml/qml/qqmlmetatypedata_p.h index 416c241af4..29c0596a51 100644 --- a/src/qml/qml/qqmlmetatypedata_p.h +++ b/src/qml/qml/qqmlmetatypedata_p.h @@ -83,7 +83,7 @@ struct QQmlMetaTypeData // a module via QQmlPrivate::RegisterCompositeType typedef QMultiHash<const QMetaObject *, QQmlTypePrivate *> MetaObjects; MetaObjects metaObjectToType; - QVector<QHash<QTypeRevision, QQmlRefPointer<QQmlPropertyCache>>> typePropertyCaches; + QVector<QHash<QTypeRevision, QQmlPropertyCache::ConstPtr>> typePropertyCaches; QHash<int, QQmlValueType *> metaTypeToValueType; QHash<const QtPrivate::QMetaTypeInterface *, QV4::ExecutableCompilationUnit *> compositeTypes; @@ -130,16 +130,18 @@ struct QQmlMetaTypeData QList<QQmlPrivate::AutoParentFunction> parentFunctions; QVector<QQmlPrivate::QmlUnitCacheLookupFunction> lookupCachedQmlUnit; - QHash<const QMetaObject *, QQmlRefPointer<QQmlPropertyCache>> propertyCaches; + QHash<const QMetaObject *, QQmlPropertyCache::ConstPtr> propertyCaches; - QQmlRefPointer<QQmlPropertyCache> propertyCacheForVersion(int index, QTypeRevision version) const; + QQmlPropertyCache::ConstPtr propertyCacheForVersion(int index, QTypeRevision version) const; void setPropertyCacheForVersion( - int index, QTypeRevision version, const QQmlRefPointer<QQmlPropertyCache> &cache); + int index, QTypeRevision version, const QQmlPropertyCache::ConstPtr &cache); void clearPropertyCachesForVersion(int index); - QQmlRefPointer<QQmlPropertyCache> propertyCache(const QMetaObject *metaObject, QTypeRevision version); - QQmlRefPointer<QQmlPropertyCache> propertyCache(const QQmlType &type, QTypeRevision version); - QQmlRefPointer<QQmlPropertyCache> findPropertyCacheInCompositeTypes(QMetaType t) const; + QQmlPropertyCache::ConstPtr propertyCache(const QMetaObject *metaObject, QTypeRevision version); + QQmlPropertyCache::ConstPtr propertyCache(const QQmlType &type, QTypeRevision version); + QQmlPropertyCache::ConstPtr findPropertyCacheInCompositeTypes(QMetaType t) const; + + QQmlPropertyCache::Ptr createPropertyCache(const QMetaObject *metaObject); void setTypeRegistrationFailures(QStringList *failures) { diff --git a/src/qml/qml/qqmlopenmetaobject.cpp b/src/qml/qml/qqmlopenmetaobject.cpp index 8b905c2351..6d88690482 100644 --- a/src/qml/qml/qqmlopenmetaobject.cpp +++ b/src/qml/qml/qqmlopenmetaobject.cpp @@ -59,7 +59,13 @@ public: QHash<QByteArray, int> names; QMetaObjectBuilder mob; QMetaObject *mem; - QQmlRefPointer<QQmlPropertyCache> cache; + + // TODO: We need to make sure that this does not escape into other threads. + // In particular, all its non-const uses are probably wrong. You should + // only set the open metaobject to "cached" once it's not going to be + // modified anymore. + QQmlPropertyCache::Ptr cache; + QSet<QQmlOpenMetaObject*> referers; }; diff --git a/src/qml/qml/qqmlpropertycachecreator.cpp b/src/qml/qml/qqmlpropertycachecreator.cpp index 1511b1ef8d..6d7d737e02 100644 --- a/src/qml/qml/qqmlpropertycachecreator.cpp +++ b/src/qml/qml/qqmlpropertycachecreator.cpp @@ -139,8 +139,7 @@ bool QQmlBindingInstantiationContext::resolveInstantiatingProperty() return instantiatingProperty != nullptr; } -QQmlRefPointer<QQmlPropertyCache> -QQmlBindingInstantiationContext::instantiatingPropertyCache() const +QQmlPropertyCache::ConstPtr QQmlBindingInstantiationContext::instantiatingPropertyCache() const { if (instantiatingProperty) { if (instantiatingProperty->isQObject()) { @@ -152,7 +151,7 @@ QQmlBindingInstantiationContext::instantiatingPropertyCache() const return QQmlMetaType::propertyCache(vtmo, instantiatingProperty->typeVersion()); } } - return QQmlRefPointer<QQmlPropertyCache>(); + return QQmlPropertyCache::ConstPtr(); } void QQmlPendingGroupPropertyBindings::resolveMissingPropertyCaches( diff --git a/src/qml/qml/qqmlpropertycachecreator_p.h b/src/qml/qml/qqmlpropertycachecreator_p.h index 76f5f1fdc7..5aa1abcbe7 100644 --- a/src/qml/qml/qqmlpropertycachecreator_p.h +++ b/src/qml/qml/qqmlpropertycachecreator_p.h @@ -81,7 +81,7 @@ struct QQmlBindingInstantiationContext { const QQmlPropertyCache::ConstPtr &referencingObjectPropertyCache); bool resolveInstantiatingProperty(); - QQmlRefPointer<QQmlPropertyCache> instantiatingPropertyCache() const; + QQmlPropertyCache::ConstPtr instantiatingPropertyCache() const; int referencingObjectIndex = -1; const QV4::CompiledData::Binding *instantiatingBinding = nullptr; @@ -131,6 +131,7 @@ public: QQmlEnginePrivate *enginePrivate, const ObjectContainer *objectContainer, const QQmlImports *imports, const QByteArray &typeClassName); + ~QQmlPropertyCacheCreator() { propertyCaches->seal(); } /*! @@ -164,7 +165,7 @@ public: }; protected: QQmlError buildMetaObjectRecursively(int objectIndex, const QQmlBindingInstantiationContext &context, VMEMetaObjectIsRequired isVMERequired); - QQmlRefPointer<QQmlPropertyCache> propertyCacheForObject(const CompiledObject *obj, const QQmlBindingInstantiationContext &context, QQmlError *error) const; + QQmlPropertyCache::ConstPtr propertyCacheForObject(const CompiledObject *obj, const QQmlBindingInstantiationContext &context, QQmlError *error) const; QQmlError createMetaObject(int objectIndex, const CompiledObject *obj, const QQmlPropertyCache::ConstPtr &baseTypeCache); QMetaType metaTypeForParameter(const QV4::CompiledData::ParameterType ¶m, QString *customTypeName = nullptr); @@ -324,7 +325,7 @@ inline QQmlError QQmlPropertyCacheCreator<ObjectContainer>::buildMetaObjectRecur } } - QQmlRefPointer<QQmlPropertyCache> baseTypeCache; + QQmlPropertyCache::ConstPtr baseTypeCache; { QQmlError error; baseTypeCache = propertyCacheForObject(obj, context, &error); @@ -382,7 +383,7 @@ inline QQmlError QQmlPropertyCacheCreator<ObjectContainer>::buildMetaObjectRecur } template <typename ObjectContainer> -inline QQmlRefPointer<QQmlPropertyCache> QQmlPropertyCacheCreator<ObjectContainer>::propertyCacheForObject(const CompiledObject *obj, const QQmlBindingInstantiationContext &context, QQmlError *error) const +inline QQmlPropertyCache::ConstPtr QQmlPropertyCacheCreator<ObjectContainer>::propertyCacheForObject(const CompiledObject *obj, const QQmlBindingInstantiationContext &context, QQmlError *error) const { if (context.instantiatingProperty) { return context.instantiatingPropertyCache(); @@ -456,7 +457,7 @@ inline QQmlError QQmlPropertyCacheCreator<ObjectContainer>::createMetaObject( obj->signalCount() + obj->propertyCount() + obj->aliasCount(), obj->enumCount()); - propertyCaches->set(objectIndex, cache); + propertyCaches->setOwn(objectIndex, cache); propertyCaches->setNeedsVMEMetaObject(objectIndex); QByteArray newClassName; @@ -1030,7 +1031,7 @@ inline QQmlError QQmlPropertyCacheAliasCreator<ObjectContainer>::appendAliasesTo if (!object.aliasCount()) return QQmlError(); - QQmlRefPointer<QQmlPropertyCache> propertyCache = propertyCaches->at(objectIndex); + QQmlPropertyCache::Ptr propertyCache = propertyCaches->ownAt(objectIndex); Q_ASSERT(propertyCache); int effectiveSignalIndex = propertyCache->signalHandlerIndexCacheStart + propertyCache->propertyIndexCache.count(); diff --git a/src/qml/qml/qqmlpropertycachevector_p.h b/src/qml/qml/qqmlpropertycachevector_p.h index 5e4b84aec0..b8e2fa1a9f 100644 --- a/src/qml/qml/qqmlpropertycachevector_p.h +++ b/src/qml/qml/qqmlpropertycachevector_p.h @@ -52,6 +52,7 @@ // #include <private/qqmlpropertycache_p.h> +#include <private/qbipointer_p.h> #include <QtCore/qtaggedpointer.h> @@ -60,11 +61,6 @@ QT_BEGIN_NAMESPACE class QQmlPropertyCacheVector { public: - enum Tag { - NoTag, - CacheNeedsVMEMetaObject - }; - QQmlPropertyCacheVector() = default; QQmlPropertyCacheVector(QQmlPropertyCacheVector &&) = default; QQmlPropertyCacheVector &operator=(QQmlPropertyCacheVector &&) = default; @@ -80,32 +76,85 @@ public: void clear() { for (int i = 0; i < data.count(); ++i) { - if (QQmlPropertyCache *cache = data.at(i).data()) - cache->release(); + const auto &cache = data.at(i); + if (cache.isT2()) { + if (QQmlPropertyCache *data = cache.asT2()) + data->release(); + } else if (const QQmlPropertyCache *data = cache.asT1()) { + data->release(); + } } data.clear(); } - void append(const QQmlRefPointer<QQmlPropertyCache> &cache) { + void append(const QQmlPropertyCache::ConstPtr &cache) { cache->addref(); - data.append(QTaggedPointer<QQmlPropertyCache, Tag>(cache.data())); + data.append(QBiPointer<const QQmlPropertyCache, QQmlPropertyCache>(cache.data())); + Q_ASSERT(data.last().isT1()); + } + + void appendOwn(const QQmlPropertyCache::Ptr &cache) { + cache->addref(); + data.append(QBiPointer<const QQmlPropertyCache, QQmlPropertyCache>(cache.data())); + Q_ASSERT(data.last().isT2()); + } + + QQmlPropertyCache::ConstPtr at(int index) const + { + const auto entry = data.at(index); + if (entry.isT2()) + return entry.asT2(); + return entry.asT1(); + } + + QQmlPropertyCache::Ptr ownAt(int index) const + { + const auto entry = data.at(index); + if (entry.isT2()) + return entry.asT2(); + return QQmlPropertyCache::Ptr(); } - QQmlRefPointer<QQmlPropertyCache> at(int index) const { return data.at(index).data(); } - void set(int index, const QQmlRefPointer<QQmlPropertyCache> &replacement) { - if (QQmlPropertyCache *oldCache = data.at(index).data()) { - if (replacement.data() == oldCache) + + void set(int index, const QQmlPropertyCache::ConstPtr &replacement) { + if (QQmlPropertyCache::ConstPtr oldCache = at(index)) { + // If it is our own, we keep it our own + if (replacement.data() == oldCache.data()) return; oldCache->release(); } data[index] = replacement.data(); replacement->addref(); + Q_ASSERT(data[index].isT1()); + } + + void setOwn(int index, const QQmlPropertyCache::Ptr &replacement) { + if (QQmlPropertyCache::ConstPtr oldCache = at(index)) { + if (replacement.data() != oldCache.data()) { + oldCache->release(); + replacement->addref(); + } + } else { + replacement->addref(); + } + data[index] = replacement.data(); + Q_ASSERT(data[index].isT2()); + } + + void setNeedsVMEMetaObject(int index) { data[index].setFlag(); } + bool needsVMEMetaObject(int index) const { return data.at(index).flag(); } + + void seal() + { + for (auto &entry: data) { + if (entry.isT2()) + entry = static_cast<const QQmlPropertyCache *>(entry.asT2()); + Q_ASSERT(entry.isT1()); + } } - void setNeedsVMEMetaObject(int index) { data[index].setTag(CacheNeedsVMEMetaObject); } - bool needsVMEMetaObject(int index) const { return data.at(index).tag() == CacheNeedsVMEMetaObject; } private: Q_DISABLE_COPY(QQmlPropertyCacheVector) - QVector<QTaggedPointer<QQmlPropertyCache, Tag>> data; + QVector<QBiPointer<const QQmlPropertyCache, QQmlPropertyCache>> data; }; QT_END_NAMESPACE diff --git a/src/qml/qml/qqmltypecompiler.cpp b/src/qml/qml/qqmltypecompiler.cpp index 60b42fee1d..617e478e57 100644 --- a/src/qml/qml/qqmltypecompiler.cpp +++ b/src/qml/qml/qqmltypecompiler.cpp @@ -855,7 +855,7 @@ void QQmlComponentAndAliasResolver::findAndRegisterImplicitComponents( qmlObjects->append(syntheticComponent); const int componentIndex = qmlObjects->count() - 1; // Keep property caches symmetric - QQmlRefPointer<QQmlPropertyCache> componentCache + QQmlPropertyCache::ConstPtr componentCache = QQmlMetaType::propertyCache(&QQmlComponent::staticMetaObject); propertyCaches.append(componentCache); diff --git a/src/qml/qml/qqmltypedata.cpp b/src/qml/qml/qqmltypedata.cpp index fa25453675..f64f0d22fb 100644 --- a/src/qml/qml/qqmltypedata.cpp +++ b/src/qml/qml/qqmltypedata.cpp @@ -245,11 +245,11 @@ void QQmlTypeData::createTypeAndPropertyCaches( setError(error); return; } - } - QQmlPropertyCacheAliasCreator<QV4::ExecutableCompilationUnit> aliasCreator( - &m_compiledData->propertyCaches, m_compiledData.data()); - aliasCreator.appendAliasPropertiesToMetaObjects(engine); + QQmlPropertyCacheAliasCreator<QV4::ExecutableCompilationUnit> aliasCreator( + &m_compiledData->propertyCaches, m_compiledData.data()); + aliasCreator.appendAliasPropertiesToMetaObjects(engine); + } pendingGroupPropertyBindings.resolveMissingPropertyCaches(&m_compiledData->propertyCaches); } |