aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml/qml
diff options
context:
space:
mode:
authorUlf Hermann <ulf.hermann@qt.io>2022-03-10 12:49:35 +0100
committerUlf Hermann <ulf.hermann@qt.io>2022-03-18 22:56:54 +0100
commitb5b5782088c25c67f090500d71fa1ae655383553 (patch)
treed14d054d570eefa303f80e6ce59ea076f43c1bb1 /src/qml/qml
parent7b8e6714e1e9707091898eba92f099c664879e80 (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.cpp31
-rw-r--r--src/qml/qml/qqmlmetatype_p.h31
-rw-r--r--src/qml/qml/qqmlmetatypedata.cpp52
-rw-r--r--src/qml/qml/qqmlmetatypedata_p.h16
-rw-r--r--src/qml/qml/qqmlopenmetaobject.cpp8
-rw-r--r--src/qml/qml/qqmlpropertycachecreator.cpp5
-rw-r--r--src/qml/qml/qqmlpropertycachecreator_p.h13
-rw-r--r--src/qml/qml/qqmlpropertycachevector_p.h81
-rw-r--r--src/qml/qml/qqmltypecompiler.cpp2
-rw-r--r--src/qml/qml/qqmltypedata.cpp8
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 &currentType = 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 &param, 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);
}