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>
This commit is contained in:
Ulf Hermann 2022-03-10 12:49:35 +01:00
parent 7b8e6714e1
commit b5b5782088
14 changed files with 175 additions and 84 deletions

View File

@ -149,7 +149,7 @@ public:
// QML specific fields
QQmlPropertyCacheVector propertyCaches;
QQmlRefPointer<QQmlPropertyCache> rootPropertyCache() const { return propertyCaches.at(/*root object*/0); }
QQmlPropertyCache::ConstPtr rootPropertyCache() const { return propertyCaches.at(/*root object*/0); }
QQmlRefPointer<QQmlTypeNameCache> typeNameCache;

View File

@ -83,7 +83,7 @@ QQmlPropertyCache::ConstPtr ResolvedTypeReference::propertyCache() const
/*!
Returns the property cache, creating one if it doesn't already exist. The cache is not referenced.
*/
QQmlRefPointer<QQmlPropertyCache> ResolvedTypeReference::createPropertyCache()
QQmlPropertyCache::ConstPtr ResolvedTypeReference::createPropertyCache()
{
if (m_typePropertyCache) {
return m_typePropertyCache;

View File

@ -74,7 +74,7 @@ public:
}
QQmlPropertyCache::ConstPtr propertyCache() const;
QQmlRefPointer<QQmlPropertyCache> createPropertyCache();
QQmlPropertyCache::ConstPtr createPropertyCache();
bool addToHash(QCryptographicHash *hash, QHash<quintptr, QByteArray> *checksums);
void doDynamicTypeCheck();
@ -115,7 +115,7 @@ public:
}
QQmlPropertyCache::ConstPtr typePropertyCache() const { return m_typePropertyCache; }
void setTypePropertyCache(QQmlRefPointer<QQmlPropertyCache> cache)
void setTypePropertyCache(QQmlPropertyCache::ConstPtr cache)
{
m_typePropertyCache = std::move(cache);
}
@ -128,7 +128,7 @@ public:
private:
QQmlType m_type;
QQmlRefPointer<QQmlPropertyCache> m_typePropertyCache;
QQmlPropertyCache::ConstPtr m_typePropertyCache;
QV4::ExecutableCompilationUnit *m_compilationUnit = nullptr;
QTypeRevision m_version = QTypeRevision::zero();

View File

@ -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);

View File

@ -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);

View File

@ -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);
}

View File

@ -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)
{

View File

@ -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;
};

View File

@ -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(

View File

@ -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();

View File

@ -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());
}
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 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();
}
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

View File

@ -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);

View File

@ -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);
}

View File

@ -118,7 +118,7 @@ void QQmlDesignerMetaObject::init(QObject *object)
QObjectPrivate *op = QObjectPrivate::get(object);
op->metaObject = this;
m_cache = QQmlMetaType::propertyCache(metaObject);
m_cache = QQmlMetaType::createPropertyCache(metaObject);
cache = m_cache;
nodeInstanceMetaObjectList.insert(this, true);