From 2a79c2bf4d9525a31e180d87d3fa249e98f5683e Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Fri, 23 Jun 2017 10:40:55 +0200 Subject: Turn QQmlType into a refcounted value type Task-number: QTBUG-61536 Change-Id: If906af2bf3afd09c23a612aaac417a751b06eba4 Reviewed-by: Simon Hausmann --- src/qml/qml/qqmlmetatype.cpp | 195 +++++++++++++++++++++++++++++-------------- src/qml/qml/qqmlmetatype_p.h | 14 +++- 2 files changed, 142 insertions(+), 67 deletions(-) (limited to 'src/qml/qml') diff --git a/src/qml/qml/qqmlmetatype.cpp b/src/qml/qml/qqmlmetatype.cpp index bb9b69c479..1959146388 100644 --- a/src/qml/qml/qqmlmetatype.cpp +++ b/src/qml/qml/qqmlmetatype.cpp @@ -155,6 +155,7 @@ QQmlMetaTypeData::~QQmlMetaTypeData() class QQmlTypePrivate { + Q_DISABLE_COPY(QQmlTypePrivate) public: QQmlTypePrivate(QQmlType::RegistrationType type); ~QQmlTypePrivate(); @@ -163,6 +164,7 @@ public: void initEnums() const; void insertEnums(const QMetaObject *metaObject) const; + QAtomicInt refCount; QQmlType::RegistrationType regType; struct QQmlCppTypeData @@ -278,7 +280,7 @@ QJSValue QQmlType::SingletonInstanceInfo::scriptApi(QQmlEngine *e) const QHash QQmlTypePrivate::attachedPropertyIds; QQmlTypePrivate::QQmlTypePrivate(QQmlType::RegistrationType type) -: regType(type), iid(0), typeId(0), listId(0), revision(0), +: refCount(1), regType(type), iid(0), typeId(0), listId(0), revision(0), containsRevisionedAttributes(false), superType(0), baseMetaObject(0), index(-1), isSetup(false), isEnumSetup(false), haveSuperType(false) { @@ -332,7 +334,7 @@ QQmlTypePrivate::~QQmlTypePrivate() } QQmlType::QQmlType(int index, const QQmlPrivate::RegisterInterface &interface) -: d(new QQmlTypePrivate(InterfaceType)) + : d(new QQmlTypePrivate(InterfaceType)) { d->iid = interface.iid; d->typeId = interface.typeId; @@ -344,7 +346,7 @@ QQmlType::QQmlType(int index, const QQmlPrivate::RegisterInterface &interface) } QQmlType::QQmlType(int index, const QString &elementName, const QQmlPrivate::RegisterSingletonType &type) -: d(new QQmlTypePrivate(SingletonType)) + : d(new QQmlTypePrivate(SingletonType)) { d->elementName = elementName; d->module = QString::fromUtf8(type.uri); @@ -372,7 +374,7 @@ QQmlType::QQmlType(int index, const QString &elementName, const QQmlPrivate::Reg } QQmlType::QQmlType(int index, const QString &elementName, const QQmlPrivate::RegisterCompositeSingletonType &type) - : d(new QQmlTypePrivate(CompositeSingletonType)) + : d(new QQmlTypePrivate(CompositeSingletonType)) { d->elementName = elementName; d->module = QString::fromUtf8(type.uri); @@ -388,7 +390,7 @@ QQmlType::QQmlType(int index, const QString &elementName, const QQmlPrivate::Reg } QQmlType::QQmlType(int index, const QString &elementName, const QQmlPrivate::RegisterType &type) -: d(new QQmlTypePrivate(CppType)) + : d(new QQmlTypePrivate(CppType)) { d->elementName = elementName; d->module = QString::fromUtf8(type.uri); @@ -425,7 +427,7 @@ QQmlType::QQmlType(int index, const QString &elementName, const QQmlPrivate::Reg } QQmlType::QQmlType(int index, const QString &elementName, const QQmlPrivate::RegisterCompositeType &type) -: d(new QQmlTypePrivate(CompositeType)) + : d(new QQmlTypePrivate(CompositeType)) { d->index = index; d->elementName = elementName; @@ -437,41 +439,78 @@ QQmlType::QQmlType(int index, const QString &elementName, const QQmlPrivate::Reg d->extraData.fd->url = type.url; } +QQmlType::QQmlType() + : d(0) +{ +} + +QQmlType::QQmlType(const QQmlType &other) + : d(other.d) +{ + if (d) + d->refCount.ref(); +} + +QQmlType &QQmlType::operator =(const QQmlType &other) +{ + if (d != other.d) { + if (d && !d->refCount.deref()) + delete d; + d = other.d; + if (d) + d->refCount.ref(); + } + return *this; +} + QQmlType::~QQmlType() { - delete d; + if (d && !d->refCount.deref()) + delete d; } -const QHashedString &QQmlType::module() const +QHashedString QQmlType::module() const { + if (!d) + return QHashedString(); return d->module; } int QQmlType::majorVersion() const { + if (!d) + return -1; return d->version_maj; } int QQmlType::minorVersion() const { + if (!d) + return -1; return d->version_min; } bool QQmlType::availableInVersion(int vmajor, int vminor) const { Q_ASSERT(vmajor >= 0 && vminor >= 0); + if (!d) + return false; return vmajor == d->version_maj && vminor >= d->version_min; } bool QQmlType::availableInVersion(const QHashedStringRef &module, int vmajor, int vminor) const { Q_ASSERT(vmajor >= 0 && vminor >= 0); + if (!d) + return false; return module == d->module && vmajor == d->version_maj && vminor >= d->version_min; } // returns the nearest _registered_ super class QQmlType *QQmlType::superType() const { + if (!d) + return 0; if (!d->haveSuperType && d->baseMetaObject) { const QMetaObject *mo = d->baseMetaObject->superClass(); while (mo && !d->superType) { @@ -487,7 +526,7 @@ QQmlType *QQmlType::superType() const QQmlType *QQmlType::resolveCompositeBaseType(QQmlEnginePrivate *engine) const { Q_ASSERT(isComposite()); - if (!engine) + if (!engine || !d) return 0; QQmlRefPointer td(engine->typeLoader.getType(sourceUrl()), QQmlRefPointer::Adopt); if (td.isNull() || !td->isComplete()) @@ -500,6 +539,8 @@ QQmlType *QQmlType::resolveCompositeBaseType(QQmlEnginePrivate *engine) const int QQmlType::resolveCompositeEnumValue(QQmlEnginePrivate *engine, const QString &name, bool *ok) const { Q_ASSERT(isComposite()); + if (!d) + return -1; *ok = false; QQmlType *type = resolveCompositeBaseType(engine); if (!type) @@ -709,21 +750,26 @@ void QQmlTypePrivate::insertEnums(const QMetaObject *metaObject) const QByteArray QQmlType::typeName() const { - if (d->regType == SingletonType || d->regType == CompositeSingletonType) - return d->extraData.sd->singletonInstanceInfo->typeName.toUtf8(); - else if (d->baseMetaObject) - return d->baseMetaObject->className(); - else - return QByteArray(); + if (d) { + if (d->regType == SingletonType || d->regType == CompositeSingletonType) + return d->extraData.sd->singletonInstanceInfo->typeName.toUtf8(); + else if (d->baseMetaObject) + return d->baseMetaObject->className(); + } + return QByteArray(); } -const QString &QQmlType::elementName() const +QString QQmlType::elementName() const { + if (!d) + return QString(); return d->elementName; } -const QString &QQmlType::qmlTypeName() const +QString QQmlType::qmlTypeName() const { + if (!d) + return QString(); if (d->name.isEmpty()) { if (!d->module.isEmpty()) d->name = static_cast(d->module) + QLatin1Char('/') + d->elementName; @@ -736,7 +782,7 @@ const QString &QQmlType::qmlTypeName() const QObject *QQmlType::create() const { - if (!isCreatable()) + if (!d || !isCreatable()) return 0; d->init(); @@ -752,7 +798,7 @@ QObject *QQmlType::create() const void QQmlType::create(QObject **out, void **memory, size_t additionalMemory) const { - if (!isCreatable()) + if (!d || !isCreatable()) return; d->init(); @@ -769,6 +815,8 @@ void QQmlType::create(QObject **out, void **memory, size_t additionalMemory) con QQmlType::SingletonInstanceInfo *QQmlType::singletonInstanceInfo() const { + if (!d) + return 0; if (d->regType != SingletonType && d->regType != CompositeSingletonType) return 0; return d->extraData.sd->singletonInstanceInfo; @@ -776,6 +824,8 @@ QQmlType::SingletonInstanceInfo *QQmlType::singletonInstanceInfo() const QQmlCustomParser *QQmlType::customParser() const { + if (!d) + return 0; if (d->regType != CppType) return 0; return d->extraData.cd->customParser; @@ -783,32 +833,34 @@ QQmlCustomParser *QQmlType::customParser() const QQmlType::CreateFunc QQmlType::createFunction() const { - if (d->regType != CppType) + if (!d || d->regType != CppType) return 0; return d->extraData.cd->newFunc; } QString QQmlType::noCreationReason() const { - if (d->regType != CppType) + if (!d || d->regType != CppType) return QString(); return d->extraData.cd->noCreationReason; } int QQmlType::createSize() const { - if (d->regType != CppType) + if (!d || d->regType != CppType) return 0; return d->extraData.cd->allocationSize; } bool QQmlType::isCreatable() const { - return d->regType == CppType && d->extraData.cd->newFunc; + return d && d->regType == CppType && d->extraData.cd->newFunc; } bool QQmlType::isExtendedType() const { + if (!d) + return false; d->init(); return !d->metaObjects.isEmpty(); @@ -816,36 +868,38 @@ bool QQmlType::isExtendedType() const bool QQmlType::isSingleton() const { - return d->regType == SingletonType || d->regType == CompositeSingletonType; + return d && (d->regType == SingletonType || d->regType == CompositeSingletonType); } bool QQmlType::isInterface() const { - return d->regType == InterfaceType; + return d && d->regType == InterfaceType; } bool QQmlType::isComposite() const { - return d->regType == CompositeType || d->regType == CompositeSingletonType; + return d && (d->regType == CompositeType || d->regType == CompositeSingletonType); } bool QQmlType::isCompositeSingleton() const { - return d->regType == CompositeSingletonType; + return d && d->regType == CompositeSingletonType; } int QQmlType::typeId() const { - return d->typeId; + return d ? d->typeId : -1; } int QQmlType::qListTypeId() const { - return d->listId; + return d ? d->listId : -1; } const QMetaObject *QQmlType::metaObject() const { + if (!d) + return 0; d->init(); if (d->metaObjects.isEmpty()) @@ -857,11 +911,13 @@ const QMetaObject *QQmlType::metaObject() const const QMetaObject *QQmlType::baseMetaObject() const { - return d->baseMetaObject; + return d ? d->baseMetaObject : 0; } bool QQmlType::containsRevisionedAttributes() const { + if (!d) + return false; d->init(); return d->containsRevisionedAttributes; @@ -869,11 +925,13 @@ bool QQmlType::containsRevisionedAttributes() const int QQmlType::metaObjectRevision() const { - return d->revision; + return d ? d->revision : -1; } QQmlAttachedPropertiesFunc QQmlType::attachedPropertiesFunction(QQmlEnginePrivate *engine) const { + if (!d) + return 0; if (d->regType == CppType) return d->extraData.cd->attachedPropertiesFunc; @@ -885,6 +943,8 @@ QQmlAttachedPropertiesFunc QQmlType::attachedPropertiesFunction(QQmlEnginePrivat const QMetaObject *QQmlType::attachedPropertiesType(QQmlEnginePrivate *engine) const { + if (!d) + return 0; if (d->regType == CppType) return d->extraData.cd->attachedPropertiesType; @@ -901,6 +961,8 @@ Qt 4.7 and QtQuick 1.0). */ int QQmlType::attachedPropertiesId(QQmlEnginePrivate *engine) const { + if (!d) + return -1; if (d->regType == CppType) return d->extraData.cd->attachedPropertiesId; @@ -912,59 +974,62 @@ int QQmlType::attachedPropertiesId(QQmlEnginePrivate *engine) const int QQmlType::parserStatusCast() const { - if (d->regType != CppType) + if (!d || d->regType != CppType) return -1; return d->extraData.cd->parserStatusCast; } int QQmlType::propertyValueSourceCast() const { - if (d->regType != CppType) + if (!d || d->regType != CppType) return -1; return d->extraData.cd->propertyValueSourceCast; } int QQmlType::propertyValueInterceptorCast() const { - if (d->regType != CppType) + if (!d || d->regType != CppType) return -1; return d->extraData.cd->propertyValueInterceptorCast; } const char *QQmlType::interfaceIId() const { - if (d->regType != InterfaceType) + if (!d || d->regType != InterfaceType) return 0; return d->iid; } int QQmlType::index() const { - return d->index; + return d ? d->index : -1; } QUrl QQmlType::sourceUrl() const { - if (d->regType == CompositeType) - return d->extraData.fd->url; - else if (d->regType == CompositeSingletonType) - return d->extraData.sd->singletonInstanceInfo->url; - else - return QUrl(); + if (d) { + if (d->regType == CompositeType) + return d->extraData.fd->url; + else if (d->regType == CompositeSingletonType) + return d->extraData.sd->singletonInstanceInfo->url; + } + return QUrl(); } int QQmlType::enumValue(QQmlEnginePrivate *engine, const QHashedStringRef &name, bool *ok) const { Q_ASSERT(ok); - if (isComposite()) - return resolveCompositeEnumValue(engine, name.toString(), ok); - *ok = true; + if (d) { + if (isComposite()) + return resolveCompositeEnumValue(engine, name.toString(), ok); + *ok = true; - d->initEnums(); + d->initEnums(); - int *rv = d->enums.value(name); - if (rv) - return *rv; + int *rv = d->enums.value(name); + if (rv) + return *rv; + } *ok = false; return -1; @@ -973,15 +1038,17 @@ int QQmlType::enumValue(QQmlEnginePrivate *engine, const QHashedStringRef &name, int QQmlType::enumValue(QQmlEnginePrivate *engine, const QHashedCStringRef &name, bool *ok) const { Q_ASSERT(ok); - if (isComposite()) - return resolveCompositeEnumValue(engine, name.toUtf16(), ok); - *ok = true; + if (d) { + if (isComposite()) + return resolveCompositeEnumValue(engine, name.toUtf16(), ok); + *ok = true; - d->initEnums(); + d->initEnums(); - int *rv = d->enums.value(name); - if (rv) - return *rv; + int *rv = d->enums.value(name); + if (rv) + return *rv; + } *ok = false; return -1; @@ -990,15 +1057,17 @@ int QQmlType::enumValue(QQmlEnginePrivate *engine, const QHashedCStringRef &name int QQmlType::enumValue(QQmlEnginePrivate *engine, const QV4::String *name, bool *ok) const { Q_ASSERT(ok); - if (isComposite()) - return resolveCompositeEnumValue(engine, name->toQString(), ok); - *ok = true; + if (d) { + if (isComposite()) + return resolveCompositeEnumValue(engine, name->toQString(), ok); + *ok = true; - d->initEnums(); + d->initEnums(); - int *rv = d->enums.value(name); - if (rv) - return *rv; + int *rv = d->enums.value(name); + if (rv) + return *rv; + } *ok = false; return -1; diff --git a/src/qml/qml/qqmlmetatype_p.h b/src/qml/qml/qqmlmetatype_p.h index 2b615e645a..e3752b7bf8 100644 --- a/src/qml/qml/qqmlmetatype_p.h +++ b/src/qml/qml/qqmlmetatype_p.h @@ -138,11 +138,18 @@ class QHashedCStringRef; class Q_QML_PRIVATE_EXPORT QQmlType { public: + QQmlType(); + QQmlType(const QQmlType &other); + QQmlType &operator =(const QQmlType &other); + ~QQmlType(); + + bool isValid() const { return d != 0; } + QByteArray typeName() const; - const QString &qmlTypeName() const; - const QString &elementName() const; + QString qmlTypeName() const; + QString elementName() const; - const QHashedString &module() const; + QHashedString module() const; int majorVersion() const; int minorVersion() const; @@ -244,7 +251,6 @@ private: QQmlType(int, const QString &, const QQmlPrivate::RegisterType &); QQmlType(int, const QString &, const QQmlPrivate::RegisterCompositeType &); QQmlType(int, const QString &, const QQmlPrivate::RegisterCompositeSingletonType &); - ~QQmlType(); QQmlTypePrivate *d; }; -- cgit v1.2.3 From a6633e41e7c6795bbbc016ce36e4ff91ec5248ad Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Fri, 23 Jun 2017 13:09:03 +0200 Subject: Use QQmlType by value in the type wrapper Task-number: QTBUG-61536 Change-Id: Ie40cb3a6e170331b0ec7ab5deaf7c1d7ef0cdaeb Reviewed-by: Simon Hausmann --- src/qml/qml/qqmlmetatype.cpp | 19 ++++++++++++ src/qml/qml/qqmlmetatype_p.h | 5 +++ src/qml/qml/qqmltypewrapper.cpp | 67 +++++++++++++++++++++-------------------- src/qml/qml/qqmltypewrapper_p.h | 6 ++-- 4 files changed, 63 insertions(+), 34 deletions(-) (limited to 'src/qml/qml') diff --git a/src/qml/qml/qqmlmetatype.cpp b/src/qml/qml/qqmlmetatype.cpp index 1959146388..2ff2cdc189 100644 --- a/src/qml/qml/qqmlmetatype.cpp +++ b/src/qml/qml/qqmlmetatype.cpp @@ -463,6 +463,13 @@ QQmlType &QQmlType::operator =(const QQmlType &other) return *this; } +QQmlType::QQmlType(QQmlTypePrivate *priv) + : d(priv) +{ + if (d) + d->refCount.ref(); +} + QQmlType::~QQmlType() { if (d && !d->refCount.deref()) @@ -1073,6 +1080,18 @@ int QQmlType::enumValue(QQmlEnginePrivate *engine, const QV4::String *name, bool return -1; } +void QQmlType::refHandle(QQmlTypePrivate *priv) +{ + if (priv) + priv->refCount.ref(); +} + +void QQmlType::derefHandle(QQmlTypePrivate *priv) +{ + if (priv && !priv->refCount.deref()) + delete priv; +} + QQmlTypeModule::QQmlTypeModule() : d(new QQmlTypeModulePrivate) { diff --git a/src/qml/qml/qqmlmetatype_p.h b/src/qml/qml/qqmlmetatype_p.h index e3752b7bf8..08198340f3 100644 --- a/src/qml/qml/qqmlmetatype_p.h +++ b/src/qml/qml/qqmlmetatype_p.h @@ -141,6 +141,7 @@ public: QQmlType(); QQmlType(const QQmlType &other); QQmlType &operator =(const QQmlType &other); + explicit QQmlType(QQmlTypePrivate *priv); ~QQmlType(); bool isValid() const { return d != 0; } @@ -223,6 +224,10 @@ public: int enumValue(QQmlEnginePrivate *engine, const QHashedStringRef &, bool *ok) const; int enumValue(QQmlEnginePrivate *engine, const QHashedCStringRef &, bool *ok) const; int enumValue(QQmlEnginePrivate *engine, const QV4::String *, bool *ok) const; + + QQmlTypePrivate *handle() const { return d; } + static void refHandle(QQmlTypePrivate *priv); + static void derefHandle(QQmlTypePrivate *priv); private: QQmlType *superType() const; QQmlType *resolveCompositeBaseType(QQmlEnginePrivate *engine) const; diff --git a/src/qml/qml/qqmltypewrapper.cpp b/src/qml/qml/qqmltypewrapper.cpp index be4ab68831..0656bd4c62 100644 --- a/src/qml/qml/qqmltypewrapper.cpp +++ b/src/qml/qml/qqmltypewrapper.cpp @@ -63,15 +63,22 @@ void Heap::QmlTypeWrapper::init() void Heap::QmlTypeWrapper::destroy() { + QQmlType::derefHandle(typePrivate); + typePrivate = nullptr; if (typeNamespace) typeNamespace->release(); object.destroy(); Object::destroy(); } +QQmlType Heap::QmlTypeWrapper::type() const +{ + return QQmlType(typePrivate); +} + bool QmlTypeWrapper::isSingleton() const { - return d()->type && d()->type->isSingleton(); + return d()->type().isSingleton(); } QObject* QmlTypeWrapper::singletonObject() const @@ -80,22 +87,16 @@ QObject* QmlTypeWrapper::singletonObject() const return 0; QQmlEngine *e = engine()->qmlEngine(); - QQmlType::SingletonInstanceInfo *siinfo = d()->type->singletonInstanceInfo(); + QQmlType::SingletonInstanceInfo *siinfo = d()->type().singletonInstanceInfo(); siinfo->init(e); return siinfo->qobjectApi(e); } QVariant QmlTypeWrapper::toVariant() const { - if (d()->type && d()->type->isSingleton()) { - QQmlEngine *e = engine()->qmlEngine(); - QQmlType::SingletonInstanceInfo *siinfo = d()->type->singletonInstanceInfo(); - siinfo->init(e); // note: this will also create QJSValue singleton which isn't strictly required. - QObject *qobjectSingleton = siinfo->qobjectApi(e); - if (qobjectSingleton) { - return QVariant::fromValue(qobjectSingleton); - } - } + QObject *qobjectSingleton = singletonObject(); + if (qobjectSingleton) + return QVariant::fromValue(qobjectSingleton); // only QObject Singleton Type can be converted to a variant. return QVariant(); @@ -103,14 +104,16 @@ QVariant QmlTypeWrapper::toVariant() const // Returns a type wrapper for type t on o. This allows access of enums, and attached properties. -ReturnedValue QmlTypeWrapper::create(QV4::ExecutionEngine *engine, QObject *o, QQmlType *t, +ReturnedValue QmlTypeWrapper::create(QV4::ExecutionEngine *engine, QObject *o, const QQmlType &t, Heap::QmlTypeWrapper::TypeNameMode mode) { - Q_ASSERT(t); + Q_ASSERT(t.isValid()); Scope scope(engine); Scoped w(scope, engine->memoryManager->allocObject()); - w->d()->mode = mode; w->d()->object = o; w->d()->type = t; + w->d()->mode = mode; w->d()->object = o; + w->d()->typePrivate = t.handle(); + QQmlType::refHandle(w->d()->typePrivate); return w.asReturnedValue(); } @@ -130,10 +133,10 @@ ReturnedValue QmlTypeWrapper::create(QV4::ExecutionEngine *engine, QObject *o, Q } static int enumForSingleton(QV4::ExecutionEngine *v4, String *name, QObject *qobjectSingleton, - QQmlType *type) + const QQmlType &type) { bool ok; - int value = type->enumValue(QQmlEnginePrivate::get(v4->qmlEngine()), name, &ok); + int value = type.enumValue(QQmlEnginePrivate::get(v4->qmlEngine()), name, &ok); if (ok) return value; @@ -149,11 +152,11 @@ static int enumForSingleton(QV4::ExecutionEngine *v4, String *name, QObject *qob return -1; } -static ReturnedValue throwLowercaseEnumError(QV4::ExecutionEngine *v4, String *name, QQmlType *type) +static ReturnedValue throwLowercaseEnumError(QV4::ExecutionEngine *v4, String *name, const QQmlType &type) { const QString message = QStringLiteral("Cannot access enum value '%1' of '%2', enum values need to start with an uppercase letter.") - .arg(name->toQString()).arg(QLatin1String(type->typeName())); + .arg(name->toQString()).arg(QLatin1String(type.typeName())); return v4->throwTypeError(message); } @@ -172,14 +175,14 @@ ReturnedValue QmlTypeWrapper::get(const Managed *m, String *name, bool *hasPrope QQmlContextData *context = v4->callingQmlContext(); QObject *object = w->d()->object; - QQmlType *type = w->d()->type; + QQmlType type = w->d()->type(); - if (type) { + if (type.isValid()) { // singleton types are handled differently to other types. - if (type->isSingleton()) { + if (type.isSingleton()) { QQmlEngine *e = v4->qmlEngine(); - QQmlType::SingletonInstanceInfo *siinfo = type->singletonInstanceInfo(); + QQmlType::SingletonInstanceInfo *siinfo = type.singletonInstanceInfo(); siinfo->init(e); QObject *qobjectSingleton = siinfo->qobjectApi(e); @@ -220,14 +223,14 @@ ReturnedValue QmlTypeWrapper::get(const Managed *m, String *name, bool *hasPrope if (name->startsWithUpper()) { bool ok = false; - int value = type->enumValue(QQmlEnginePrivate::get(v4->qmlEngine()), name, &ok); + int value = type.enumValue(QQmlEnginePrivate::get(v4->qmlEngine()), name, &ok); if (ok) return QV4::Primitive::fromInt32(value).asReturnedValue(); // Fall through to base implementation } else if (w->d()->object) { - QObject *ao = qmlAttachedPropertiesObjectById(type->attachedPropertiesId(QQmlEnginePrivate::get(v4->qmlEngine())), object); + QObject *ao = qmlAttachedPropertiesObjectById(type.attachedPropertiesId(QQmlEnginePrivate::get(v4->qmlEngine())), object); if (ao) return QV4::QObjectWrapper::getQmlProperty(v4, context, ao, name, QV4::QObjectWrapper::IgnoreRevision, hasProperty); @@ -245,7 +248,7 @@ ReturnedValue QmlTypeWrapper::get(const Managed *m, String *name, bool *hasPrope if (r.isValid()) { if (r.type) { - return create(scope.engine, object, r.type, w->d()->mode); + return create(scope.engine, object, *r.type, w->d()->mode); } else if (r.scriptIndex != -1) { QV4::ScopedObject scripts(scope, context->importedScripts.valueRef()); return scripts->getIndexed(r.scriptIndex); @@ -269,9 +272,9 @@ ReturnedValue QmlTypeWrapper::get(const Managed *m, String *name, bool *hasPrope *hasProperty = ok; // Warn when attempting to access a lowercased enum value, non-singleton case - if (!ok && type && !type->isSingleton() && !name->startsWithUpper()) { + if (!ok && type.isValid() && !type.isSingleton() && !name->startsWithUpper()) { bool enumOk = false; - type->enumValue(QQmlEnginePrivate::get(v4->qmlEngine()), name, &enumOk); + type.enumValue(QQmlEnginePrivate::get(v4->qmlEngine()), name, &enumOk); if (enumOk) return throwLowercaseEnumError(v4, name, type); } @@ -291,16 +294,16 @@ void QmlTypeWrapper::put(Managed *m, String *name, const Value &value) QV4::Scope scope(v4); QQmlContextData *context = v4->callingQmlContext(); - QQmlType *type = w->d()->type; - if (type && !type->isSingleton() && w->d()->object) { + QQmlType type = w->d()->type(); + if (type.isValid() && !type.isSingleton() && w->d()->object) { QObject *object = w->d()->object; QQmlEngine *e = scope.engine->qmlEngine(); - QObject *ao = qmlAttachedPropertiesObjectById(type->attachedPropertiesId(QQmlEnginePrivate::get(e)), object); + QObject *ao = qmlAttachedPropertiesObjectById(type.attachedPropertiesId(QQmlEnginePrivate::get(e)), object); if (ao) QV4::QObjectWrapper::setQmlProperty(v4, context, ao, name, QV4::QObjectWrapper::IgnoreRevision, value); - } else if (type && type->isSingleton()) { + } else if (type.isValid() && type.isSingleton()) { QQmlEngine *e = scope.engine->qmlEngine(); - QQmlType::SingletonInstanceInfo *siinfo = type->singletonInstanceInfo(); + QQmlType::SingletonInstanceInfo *siinfo = type.singletonInstanceInfo(); siinfo->init(e); QObject *qobjectSingleton = siinfo->qobjectApi(e); diff --git a/src/qml/qml/qqmltypewrapper_p.h b/src/qml/qml/qqmltypewrapper_p.h index 3b0ae04cc1..c21a66424b 100644 --- a/src/qml/qml/qqmltypewrapper_p.h +++ b/src/qml/qml/qqmltypewrapper_p.h @@ -76,7 +76,9 @@ struct QmlTypeWrapper : Object { TypeNameMode mode; QQmlQPointer object; - QQmlType *type; + QQmlType type() const; + + QQmlTypePrivate *typePrivate; QQmlTypeNameCache *typeNamespace; const void *importNamespace; }; @@ -93,7 +95,7 @@ struct Q_QML_EXPORT QmlTypeWrapper : Object QVariant toVariant() const; - static ReturnedValue create(ExecutionEngine *, QObject *, QQmlType *, + static ReturnedValue create(ExecutionEngine *, QObject *, const QQmlType &, Heap::QmlTypeWrapper::TypeNameMode = Heap::QmlTypeWrapper::IncludeEnums); static ReturnedValue create(ExecutionEngine *, QObject *, QQmlTypeNameCache *, const void *, Heap::QmlTypeWrapper::TypeNameMode = Heap::QmlTypeWrapper::IncludeEnums); -- cgit v1.2.3 From 49a11e882059ee1729f776722e085dd21d378c36 Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Fri, 23 Jun 2017 13:20:23 +0200 Subject: Use QQmlType by value QQmlType is now refcounted, and we need to use it by value, to control it's lifetime properly. This is required, so we can clean up the QQmlMetaTypeData cache on engine destruction and with trimComponentCache() Task-number: QTBUG-61536 Change-Id: If86391c86ea20a646ded7c9925d8f743f628fb91 Reviewed-by: Simon Hausmann --- src/qml/qml/qqmlcustomparser.cpp | 10 ++- src/qml/qml/qqmlengine.cpp | 47 ++++++------ src/qml/qml/qqmlengine_p.h | 14 ++-- src/qml/qml/qqmlimport.cpp | 56 ++++++++------- src/qml/qml/qqmlimport_p.h | 12 ++-- src/qml/qml/qqmllist.cpp | 2 +- src/qml/qml/qqmlmetatype.cpp | 147 ++++++++++++++++++++------------------ src/qml/qml/qqmlmetatype_p.h | 52 +++++++++----- src/qml/qml/qqmlobjectcreator.cpp | 34 ++++----- src/qml/qml/qqmlproperty.cpp | 23 +++--- src/qml/qml/qqmltypeloader.cpp | 46 ++++++------ src/qml/qml/qqmltypeloader_p.h | 4 +- src/qml/qml/qqmltypenamecache.cpp | 8 +-- src/qml/qml/qqmltypenamecache_p.h | 22 +++--- src/qml/qml/qqmltypewrapper.cpp | 6 +- 15 files changed, 252 insertions(+), 231 deletions(-) (limited to 'src/qml/qml') diff --git a/src/qml/qml/qqmlcustomparser.cpp b/src/qml/qml/qqmlcustomparser.cpp index 0b0bbef795..ecdaf41523 100644 --- a/src/qml/qml/qqmlcustomparser.cpp +++ b/src/qml/qml/qqmlcustomparser.cpp @@ -132,7 +132,7 @@ int QQmlCustomParser::evaluateEnum(const QByteArray& script, bool *ok) const if (scope != QLatin1String("Qt")) { if (imports.isNull()) return -1; - QQmlType *type = 0; + QQmlType type; if (imports.isT1()) { imports.asT1()->resolveType(scope, &type, 0, 0, 0); @@ -142,7 +142,7 @@ int QQmlCustomParser::evaluateEnum(const QByteArray& script, bool *ok) const type = result.type; } - return type ? type->enumValue(engine, QHashedCStringRef(enumValue.constData(), enumValue.length()), ok) : -1; + return type.enumValue(engine, QHashedCStringRef(enumValue.constData(), enumValue.length()), ok); } const QMetaObject *mo = StaticQtMetaObject::get(); @@ -163,12 +163,10 @@ const QMetaObject *QQmlCustomParser::resolveType(const QString& name) const { if (!imports.isT1()) return nullptr; - QQmlType *qmltype = 0; + QQmlType qmltype; if (!imports.asT1()->resolveType(name, &qmltype, 0, 0, 0)) return nullptr; - if (!qmltype) - return nullptr; - return qmltype->metaObject(); + return qmltype.metaObject(); } QT_END_NAMESPACE diff --git a/src/qml/qml/qqmlengine.cpp b/src/qml/qml/qqmlengine.cpp index ba22bfde76..7aae994c29 100644 --- a/src/qml/qml/qqmlengine.cpp +++ b/src/qml/qml/qqmlengine.cpp @@ -677,7 +677,7 @@ QQmlEnginePrivate::QQmlEnginePrivate(QQmlEngine *e) QQmlEnginePrivate::~QQmlEnginePrivate() { - typedef QHash, QQmlPropertyCache *>::const_iterator TypePropertyCacheIt; + typedef QHash, 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); @@ -1022,9 +1022,9 @@ QQmlEngine::~QQmlEngine() // we do this here and not in the private dtor since otherwise a crash can // occur (if we are the QObject parent of the QObject singleton instance) // XXX TODO: performance -- store list of singleton types separately? - const QList singletonTypes = QQmlMetaType::qmlSingletonTypes(); - for (QQmlType *currType : singletonTypes) - currType->singletonInstanceInfo()->destroy(this); + QList singletonTypes = QQmlMetaType::qmlSingletonTypes(); + for (const QQmlType &currType : singletonTypes) + currType.singletonInstanceInfo()->destroy(this); delete d->rootContext; d->rootContext = 0; @@ -2194,19 +2194,18 @@ QString QQmlEnginePrivate::offlineStorageDatabaseDirectory() const return q->offlineStoragePath() + QDir::separator() + QLatin1String("Databases") + QDir::separator(); } -QQmlPropertyCache *QQmlEnginePrivate::createCache(QQmlType *type, int minorVersion) +QQmlPropertyCache *QQmlEnginePrivate::createCache(const QQmlType &type, int minorVersion) { - QList types; + QVector types; int maxMinorVersion = 0; - const QMetaObject *metaObject = type->metaObject(); + const QMetaObject *metaObject = type.metaObject(); while (metaObject) { - QQmlType *t = QQmlMetaType::qmlType(metaObject, type->module(), - type->majorVersion(), minorVersion); - if (t) { - maxMinorVersion = qMax(maxMinorVersion, t->minorVersion()); + QQmlType t = QQmlMetaType::qmlType(metaObject, type.module(), type.majorVersion(), minorVersion); + if (t.isValid()) { + maxMinorVersion = qMax(maxMinorVersion, t.minorVersion()); types << t; } else { types << 0; @@ -2221,16 +2220,16 @@ QQmlPropertyCache *QQmlEnginePrivate::createCache(QQmlType *type, int minorVersi return c; } - QQmlPropertyCache *raw = cache(type->metaObject()); + QQmlPropertyCache *raw = cache(type.metaObject()); bool hasCopied = false; for (int ii = 0; ii < types.count(); ++ii) { - QQmlType *currentType = types.at(ii); - if (!currentType) + QQmlType currentType = types.at(ii); + if (!currentType.isValid()) continue; - int rev = currentType->metaObjectRevision(); + int rev = currentType.metaObjectRevision(); int moIndex = types.count() - 1 - ii; if (raw->allowedRevisionCache[moIndex] != rev) { @@ -2280,7 +2279,7 @@ QQmlPropertyCache *QQmlEnginePrivate::createCache(QQmlType *type, int minorVersi 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.")); + 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 @@ -2348,8 +2347,8 @@ QQmlMetaObject QQmlEnginePrivate::rawMetaObjectForType(int t) const if (iter != m_compositeTypes.cend()) { return QQmlMetaObject((*iter)->rootPropertyCache()); } else { - QQmlType *type = QQmlMetaType::qmlType(t); - return QQmlMetaObject(type?type->baseMetaObject():0); + QQmlType type = QQmlMetaType::qmlType(t); + return QQmlMetaObject(type.baseMetaObject()); } } @@ -2360,8 +2359,8 @@ QQmlMetaObject QQmlEnginePrivate::metaObjectForType(int t) const if (iter != m_compositeTypes.cend()) { return QQmlMetaObject((*iter)->rootPropertyCache()); } else { - QQmlType *type = QQmlMetaType::qmlType(t); - return QQmlMetaObject(type?type->metaObject():0); + QQmlType type = QQmlMetaType::qmlType(t); + return QQmlMetaObject(type.metaObject()); } } @@ -2372,9 +2371,9 @@ QQmlPropertyCache *QQmlEnginePrivate::propertyCacheForType(int t) if (iter != m_compositeTypes.cend()) { return (*iter)->rootPropertyCache(); } else { - QQmlType *type = QQmlMetaType::qmlType(t); + QQmlType type = QQmlMetaType::qmlType(t); locker.unlock(); - return type?cache(type->metaObject()):0; + return type.isValid() ? cache(type.metaObject()) : 0; } } @@ -2385,9 +2384,9 @@ QQmlPropertyCache *QQmlEnginePrivate::rawPropertyCacheForType(int t) if (iter != m_compositeTypes.cend()) { return (*iter)->rootPropertyCache(); } else { - QQmlType *type = QQmlMetaType::qmlType(t); + QQmlType type = QQmlMetaType::qmlType(t); locker.unlock(); - return type?cache(type->baseMetaObject()):0; + return type.isValid() ? cache(type.baseMetaObject()) : 0; } } diff --git a/src/qml/qml/qqmlengine_p.h b/src/qml/qml/qqmlengine_p.h index 1bdeacd524..3ed8dbccff 100644 --- a/src/qml/qml/qqmlengine_p.h +++ b/src/qml/qml/qqmlengine_p.h @@ -208,7 +208,7 @@ public: QString offlineStorageDatabaseDirectory() const; // These methods may be called from the loader thread - inline QQmlPropertyCache *cache(QQmlType *, int); + inline QQmlPropertyCache *cache(const QQmlType &, int); using QJSEnginePrivate::cache; // These methods may be called from the loader thread @@ -260,11 +260,11 @@ public: private: // Must be called locked - QQmlPropertyCache *createCache(QQmlType *, int); + 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, QQmlPropertyCache *> typePropertyCache; + QHash, QQmlPropertyCache *> typePropertyCache; QHash m_qmlLists; QHash m_compositeTypes; static bool s_designerMode; @@ -375,12 +375,12 @@ Returns a QQmlPropertyCache for \a type with \a minorVersion. The returned cache is not referenced, so if it is to be stored, call addref(). */ -QQmlPropertyCache *QQmlEnginePrivate::cache(QQmlType *type, int minorVersion) +QQmlPropertyCache *QQmlEnginePrivate::cache(const QQmlType &type, int minorVersion) { - Q_ASSERT(type); + Q_ASSERT(type.isValid()); - if (minorVersion == -1 || !type->containsRevisionedAttributes()) - return cache(type->metaObject()); + if (minorVersion == -1 || !type.containsRevisionedAttributes()) + return cache(type.metaObject()); Locker locker(this); QQmlPropertyCache *rv = typePropertyCache.value(qMakePair(type, minorVersion)); diff --git a/src/qml/qml/qqmlimport.cpp b/src/qml/qml/qqmlimport.cpp index ec748d1ca9..89c7fd3214 100644 --- a/src/qml/qml/qqmlimport.cpp +++ b/src/qml/qml/qqmlimport.cpp @@ -142,13 +142,13 @@ bool isPathAbsolute(const QString &path) Errors (if there are any) are placed into \a errors, if it is nonzero. Note that errors are treated as fatal if \a errors is not set. */ -QQmlType *fetchOrCreateTypeForUrl(const QString &urlString, const QHashedStringRef& typeName, +QQmlType fetchOrCreateTypeForUrl(const QString &urlString, const QHashedStringRef& typeName, bool isCompositeSingleton, QList *errors, int majorVersion=-1, int minorVersion=-1) { QUrl url(urlString); // ### unfortunate (costly) conversion - QQmlType *ret = QQmlMetaType::qmlType(url); - if (ret) + QQmlType ret = QQmlMetaType::qmlType(url); + if (ret.isValid()) return ret; int dot = typeName.indexOf(QLatin1Char('.')); @@ -198,7 +198,7 @@ QQmlType *fetchOrCreateTypeForUrl(const QString &urlString, const QHashedStringR // This means that the type couldn't be found by URL, but could not be // registered either, meaning we most likely were passed some kind of bad // data. - if (!ret) { + if (!ret.isValid()) { if (!errors) // Cannot list errors properly, just quit qFatal("%s", QQmlMetaType::typeRegistrationFailures().join('\n').toLatin1().constData()); QQmlError error; @@ -295,7 +295,7 @@ public: QList *errors); bool resolveType(const QHashedStringRef &type, int *vmajor, int *vminor, - QQmlType** type_return, QList *errors); + QQmlType *type_return, QList *errors); QUrl baseUrl; QString base; @@ -619,7 +619,7 @@ QString QQmlImports::versionString(int vmaj, int vmin, ImportVersion version) \sa addFileImport(), addLibraryImport */ bool QQmlImports::resolveType(const QHashedStringRef &type, - QQmlType** type_return, int *vmaj, int *vmin, + QQmlType *type_return, int *vmaj, int *vmin, QQmlImportNamespace** ns_return, QList *errors) const { QQmlImportNamespace* ns = d->findQualifiedNamespace(type); @@ -629,17 +629,19 @@ bool QQmlImports::resolveType(const QHashedStringRef &type, return true; } if (type_return) { - if (d->resolveType(type,vmaj,vmin,type_return, errors)) { + if (d->resolveType(type, vmaj, vmin, type_return, errors)) { if (qmlImportTrace()) { #define RESOLVE_TYPE_DEBUG qDebug().nospace() << "QQmlImports(" << qPrintable(baseUrl().toString()) \ << ')' << "::resolveType: " << type.toString() << " => " - if (type_return && *type_return && (*type_return)->isCompositeSingleton()) - RESOLVE_TYPE_DEBUG << (*type_return)->typeName() << ' ' << (*type_return)->sourceUrl() << " TYPE/URL-SINGLETON"; - else if (type_return && *type_return && (*type_return)->isComposite()) - RESOLVE_TYPE_DEBUG << (*type_return)->typeName() << ' ' << (*type_return)->sourceUrl() << " TYPE/URL"; - else if (type_return && *type_return) - RESOLVE_TYPE_DEBUG << (*type_return)->typeName() << " TYPE"; + if (type_return && type_return->isValid()) { + if (type_return->isCompositeSingleton()) + RESOLVE_TYPE_DEBUG << type_return->typeName() << ' ' << type_return->sourceUrl() << " TYPE/URL-SINGLETON"; + else if (type_return->isComposite()) + RESOLVE_TYPE_DEBUG << type_return->typeName() << ' ' << type_return->sourceUrl() << " TYPE/URL"; + else + RESOLVE_TYPE_DEBUG << type_return->typeName() << " TYPE"; + } #undef RESOLVE_TYPE_DEBUG } return true; @@ -704,19 +706,19 @@ QQmlDirScripts QQmlImportInstance::getVersionedScripts(const QQmlDirScripts &qml If the return pointer is 0, the corresponding search is not done. */ -bool QQmlImports::resolveType(QQmlImportNamespace* ns, const QHashedStringRef &type, - QQmlType** type_return, int *vmaj, int *vmin) const +bool QQmlImports::resolveType(QQmlImportNamespace *ns, const QHashedStringRef &type, + QQmlType *type_return, int *vmaj, int *vmin) const { - return ns->resolveType(d->typeLoader,type,vmaj,vmin,type_return); + return ns->resolveType(d->typeLoader, type, vmaj, vmin, type_return); } bool QQmlImportInstance::resolveType(QQmlTypeLoader *typeLoader, const QHashedStringRef& type, int *vmajor, int *vminor, - QQmlType** type_return, QString *base, bool *typeRecursionDetected) const + QQmlType* type_return, QString *base, bool *typeRecursionDetected) const { if (majversion >= 0 && minversion >= 0) { - QQmlType *t = QQmlMetaType::qmlType(type, uri, majversion, minversion); - if (t) { + QQmlType t = QQmlMetaType::qmlType(type, uri, majversion, minversion); + if (t.isValid()) { if (vmajor) *vmajor = majversion; if (vminor) *vminor = minversion; if (type_return) @@ -766,11 +768,11 @@ bool QQmlImportInstance::resolveType(QQmlTypeLoader *typeLoader, componentUrl = resolveLocalUrl(QString(url + candidate->typeName + dotqml_string), candidate->fileName); int major = vmajor ? *vmajor : -1; int minor = vminor ? *vminor : -1; - QQmlType *returnType = fetchOrCreateTypeForUrl(componentUrl, type, isCompositeSingleton, 0, + QQmlType returnType = fetchOrCreateTypeForUrl(componentUrl, type, isCompositeSingleton, 0, major, minor); if (type_return) *type_return = returnType; - return returnType != 0; + return returnType.isValid(); } } else if (!isLibrary) { QString qmlUrl; @@ -794,10 +796,10 @@ bool QQmlImportInstance::resolveType(QQmlTypeLoader *typeLoader, if (typeRecursionDetected) *typeRecursionDetected = true; } else { - QQmlType *returnType = fetchOrCreateTypeForUrl(qmlUrl, type, false, 0); + QQmlType returnType = fetchOrCreateTypeForUrl(qmlUrl, type, false, 0); if (type_return) *type_return = returnType; - return returnType != 0; + return returnType.isValid(); } } } @@ -806,7 +808,7 @@ bool QQmlImportInstance::resolveType(QQmlTypeLoader *typeLoader, } bool QQmlImportsPrivate::resolveType(const QHashedStringRef& type, int *vmajor, int *vminor, - QQmlType** type_return, QList *errors) + QQmlType *type_return, QList *errors) { QQmlImportNamespace *s = 0; int dot = type.indexOf(Dot); @@ -835,12 +837,12 @@ bool QQmlImportsPrivate::resolveType(const QHashedStringRef& type, int *vmajor, } QHashedStringRef unqualifiedtype = dot < 0 ? type : QHashedStringRef(type.constData()+dot+1, type.length()-dot-1); if (s) { - if (s->resolveType(typeLoader,unqualifiedtype,vmajor,vminor,type_return, &base, errors)) + if (s->resolveType(typeLoader, unqualifiedtype, vmajor, vminor, type_return, &base, errors)) return true; if (s->imports.count() == 1 && !s->imports.at(0)->isLibrary && type_return && s != &unqualifiedset) { // qualified, and only 1 url *type_return = fetchOrCreateTypeForUrl(resolveLocalUrl(s->imports.at(0)->url, unqualifiedtype.toString() + QLatin1String(".qml")), type, false, errors); - return (*type_return != 0); + return type_return->isValid(); } } @@ -857,7 +859,7 @@ QQmlImportInstance *QQmlImportNamespace::findImport(const QString &uri) const } bool QQmlImportNamespace::resolveType(QQmlTypeLoader *typeLoader, const QHashedStringRef &type, - int *vmajor, int *vminor, QQmlType** type_return, + int *vmajor, int *vminor, QQmlType *type_return, QString *base, QList *errors) { bool typeRecursionDetected = false; diff --git a/src/qml/qml/qqmlimport_p.h b/src/qml/qml/qqmlimport_p.h index 7c691a468c..8a0a4ea4f1 100644 --- a/src/qml/qml/qqmlimport_p.h +++ b/src/qml/qml/qqmlimport_p.h @@ -86,7 +86,7 @@ struct QQmlImportInstance static QQmlDirScripts getVersionedScripts(const QQmlDirScripts &qmldirscripts, int vmaj, int vmin); bool resolveType(QQmlTypeLoader *typeLoader, const QHashedStringRef &type, - int *vmajor, int *vminor, QQmlType** type_return, + int *vmajor, int *vminor, QQmlType* type_return, QString *base = 0, bool *typeRecursionDetected = 0) const; }; @@ -101,7 +101,7 @@ public: QQmlImportInstance *findImport(const QString &uri) const; bool resolveType(QQmlTypeLoader *typeLoader, const QHashedStringRef& type, - int *vmajor, int *vminor, QQmlType** type_return, + int *vmajor, int *vminor, QQmlType* type_return, QString *base = 0, QList *errors = 0); // Prefix when used as a qualified import. Otherwise empty. @@ -125,13 +125,13 @@ public: QUrl baseUrl() const; bool resolveType(const QHashedStringRef &type, - QQmlType** type_return, + QQmlType *type_return, int *version_major, int *version_minor, - QQmlImportNamespace** ns_return, + QQmlImportNamespace **ns_return, QList *errors = 0) const; - bool resolveType(QQmlImportNamespace*, + bool resolveType(QQmlImportNamespace *, const QHashedStringRef& type, - QQmlType** type_return, int *version_major, int *version_minor) const; + QQmlType *type_return, int *version_major, int *version_minor) const; bool addImplicitImport(QQmlImportDatabase *importDb, QList *errors); diff --git a/src/qml/qml/qqmllist.cpp b/src/qml/qml/qqmllist.cpp index 2c71293363..71be2e82a3 100644 --- a/src/qml/qml/qqmllist.cpp +++ b/src/qml/qml/qqmllist.cpp @@ -148,7 +148,7 @@ QQmlListReference::QQmlListReference(QObject *object, const char *property, QQml d = new QQmlListReferencePrivate; d->object = object; - d->elementType = p?p->rawMetaObjectForType(listType):QQmlMetaType::qmlType(listType)->baseMetaObject(); + d->elementType = p ? p->rawMetaObjectForType(listType) : QQmlMetaType::qmlType(listType).baseMetaObject(); d->propertyType = data->propType(); void *args[] = { &d->property, 0 }; diff --git a/src/qml/qml/qqmlmetatype.cpp b/src/qml/qml/qqmlmetatype.cpp index 2ff2cdc189..3e29222200 100644 --- a/src/qml/qml/qqmlmetatype.cpp +++ b/src/qml/qml/qqmlmetatype.cpp @@ -209,7 +209,7 @@ public: int listId; int revision; mutable bool containsRevisionedAttributes; - mutable QQmlType *superType; + mutable QQmlType superType; const QMetaObject *baseMetaObject; int index; @@ -281,7 +281,7 @@ QHash QQmlTypePrivate::attachedPropertyIds; QQmlTypePrivate::QQmlTypePrivate(QQmlType::RegistrationType type) : refCount(1), regType(type), iid(0), typeId(0), listId(0), revision(0), - containsRevisionedAttributes(false), superType(0), baseMetaObject(0), + containsRevisionedAttributes(false), baseMetaObject(0), index(-1), isSetup(false), isEnumSetup(false), haveSuperType(false) { switch (type) { @@ -476,6 +476,27 @@ QQmlType::~QQmlType() delete d; } +QQmlType::QQmlType(QQmlType *otherPointer) + : d(0) +{ + if (otherPointer) { + d = otherPointer->d; + if (d) + d->refCount.ref(); + } +} + +QQmlType &QQmlType::operator =(QQmlType *otherPointer) { + if (otherPointer && otherPointer->d != d) { + if (d && !d->refCount.deref()) + delete d; + d = otherPointer->d; + if (d) + d->refCount.ref(); + } + return *this; +} + QHashedString QQmlType::module() const { if (!d) @@ -514,13 +535,13 @@ bool QQmlType::availableInVersion(const QHashedStringRef &module, int vmajor, in } // returns the nearest _registered_ super class -QQmlType *QQmlType::superType() const +QQmlType QQmlType::superType() const { if (!d) return 0; if (!d->haveSuperType && d->baseMetaObject) { const QMetaObject *mo = d->baseMetaObject->superClass(); - while (mo && !d->superType) { + while (mo && !d->superType.isValid()) { d->superType = QQmlMetaType::qmlType(mo, d->module, d->version_maj, d->version_min); mo = mo->superClass(); } @@ -530,7 +551,7 @@ QQmlType *QQmlType::superType() const return d->superType; } -QQmlType *QQmlType::resolveCompositeBaseType(QQmlEnginePrivate *engine) const +QQmlType QQmlType::resolveCompositeBaseType(QQmlEnginePrivate *engine) const { Q_ASSERT(isComposite()); if (!engine || !d) @@ -549,10 +570,8 @@ int QQmlType::resolveCompositeEnumValue(QQmlEnginePrivate *engine, const QString if (!d) return -1; *ok = false; - QQmlType *type = resolveCompositeBaseType(engine); - if (!type) - return -1; - return type->enumValue(engine, name, ok); + QQmlType type = resolveCompositeBaseType(engine); + return type.enumValue(engine, name, ok); } static void clone(QMetaObjectBuilder &builder, const QMetaObject *mo, @@ -942,10 +961,10 @@ QQmlAttachedPropertiesFunc QQmlType::attachedPropertiesFunction(QQmlEnginePrivat if (d->regType == CppType) return d->extraData.cd->attachedPropertiesFunc; - QQmlType *base = 0; + QQmlType base; if (d->regType == CompositeType) base = resolveCompositeBaseType(engine); - return base ? base->attachedPropertiesFunction(engine) : 0; + return base.attachedPropertiesFunction(engine); } const QMetaObject *QQmlType::attachedPropertiesType(QQmlEnginePrivate *engine) const @@ -955,10 +974,10 @@ const QMetaObject *QQmlType::attachedPropertiesType(QQmlEnginePrivate *engine) c if (d->regType == CppType) return d->extraData.cd->attachedPropertiesType; - QQmlType *base = 0; + QQmlType base; if (d->regType == CompositeType) base = resolveCompositeBaseType(engine); - return base ? base->attachedPropertiesType(engine) : 0; + return base.attachedPropertiesType(engine); } /* @@ -973,10 +992,10 @@ int QQmlType::attachedPropertiesId(QQmlEnginePrivate *engine) const if (d->regType == CppType) return d->extraData.cd->attachedPropertiesId; - QQmlType *base = 0; + QQmlType base; if (d->regType == CompositeType) base = resolveCompositeBaseType(engine); - return base ? base->attachedPropertiesId(engine) : 0; + return base.attachedPropertiesId(engine); } int QQmlType::parserStatusCast() const @@ -1137,46 +1156,32 @@ void QQmlTypeModulePrivate::add(QQmlType *type) list.append(type); } -QQmlType *QQmlTypeModule::type(const QHashedStringRef &name, int minor) const +QQmlType QQmlTypeModule::type(const QHashedStringRef &name, int minor) const { QMutexLocker lock(metaTypeDataLock()); QList *types = d->typeHash.value(name); - if (!types) return 0; - - for (int ii = 0; ii < types->count(); ++ii) - if (types->at(ii)->minorVersion() <= minor) - return types->at(ii); + if (types) { + for (int ii = 0; ii < types->count(); ++ii) + if (types->at(ii)->minorVersion() <= minor) + return types->at(ii); + } - return 0; + return QQmlType(); } -QQmlType *QQmlTypeModule::type(const QV4::String *name, int minor) const +QQmlType QQmlTypeModule::type(const QV4::String *name, int minor) const { QMutexLocker lock(metaTypeDataLock()); QList *types = d->typeHash.value(name); - if (!types) return 0; - - for (int ii = 0; ii < types->count(); ++ii) - if (types->at(ii)->minorVersion() <= minor) - return types->at(ii); - - return 0; -} - -QList QQmlTypeModule::singletonTypes(int minor) const -{ - QMutexLocker lock(metaTypeDataLock()); - - QList retn; - for (int ii = 0; ii < d->types.count(); ++ii) { - QQmlType *curr = d->types.at(ii); - if (curr->isSingleton() && curr->minorVersion() <= minor) - retn.append(curr); + if (types) { + for (int ii = 0; ii < types->count(); ++ii) + if (types->at(ii)->minorVersion() <= minor) + return types->at(ii); } - return retn; + return QQmlType(); } QQmlTypeModuleVersion::QQmlTypeModuleVersion() @@ -1213,16 +1218,18 @@ int QQmlTypeModuleVersion::minorVersion() const return m_minor; } -QQmlType *QQmlTypeModuleVersion::type(const QHashedStringRef &name) const +QQmlType QQmlTypeModuleVersion::type(const QHashedStringRef &name) const { - if (m_module) return m_module->type(name, m_minor); - else return 0; + if (!m_module) + return QQmlType(); + return m_module->type(name, m_minor); } -QQmlType *QQmlTypeModuleVersion::type(const QV4::String *name) const +QQmlType QQmlTypeModuleVersion::type(const QV4::String *name) const { - if (m_module) return m_module->type(name, m_minor); - else return 0; + if (!m_module) + return QQmlType(); + return m_module->type(name, m_minor); } void qmlClearTypeRegistrations() // Declared in qqml.h @@ -1369,7 +1376,7 @@ QQmlTypeModule *getTypeModule(const QHashedString &uri, int majorVersion, QQmlMe } // NOTE: caller must hold a QMutexLocker on "data" -void addTypeToData(QQmlType* type, QQmlMetaTypeData *data) +void addTypeToData(QQmlType *type, QQmlMetaTypeData *data) { if (!type->elementName().isEmpty()) data->nameToType.insertMulti(type->elementName(), type); @@ -1855,7 +1862,7 @@ QQmlMetaType::StringConverter QQmlMetaType::customStringConverter(int type) Returns the type (if any) of URI-qualified named \a qualifiedName and version specified by \a version_major and \a version_minor. */ -QQmlType *QQmlMetaType::qmlType(const QString &qualifiedName, int version_major, int version_minor) +QQmlType QQmlMetaType::qmlType(const QString &qualifiedName, int version_major, int version_minor) { int slash = qualifiedName.indexOf(QLatin1Char('/')); if (slash <= 0) @@ -1871,7 +1878,7 @@ QQmlType *QQmlMetaType::qmlType(const QString &qualifiedName, int version_major, Returns the type (if any) of \a name in \a module and version specified by \a version_major and \a version_minor. */ -QQmlType *QQmlMetaType::qmlType(const QHashedStringRef &name, const QHashedStringRef &module, int version_major, int version_minor) +QQmlType QQmlMetaType::qmlType(const QHashedStringRef &name, const QHashedStringRef &module, int version_major, int version_minor) { Q_ASSERT(version_major >= 0 && version_minor >= 0); QMutexLocker lock(metaTypeDataLock()); @@ -1881,18 +1888,18 @@ QQmlType *QQmlMetaType::qmlType(const QHashedStringRef &name, const QHashedStrin while (it != data->nameToType.cend() && it.key() == name) { // XXX version_major<0 just a kludge for QQmlPropertyPrivate::initProperty if (version_major < 0 || module.isEmpty() || (*it)->availableInVersion(module, version_major,version_minor)) - return (*it); + return *(*it); ++it; } - return 0; + return QQmlType(); } /*! Returns the type (if any) that corresponds to the \a metaObject. Returns null if no type is registered. */ -QQmlType *QQmlMetaType::qmlType(const QMetaObject *metaObject) +QQmlType QQmlMetaType::qmlType(const QMetaObject *metaObject) { QMutexLocker lock(metaTypeDataLock()); QQmlMetaTypeData *data = metaTypeData(); @@ -1905,7 +1912,7 @@ QQmlType *QQmlMetaType::qmlType(const QMetaObject *metaObject) by \a version_major and \a version_minor in module specified by \a uri. Returns null if no type is registered. */ -QQmlType *QQmlMetaType::qmlType(const QMetaObject *metaObject, const QHashedStringRef &module, int version_major, int version_minor) +QQmlType QQmlMetaType::qmlType(const QMetaObject *metaObject, const QHashedStringRef &module, int version_major, int version_minor) { Q_ASSERT(version_major >= 0 && version_minor >= 0); QMutexLocker lock(metaTypeDataLock()); @@ -1926,7 +1933,7 @@ QQmlType *QQmlMetaType::qmlType(const QMetaObject *metaObject, const QHashedStri Returns the type (if any) that corresponds to the QVariant::Type \a userType. Returns null if no type is registered. */ -QQmlType *QQmlMetaType::qmlType(int userType) +QQmlType QQmlMetaType::qmlType(int userType) { QMutexLocker lock(metaTypeDataLock()); QQmlMetaTypeData *data = metaTypeData(); @@ -1944,7 +1951,7 @@ QQmlType *QQmlMetaType::qmlType(int userType) Returns null if no such type is registered. */ -QQmlType *QQmlMetaType::qmlType(const QUrl &url, bool includeNonFileImports /* = false */) +QQmlType QQmlMetaType::qmlType(const QUrl &url, bool includeNonFileImports /* = false */) { QMutexLocker lock(metaTypeDataLock()); QQmlMetaTypeData *data = metaTypeData(); @@ -1954,9 +1961,9 @@ QQmlType *QQmlMetaType::qmlType(const QUrl &url, bool includeNonFileImports /* = type = data->urlToNonFileImportType.value(url); if (type && type->sourceUrl() == url) - return type; + return *type; else - return 0; + return QQmlType(); } /*! @@ -1964,7 +1971,7 @@ QQmlType *QQmlMetaType::qmlType(const QUrl &url, bool includeNonFileImports /* = This is for use when you just got the index back from a qmlRegister function. Returns null if the index is out of bounds. */ -QQmlType *QQmlMetaType::qmlTypeFromIndex(int idx) +QQmlType QQmlMetaType::qmlTypeFromIndex(int idx) { QMutexLocker lock(metaTypeDataLock()); QQmlMetaTypeData *data = metaTypeData(); @@ -1996,7 +2003,7 @@ QList QQmlMetaType::qmlTypeNames() /*! Returns the list of registered QML types. */ -QList QQmlMetaType::qmlTypes() +QList QQmlMetaType::qmlTypes() { QMutexLocker lock(metaTypeDataLock()); QQmlMetaTypeData *data = metaTypeData(); @@ -2007,7 +2014,7 @@ QList QQmlMetaType::qmlTypes() /*! Returns the list of all registered types. */ -QList QQmlMetaType::qmlAllTypes() +QList QQmlMetaType::qmlAllTypes() { QMutexLocker lock(metaTypeDataLock()); QQmlMetaTypeData *data = metaTypeData(); @@ -2018,15 +2025,15 @@ QList QQmlMetaType::qmlAllTypes() /*! Returns the list of registered QML singleton types. */ -QList QQmlMetaType::qmlSingletonTypes() +QList QQmlMetaType::qmlSingletonTypes() { QMutexLocker lock(metaTypeDataLock()); QQmlMetaTypeData *data = metaTypeData(); - QList retn; + QList retn; for (const auto type : qAsConst(data->nameToType)) { if (type->isSingleton()) - retn.append(type); + retn.append(*type); } return retn; } @@ -2053,9 +2060,9 @@ QString QQmlMetaType::prettyTypeName(const QObject *object) if (!object) return typeName; - const QQmlType *type = QQmlMetaType::qmlType(object->metaObject()); - if (type) { - typeName = type->qmlTypeName(); + QQmlType type = QQmlMetaType::qmlType(object->metaObject()); + if (type.isValid()) { + typeName = type.qmlTypeName(); const int lastSlash = typeName.lastIndexOf(QLatin1Char('/')); if (lastSlash != -1) typeName = typeName.mid(lastSlash + 1); @@ -2071,8 +2078,8 @@ QString QQmlMetaType::prettyTypeName(const QObject *object) if (marker != -1) { typeName = typeName.leftRef(marker) + QLatin1Char('*'); type = QQmlMetaType::qmlType(QMetaType::type(typeName.toLatin1())); - if (type) { - QString qmlTypeName = type->qmlTypeName(); + if (type.isValid()) { + QString qmlTypeName = type.qmlTypeName(); const int lastSlash = qmlTypeName.lastIndexOf(QLatin1Char('/')); if (lastSlash != -1) qmlTypeName = qmlTypeName.mid(lastSlash + 1); diff --git a/src/qml/qml/qqmlmetatype_p.h b/src/qml/qml/qqmlmetatype_p.h index 08198340f3..d17172a917 100644 --- a/src/qml/qml/qqmlmetatype_p.h +++ b/src/qml/qml/qqmlmetatype_p.h @@ -77,17 +77,17 @@ class Q_QML_PRIVATE_EXPORT QQmlMetaType { public: static QList qmlTypeNames(); - static QList qmlTypes(); - static QList qmlSingletonTypes(); - static QList qmlAllTypes(); - - static QQmlType *qmlType(const QString &qualifiedName, int, int); - static QQmlType *qmlType(const QHashedStringRef &name, const QHashedStringRef &module, int, int); - static QQmlType *qmlType(const QMetaObject *); - static QQmlType *qmlType(const QMetaObject *metaObject, const QHashedStringRef &module, int version_major, int version_minor); - static QQmlType *qmlType(int); - static QQmlType *qmlType(const QUrl &url, bool includeNonFileImports = false); - static QQmlType *qmlTypeFromIndex(int); + static QList qmlTypes(); + static QList qmlSingletonTypes(); + static QList qmlAllTypes(); + + static QQmlType qmlType(const QString &qualifiedName, int, int); + static QQmlType qmlType(const QHashedStringRef &name, const QHashedStringRef &module, int, int); + static QQmlType qmlType(const QMetaObject *); + static QQmlType qmlType(const QMetaObject *metaObject, const QHashedStringRef &module, int version_major, int version_minor); + static QQmlType qmlType(int); + static QQmlType qmlType(const QUrl &url, bool includeNonFileImports = false); + static QQmlType qmlTypeFromIndex(int); static QMetaProperty defaultProperty(const QMetaObject *); static QMetaProperty defaultProperty(QObject *); @@ -144,7 +144,16 @@ public: explicit QQmlType(QQmlTypePrivate *priv); ~QQmlType(); + // ### get rid of these two again + QQmlType(QQmlType *otherPointer); + QQmlType &operator =(QQmlType *otherPointer); + + bool operator ==(const QQmlType &other) const { + return d == other.d; + } + bool isValid() const { return d != 0; } + const QQmlTypePrivate *key() const { return d; } QByteArray typeName() const; QString qmlTypeName() const; @@ -229,8 +238,8 @@ public: static void refHandle(QQmlTypePrivate *priv); static void derefHandle(QQmlTypePrivate *priv); private: - QQmlType *superType() const; - QQmlType *resolveCompositeBaseType(QQmlEnginePrivate *engine) const; + QQmlType superType() const; + QQmlType resolveCompositeBaseType(QQmlEnginePrivate *engine) const; int resolveCompositeEnumValue(QQmlEnginePrivate *engine, const QString &name, bool *ok) const; friend class QQmlTypePrivate; friend struct QQmlMetaTypeData; @@ -250,6 +259,7 @@ private: friend int registerCompositeType(const QQmlPrivate::RegisterCompositeType &); friend int registerCompositeSingletonType(const QQmlPrivate::RegisterCompositeSingletonType &); friend int registerQmlUnitCacheHook(const QQmlPrivate::RegisterQmlUnitCacheHook &); + friend uint qHash(const QQmlType &t, uint seed); friend Q_QML_EXPORT void qmlClearTypeRegistrations(); QQmlType(int, const QQmlPrivate::RegisterInterface &); QQmlType(int, const QString &, const QQmlPrivate::RegisterSingletonType &); @@ -260,6 +270,12 @@ private: QQmlTypePrivate *d; }; +Q_DECLARE_TYPEINFO(QQmlMetaType, Q_MOVABLE_TYPE); + + +inline uint qHash(const QQmlType &t, uint seed = 0) { return qHash(reinterpret_cast(t.d), seed); } + + class QQmlTypeModulePrivate; class QQmlTypeModule { @@ -270,10 +286,8 @@ public: int minimumMinorVersion() const; int maximumMinorVersion() const; - QQmlType *type(const QHashedStringRef &, int) const; - QQmlType *type(const QV4::String *, int) const; - - QList singletonTypes(int) const; + QQmlType type(const QHashedStringRef &, int) const; + QQmlType type(const QV4::String *, int) const; private: //Used by register functions and creates the QQmlTypeModule for them @@ -299,8 +313,8 @@ public: QQmlTypeModule *module() const; int minorVersion() const; - QQmlType *type(const QHashedStringRef &) const; - QQmlType *type(const QV4::String *) const; + QQmlType type(const QHashedStringRef &) const; + QQmlType type(const QV4::String *) const; private: QQmlTypeModule *m_module; diff --git a/src/qml/qml/qqmlobjectcreator.cpp b/src/qml/qml/qqmlobjectcreator.cpp index 2cbcfbbfb6..6867aaad75 100644 --- a/src/qml/qml/qqmlobjectcreator.cpp +++ b/src/qml/qml/qqmlobjectcreator.cpp @@ -613,11 +613,11 @@ void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const } } -static QQmlType *qmlTypeForObject(QObject *object) +static QQmlType qmlTypeForObject(QObject *object) { - QQmlType *type = 0; + QQmlType type; const QMetaObject *mo = object->metaObject(); - while (mo && !type) { + while (mo && !type.isValid()) { type = QQmlMetaType::qmlType(mo); mo = mo->superClass(); } @@ -654,7 +654,7 @@ void QQmlObjectCreator::setupBindings(bool applyDeferredBindings) } else if (binding) { QQmlValueTypeProxyBinding *proxy = static_cast(binding); - if (qmlTypeForObject(_bindingTarget)) { + if (qmlTypeForObject(_bindingTarget).isValid()) { quint32 bindingSkipList = 0; QQmlPropertyData *defaultProperty = _compiledObject->indexOfDefaultPropertyOrAlias != -1 ? _propertyCache->parent()->defaultProperty() : _propertyCache->defaultProperty(); @@ -712,15 +712,15 @@ bool QQmlObjectCreator::setPropertyBinding(const QQmlPropertyData *property, con Q_ASSERT(stringAt(qmlUnit->objectAt(binding->value.objectIndex)->inheritedTypeNameIndex).isEmpty()); QV4::CompiledData::ResolvedTypeReference *tr = resolvedTypes.value(binding->propertyNameIndex); Q_ASSERT(tr); - QQmlType *attachedType = tr->type; - if (!attachedType) { + QQmlType attachedType = tr->type; + if (!attachedType.isValid()) { QQmlTypeNameCache::Result res = context->imports->query(stringAt(binding->propertyNameIndex)); if (res.isValid()) attachedType = res.type; else return false; } - const int id = attachedType->attachedPropertiesId(QQmlEnginePrivate::get(engine)); + const int id = attachedType.attachedPropertiesId(QQmlEnginePrivate::get(engine)); QObject *qmlObject = qmlAttachedPropertiesObjectById(id, _qobject); if (!populateInstance(binding->value.objectIndex, qmlObject, qmlObject, /*value type property*/0)) return false; @@ -850,10 +850,10 @@ bool QQmlObjectCreator::setPropertyBinding(const QQmlPropertyData *property, con if (binding->type == QV4::CompiledData::Binding::Type_Object) { if (binding->flags & QV4::CompiledData::Binding::IsOnAssignment) { // ### determine value source and interceptor casts ahead of time. - QQmlType *type = qmlTypeForObject(createdSubObject); - Q_ASSERT(type); + QQmlType type = qmlTypeForObject(createdSubObject); + Q_ASSERT(type.isValid()); - int valueSourceCast = type->propertyValueSourceCast(); + int valueSourceCast = type.propertyValueSourceCast(); if (valueSourceCast != -1) { QQmlPropertyValueSource *vs = reinterpret_cast(reinterpret_cast(createdSubObject) + valueSourceCast); QObject *target = createdSubObject->parent(); @@ -865,7 +865,7 @@ bool QQmlObjectCreator::setPropertyBinding(const QQmlPropertyData *property, con vs->setTarget(prop); return true; } - int valueInterceptorCast = type->propertyValueInterceptorCast(); + int valueInterceptorCast = type.propertyValueInterceptorCast(); if (valueInterceptorCast != -1) { QQmlPropertyValueInterceptor *vi = reinterpret_cast(reinterpret_cast(createdSubObject) + valueInterceptorCast); QObject *target = createdSubObject->parent(); @@ -1060,13 +1060,13 @@ QObject *QQmlObjectCreator::createInstance(int index, QObject *parent, bool isCo QV4::CompiledData::ResolvedTypeReference *typeRef = resolvedTypes.value(obj->inheritedTypeNameIndex); Q_ASSERT(typeRef); installPropertyCache = !typeRef->isFullyDynamicType; - QQmlType *type = typeRef->type; - if (type) { + QQmlType type = typeRef->type; + if (type.isValid()) { Q_QML_OC_PROFILE(sharedState->profiler, profiler.update( - compilationUnit, obj, type->qmlTypeName(), context->url())); + compilationUnit, obj, type.qmlTypeName(), context->url())); void *ddataMemory = 0; - type->create(&instance, &ddataMemory, sizeof(QQmlData)); + type.create(&instance, &ddataMemory, sizeof(QQmlData)); if (!instance) { recordError(obj->location, tr("Unable to create object of type %1").arg(stringAt(obj->inheritedTypeNameIndex))); return 0; @@ -1080,11 +1080,11 @@ QObject *QQmlObjectCreator::createInstance(int index, QObject *parent, bool isCo p->declarativeData = ddata; } - const int parserStatusCast = type->parserStatusCast(); + const int parserStatusCast = type.parserStatusCast(); if (parserStatusCast != -1) parserStatus = reinterpret_cast(reinterpret_cast(instance) + parserStatusCast); - customParser = type->customParser(); + customParser = type.customParser(); if (sharedState->rootContext && sharedState->rootContext->isRootObjectInCreation) { QQmlData *ddata = QQmlData::get(instance, /*create*/true); diff --git a/src/qml/qml/qqmlproperty.cpp b/src/qml/qml/qqmlproperty.cpp index 9b5f7b0a06..21bbcadb1c 100644 --- a/src/qml/qml/qqmlproperty.cpp +++ b/src/qml/qml/qqmlproperty.cpp @@ -253,24 +253,24 @@ void QQmlPropertyPrivate::initProperty(QObject *obj, const QString &name) if (typeNameCache) { QQmlTypeNameCache::Result r = typeNameCache->query(pathName); if (r.isValid()) { - if (r.type) { + if (r.type.isValid()) { QQmlEnginePrivate *enginePrivate = QQmlEnginePrivate::get(engine); - QQmlAttachedPropertiesFunc func = r.type->attachedPropertiesFunction(enginePrivate); + QQmlAttachedPropertiesFunc func = r.type.attachedPropertiesFunction(enginePrivate); if (!func) return; // Not an attachable type - currentObject = qmlAttachedPropertiesObjectById(r.type->attachedPropertiesId(enginePrivate), currentObject); + currentObject = qmlAttachedPropertiesObjectById(r.type.attachedPropertiesId(enginePrivate), currentObject); if (!currentObject) return; // Something is broken with the attachable type } else if (r.importNamespace) { if ((ii + 1) == path.count()) return; // No type following the namespace ++ii; r = typeNameCache->query(path.at(ii), r.importNamespace); - if (!r.type) return; // Invalid type in namespace + if (!r.type.isValid()) return; // Invalid type in namespace QQmlEnginePrivate *enginePrivate = QQmlEnginePrivate::get(engine); - QQmlAttachedPropertiesFunc func = r.type->attachedPropertiesFunction(enginePrivate); + QQmlAttachedPropertiesFunc func = r.type.attachedPropertiesFunction(enginePrivate); if (!func) return; // Not an attachable type - currentObject = qmlAttachedPropertiesObjectById(r.type->attachedPropertiesId(enginePrivate), currentObject); + currentObject = qmlAttachedPropertiesObjectById(r.type.attachedPropertiesId(enginePrivate), currentObject); if (!currentObject) return; // Something is broken with the attachable type } else if (r.scriptIndex != -1) { @@ -1275,10 +1275,10 @@ bool QQmlPropertyPrivate::write(QObject *object, if (enginePriv) { listType = enginePriv->rawMetaObjectForType(enginePriv->listType(property.propType())); } else { - QQmlType *type = QQmlMetaType::qmlType(QQmlMetaType::listType(property.propType())); - if (!type) + QQmlType type = QQmlMetaType::qmlType(QQmlMetaType::listType(property.propType())); + if (!type.isValid()) return false; - listType = type->baseMetaObject(); + listType = type.baseMetaObject(); } if (listType.isNull()) return false; @@ -1393,8 +1393,9 @@ QQmlMetaObject QQmlPropertyPrivate::rawMetaObjectForType(QQmlEnginePrivate *engi return metaType.metaObject(); if (engine) return engine->rawMetaObjectForType(userType); - if (QQmlType *type = QQmlMetaType::qmlType(userType)) - return QQmlMetaObject(type->baseMetaObject()); + QQmlType type = QQmlMetaType::qmlType(userType); + if (type.isValid()) + return QQmlMetaObject(type.baseMetaObject()); return QQmlMetaObject(); } diff --git a/src/qml/qml/qqmltypeloader.cpp b/src/qml/qml/qqmltypeloader.cpp index e4293596d8..fbb04af165 100644 --- a/src/qml/qml/qqmltypeloader.cpp +++ b/src/qml/qml/qqmltypeloader.cpp @@ -2013,7 +2013,7 @@ QString QQmlTypeData::TypeReference::qualifiedName() const if (!prefix.isEmpty()) { result = prefix + QLatin1Char('.'); } - result.append(type->qmlTypeName()); + result.append(type.qmlTypeName()); return result; } @@ -2168,8 +2168,8 @@ static bool addTypeReferenceChecksumsToHash(const QListcompilationUnit(); hash->addData(unit->data->md5Checksum, sizeof(unit->data->md5Checksum)); - } else if (typeRef.type) { - const auto propertyCache = QQmlEnginePrivate::get(engine)->cache(typeRef.type->metaObject()); + } else if (typeRef.type.isValid()) { + const auto propertyCache = QQmlEnginePrivate::get(engine)->cache(typeRef.type.metaObject()); bool ok = false; hash->addData(propertyCache->checksum(&ok)); if (!ok) @@ -2233,7 +2233,7 @@ void QQmlTypeData::done() const TypeReference &type = m_compositeSingletons.at(ii); Q_ASSERT(!type.typeData || type.typeData->isCompleteOrError()); if (type.typeData && type.typeData->isError()) { - QString typeName = type.type->qmlTypeName(); + QString typeName = type.type.qmlTypeName(); QList errors = type.typeData->errors(); QQmlError error; @@ -2300,24 +2300,24 @@ void QQmlTypeData::done() } { - QQmlType *type = QQmlMetaType::qmlType(finalUrl(), true); + QQmlType type = QQmlMetaType::qmlType(finalUrl(), true); if (m_compiledData && m_compiledData->data->flags & QV4::CompiledData::Unit::IsSingleton) { - if (!type) { + if (!type.isValid()) { QQmlError error; error.setDescription(QQmlTypeLoader::tr("No matching type found, pragma Singleton files cannot be used by QQmlComponent.")); setError(error); return; - } else if (!type->isCompositeSingleton()) { + } else if (!type.isCompositeSingleton()) { QQmlError error; - error.setDescription(QQmlTypeLoader::tr("pragma Singleton used with a non composite singleton type %1").arg(type->qmlTypeName())); + error.setDescription(QQmlTypeLoader::tr("pragma Singleton used with a non composite singleton type %1").arg(type.qmlTypeName())); setError(error); return; } } else { // If the type is CompositeSingleton but there was no pragma Singleton in the // QML file, lets report an error. - if (type && type->isCompositeSingleton()) { - QString typeName = type->qmlTypeName(); + if (type.isValid() && type.isCompositeSingleton()) { + QString typeName = type.qmlTypeName(); setError(QQmlTypeLoader::tr("qmldir defines type as singleton, but no pragma Singleton found in type %1.").arg(typeName)); return; } @@ -2609,8 +2609,8 @@ void QQmlTypeData::resolveTypes() if (!resolveType(typeName, majorVersion, minorVersion, ref)) return; - if (ref.type->isCompositeSingleton()) { - ref.typeData = typeLoader()->getType(ref.type->sourceUrl()); + if (ref.type.isCompositeSingleton()) { + ref.typeData = typeLoader()->getType(ref.type.sourceUrl()); addDependency(ref.typeData); ref.prefix = csRef.prefix; @@ -2637,8 +2637,8 @@ void QQmlTypeData::resolveTypes() if (!resolveType(name, majorVersion, minorVersion, ref, unresolvedRef->location.line, unresolvedRef->location.column, reportErrors) && reportErrors) return; - if (ref.type && ref.type->isComposite()) { - ref.typeData = typeLoader()->getType(ref.type->sourceUrl()); + if (ref.type.isComposite()) { + ref.typeData = typeLoader()->getType(ref.type.sourceUrl()); addDependency(ref.typeData); } ref.majorVersion = majorVersion; @@ -2665,7 +2665,7 @@ QQmlCompileError QQmlTypeData::buildTypeResolutionCaches( // Add any Composite Singletons that were used to the import cache for (const QQmlTypeData::TypeReference &singleton: m_compositeSingletons) - (*typeNameCache)->add(singleton.type->qmlTypeName(), singleton.type->sourceUrl(), singleton.prefix); + (*typeNameCache)->add(singleton.type.qmlTypeName(), singleton.type.sourceUrl(), singleton.prefix); m_importCache.populateCache(*typeNameCache); @@ -2673,24 +2673,24 @@ QQmlCompileError QQmlTypeData::buildTypeResolutionCaches( for (auto resolvedType = m_resolvedTypes.constBegin(), end = m_resolvedTypes.constEnd(); resolvedType != end; ++resolvedType) { QScopedPointer ref(new QV4::CompiledData::ResolvedTypeReference); - QQmlType *qmlType = resolvedType->type; + QQmlType qmlType = resolvedType->type; if (resolvedType->typeData) { - if (resolvedType->needsCreation && qmlType->isCompositeSingleton()) { - return QQmlCompileError(resolvedType->location, tr("Composite Singleton Type %1 is not creatable.").arg(qmlType->qmlTypeName())); + if (resolvedType->needsCreation && qmlType.isCompositeSingleton()) { + return QQmlCompileError(resolvedType->location, tr("Composite Singleton Type %1 is not creatable.").arg(qmlType.qmlTypeName())); } ref->compilationUnit = resolvedType->typeData->compilationUnit(); - } else if (qmlType) { + } else if (qmlType.isValid()) { ref->type = qmlType; - Q_ASSERT(ref->type); + Q_ASSERT(ref->type.isValid()); - if (resolvedType->needsCreation && !ref->type->isCreatable()) { - QString reason = ref->type->noCreationReason(); + if (resolvedType->needsCreation && !ref->type.isCreatable()) { + QString reason = ref->type.noCreationReason(); if (reason.isEmpty()) reason = tr("Element is not creatable."); return QQmlCompileError(resolvedType->location, reason); } - if (ref->type->containsRevisionedAttributes()) { + if (ref->type.containsRevisionedAttributes()) { ref->typePropertyCache = engine->cache(ref->type, resolvedType->minorVersion); } diff --git a/src/qml/qml/qqmltypeloader_p.h b/src/qml/qml/qqmltypeloader_p.h index f367fa6f58..762fcdac65 100644 --- a/src/qml/qml/qqmltypeloader_p.h +++ b/src/qml/qml/qqmltypeloader_p.h @@ -393,10 +393,10 @@ class Q_AUTOTEST_EXPORT QQmlTypeData : public QQmlTypeLoader::Blob public: struct TypeReference { - TypeReference() : type(0), majorVersion(0), minorVersion(0), typeData(0), needsCreation(true) {} + TypeReference() : majorVersion(0), minorVersion(0), typeData(0), needsCreation(true) {} QV4::CompiledData::Location location; - QQmlType *type; + QQmlType type; int majorVersion; int minorVersion; QQmlTypeData *typeData; diff --git a/src/qml/qml/qqmltypenamecache.cpp b/src/qml/qml/qqmltypenamecache.cpp index c8e2b92c29..a8f55d2e48 100644 --- a/src/qml/qml/qqmltypenamecache.cpp +++ b/src/qml/qml/qqmltypenamecache.cpp @@ -100,7 +100,7 @@ QQmlTypeNameCache::Result QQmlTypeNameCache::query(const QHashedStringRef &name) // Look up anonymous types from the imports of this document QQmlImportNamespace *typeNamespace = 0; QList errors; - QQmlType *t = 0; + QQmlType t; bool typeFound = m_imports.resolveType(name, &t, 0, 0, &typeNamespace, &errors); if (typeFound) { return Result(t); @@ -130,7 +130,7 @@ QQmlTypeNameCache::Result QQmlTypeNameCache::query(const QHashedStringRef &name, QString qualifiedTypeName = i->m_qualifier + QLatin1Char('.') + name.toString(); QQmlImportNamespace *typeNamespace = 0; QList errors; - QQmlType *t = 0; + QQmlType t; bool typeFound = m_imports.resolveType(qualifiedTypeName, &t, 0, 0, &typeNamespace, &errors); if (typeFound) { return Result(t); @@ -155,7 +155,7 @@ QQmlTypeNameCache::Result QQmlTypeNameCache::query(const QV4::String *name) cons QString typeName = name->toQStringNoThrow(); QQmlImportNamespace *typeNamespace = 0; QList errors; - QQmlType *t = 0; + QQmlType t; bool typeFound = m_imports.resolveType(typeName, &t, 0, 0, &typeNamespace, &errors); if (typeFound) { return Result(t); @@ -191,7 +191,7 @@ QQmlTypeNameCache::Result QQmlTypeNameCache::query(const QV4::String *name, cons QString qualifiedTypeName = i->m_qualifier + QLatin1Char('.') + name->toQStringNoThrow(); QQmlImportNamespace *typeNamespace = 0; QList errors; - QQmlType *t = 0; + QQmlType t; bool typeFound = m_imports.resolveType(qualifiedTypeName, &t, 0, 0, &typeNamespace, &errors); if (typeFound) { return Result(t); diff --git a/src/qml/qml/qqmltypenamecache_p.h b/src/qml/qml/qqmltypenamecache_p.h index 7cdcbe91b6..0705166ec2 100644 --- a/src/qml/qml/qqmltypenamecache_p.h +++ b/src/qml/qml/qqmltypenamecache_p.h @@ -78,13 +78,13 @@ public: struct Result { inline Result(); inline Result(const void *importNamespace); - inline Result(QQmlType *type); + inline Result(const QQmlType &type); inline Result(int scriptIndex); inline Result(const Result &); inline bool isValid() const; - QQmlType *type; + QQmlType type; const void *importNamespace; int scriptIndex; }; @@ -132,9 +132,8 @@ private: { QUrl *url = urls.value(key); if (url) { - QQmlType *type = QQmlMetaType::qmlType(*url); - if (type) - return Result(type); + QQmlType type = QQmlMetaType::qmlType(*url); + return Result(type); } return Result(); @@ -145,7 +144,8 @@ private: { QVector::const_iterator end = modules.constEnd(); for (QVector::const_iterator it = modules.constBegin(); it != end; ++it) { - if (QQmlType *type = it->type(key)) + QQmlType type = it->type(key); + if (type.isValid()) return Result(type); } @@ -160,22 +160,22 @@ private: }; QQmlTypeNameCache::Result::Result() -: type(0), importNamespace(0), scriptIndex(-1) +: importNamespace(0), scriptIndex(-1) { } QQmlTypeNameCache::Result::Result(const void *importNamespace) -: type(0), importNamespace(importNamespace), scriptIndex(-1) +: importNamespace(importNamespace), scriptIndex(-1) { } -QQmlTypeNameCache::Result::Result(QQmlType *type) +QQmlTypeNameCache::Result::Result(const QQmlType &type) : type(type), importNamespace(0), scriptIndex(-1) { } QQmlTypeNameCache::Result::Result(int scriptIndex) -: type(0), importNamespace(0), scriptIndex(scriptIndex) +: importNamespace(0), scriptIndex(scriptIndex) { } @@ -186,7 +186,7 @@ QQmlTypeNameCache::Result::Result(const Result &o) bool QQmlTypeNameCache::Result::isValid() const { - return type || importNamespace || scriptIndex != -1; + return type.isValid() || importNamespace || scriptIndex != -1; } QQmlTypeNameCache::Import::Import() diff --git a/src/qml/qml/qqmltypewrapper.cpp b/src/qml/qml/qqmltypewrapper.cpp index 0656bd4c62..6fab7697f8 100644 --- a/src/qml/qml/qqmltypewrapper.cpp +++ b/src/qml/qml/qqmltypewrapper.cpp @@ -247,8 +247,8 @@ ReturnedValue QmlTypeWrapper::get(const Managed *m, String *name, bool *hasPrope QQmlTypeNameCache::Result r = w->d()->typeNamespace->query(name, w->d()->importNamespace); if (r.isValid()) { - if (r.type) { - return create(scope.engine, object, *r.type, w->d()->mode); + if (r.type.isValid()) { + return create(scope.engine, object, r.type, w->d()->mode); } else if (r.scriptIndex != -1) { QV4::ScopedObject scripts(scope, context->importedScripts.valueRef()); return scripts->getIndexed(r.scriptIndex); @@ -301,7 +301,7 @@ void QmlTypeWrapper::put(Managed *m, String *name, const Value &value) QObject *ao = qmlAttachedPropertiesObjectById(type.attachedPropertiesId(QQmlEnginePrivate::get(e)), object); if (ao) QV4::QObjectWrapper::setQmlProperty(v4, context, ao, name, QV4::QObjectWrapper::IgnoreRevision, value); - } else if (type.isValid() && type.isSingleton()) { + } else if (type.isSingleton()) { QQmlEngine *e = scope.engine->qmlEngine(); QQmlType::SingletonInstanceInfo *siinfo = type.singletonInstanceInfo(); siinfo->init(e); -- cgit v1.2.3 From db1034d093d76b4b6e66fcdd178800e0cf9d1005 Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Fri, 23 Jun 2017 12:10:23 +0200 Subject: Move the engine pointer from the property cache to the VME meta object This is where it belongs, and it makes the PropertyCache independent of the engine used. Task-number: QTBUG-61536 Change-Id: I21c2674ee3e2895abd2418764d140b154b47b868 Reviewed-by: Simon Hausmann --- src/qml/qml/qqmlobjectcreator.cpp | 2 +- src/qml/qml/qqmlopenmetaobject.cpp | 2 +- src/qml/qml/qqmlpropertycache.cpp | 42 +++++++--------------- src/qml/qml/qqmlpropertycache_p.h | 18 +++------- src/qml/qml/qqmlvmemetaobject.cpp | 71 +++++++++++++++++++------------------- src/qml/qml/qqmlvmemetaobject_p.h | 3 +- 6 files changed, 56 insertions(+), 82 deletions(-) (limited to 'src/qml/qml') diff --git a/src/qml/qml/qqmlobjectcreator.cpp b/src/qml/qml/qqmlobjectcreator.cpp index 6867aaad75..45f7c5333a 100644 --- a/src/qml/qml/qqmlobjectcreator.cpp +++ b/src/qml/qml/qqmlobjectcreator.cpp @@ -1325,7 +1325,7 @@ bool QQmlObjectCreator::populateInstance(int index, QObject *instance, QObject * if (propertyCaches->needsVMEMetaObject(_compiledObjectIndex)) { Q_ASSERT(!cache.isNull()); // install on _object - vmeMetaObject = new QQmlVMEMetaObject(_qobject, cache, compilationUnit, _compiledObjectIndex); + vmeMetaObject = new QQmlVMEMetaObject(v4, _qobject, cache, compilationUnit, _compiledObjectIndex); if (_ddata->propertyCache) _ddata->propertyCache->release(); _ddata->propertyCache = cache; diff --git a/src/qml/qml/qqmlopenmetaobject.cpp b/src/qml/qml/qqmlopenmetaobject.cpp index 49f02476a2..fc85030b3d 100644 --- a/src/qml/qml/qqmlopenmetaobject.cpp +++ b/src/qml/qml/qqmlopenmetaobject.cpp @@ -376,7 +376,7 @@ void QQmlOpenMetaObject::setCached(bool c) QQmlData *qmldata = QQmlData::get(d->object, true); if (d->cacheProperties) { if (!d->type->d->cache) - d->type->d->cache = new QQmlPropertyCache(QV8Engine::getV4(d->type->d->engine), this); + d->type->d->cache = new QQmlPropertyCache(this); qmldata->propertyCache = d->type->d->cache; d->type->d->cache->addref(); } else { diff --git a/src/qml/qml/qqmlpropertycache.cpp b/src/qml/qml/qqmlpropertycache.cpp index d18159841c..9a495e6fa3 100644 --- a/src/qml/qml/qqmlpropertycache.cpp +++ b/src/qml/qml/qqmlpropertycache.cpp @@ -99,7 +99,7 @@ static QQmlPropertyData::Flags fastFlagsForProperty(const QMetaProperty &p) // Flags that do depend on the property's QMetaProperty::userType() and thus are slow to // load -static void flagsForPropertyType(int propType, QQmlEngine *engine, QQmlPropertyData::Flags &flags) +static void flagsForPropertyType(int propType, QQmlPropertyData::Flags &flags) { Q_ASSERT(propType != -1); @@ -116,9 +116,7 @@ static void flagsForPropertyType(int propType, QQmlEngine *engine, QQmlPropertyD } else if (propType == qMetaTypeId()) { flags.type = QQmlPropertyData::Flags::V4HandleType; } else { - QQmlMetaType::TypeCategory cat = - engine ? QQmlEnginePrivate::get(engine)->typeCategory(propType) - : QQmlMetaType::typeCategory(propType); + QQmlMetaType::TypeCategory cat = QQmlMetaType::typeCategory(propType); if (cat == QQmlMetaType::Object || QMetaType::typeFlags(propType) & QMetaType::PointerToQObject) flags.type = QQmlPropertyData::Flags::QObjectDerivedType; @@ -136,10 +134,10 @@ static int metaObjectSignalCount(const QMetaObject *metaObject) } QQmlPropertyData::Flags -QQmlPropertyData::flagsForProperty(const QMetaProperty &p, QQmlEngine *engine) +QQmlPropertyData::flagsForProperty(const QMetaProperty &p) { auto flags = fastFlagsForProperty(p); - flagsForPropertyType(p.userType(), engine, flags); + flagsForPropertyType(p.userType(), flags); return flags; } @@ -166,13 +164,13 @@ void QQmlPropertyData::lazyLoad(const QMetaProperty &p) } } -void QQmlPropertyData::load(const QMetaProperty &p, QQmlEngine *engine) +void QQmlPropertyData::load(const QMetaProperty &p) { setPropType(p.userType()); setCoreIndex(p.propertyIndex()); setNotifyIndex(QMetaObjectPrivate::signalIndex(p.notifySignal())); setFlags(fastFlagsForProperty(p)); - flagsForPropertyType(propType(), engine, _flags); + flagsForPropertyType(propType(), _flags); Q_ASSERT(p.revision() <= Q_INT16_MAX); setRevision(p.revision()); } @@ -244,19 +242,18 @@ void QQmlPropertyData::lazyLoad(const QMetaMethod &m) /*! Creates a new empty QQmlPropertyCache. */ -QQmlPropertyCache::QQmlPropertyCache(QV4::ExecutionEngine *e) - : engine(e), _parent(0), propertyIndexCacheStart(0), methodIndexCacheStart(0), +QQmlPropertyCache::QQmlPropertyCache() + : _parent(0), propertyIndexCacheStart(0), methodIndexCacheStart(0), signalHandlerIndexCacheStart(0), _hasPropertyOverrides(false), _ownMetaObject(false), _metaObject(0), argumentsCache(0), _jsFactoryMethodIndex(-1) { - Q_ASSERT(engine); } /*! Creates a new QQmlPropertyCache of \a metaObject. */ -QQmlPropertyCache::QQmlPropertyCache(QV4::ExecutionEngine *e, const QMetaObject *metaObject) - : QQmlPropertyCache(e) +QQmlPropertyCache::QQmlPropertyCache(const QMetaObject *metaObject) + : QQmlPropertyCache() { Q_ASSERT(metaObject); @@ -265,8 +262,6 @@ QQmlPropertyCache::QQmlPropertyCache(QV4::ExecutionEngine *e, const QMetaObject QQmlPropertyCache::~QQmlPropertyCache() { - clear(); - QQmlPropertyCacheMethodArguments *args = argumentsCache; while (args) { QQmlPropertyCacheMethodArguments *next = args->next; @@ -284,24 +279,11 @@ QQmlPropertyCache::~QQmlPropertyCache() if (_ownMetaObject) free(const_cast(_metaObject)); _metaObject = 0; _parent = 0; - engine = 0; -} - -void QQmlPropertyCache::destroy() -{ - delete this; -} - -// This is inherited from QQmlCleanup, so it should only clear the things -// that are tied to the specific QQmlEngine. -void QQmlPropertyCache::clear() -{ - engine = 0; } QQmlPropertyCache *QQmlPropertyCache::copy(int reserve) { - QQmlPropertyCache *cache = new QQmlPropertyCache(engine); + QQmlPropertyCache *cache = new QQmlPropertyCache(); cache->_parent = this; cache->_parent->addref(); cache->propertyIndexCacheStart = propertyIndexCache.count() + propertyIndexCacheStart; @@ -711,7 +693,7 @@ void QQmlPropertyCache::resolve(QQmlPropertyData *data) const data->setPropType(registerResult == -1 ? QMetaType::UnknownType : registerResult); } } - flagsForPropertyType(data->propType(), engine->qmlEngine(), data->_flags); + flagsForPropertyType(data->propType(), data->_flags); } } diff --git a/src/qml/qml/qqmlpropertycache_p.h b/src/qml/qml/qqmlpropertycache_p.h index 64be1cb206..6444d8800a 100644 --- a/src/qml/qml/qqmlpropertycache_p.h +++ b/src/qml/qml/qqmlpropertycache_p.h @@ -288,8 +288,8 @@ public: inline bool operator==(const QQmlPropertyRawData &); - static Flags flagsForProperty(const QMetaProperty &, QQmlEngine *engine = 0); - void load(const QMetaProperty &, QQmlEngine *engine = 0); + static Flags flagsForProperty(const QMetaProperty &); + void load(const QMetaProperty &); void load(const QMetaMethod &); QString name(QObject *) const; QString name(const QMetaObject *) const; @@ -350,11 +350,11 @@ private: }; class QQmlPropertyCacheMethodArguments; -class Q_QML_PRIVATE_EXPORT QQmlPropertyCache : public QQmlRefCount, public QQmlCleanup +class Q_QML_PRIVATE_EXPORT QQmlPropertyCache : public QQmlRefCount { public: - QQmlPropertyCache(QV4::ExecutionEngine *); - QQmlPropertyCache(QV4::ExecutionEngine *, const QMetaObject *); + QQmlPropertyCache(); + QQmlPropertyCache(const QMetaObject *); virtual ~QQmlPropertyCache(); void update(const QMetaObject *); @@ -445,11 +445,6 @@ public: static bool addToHash(QCryptographicHash &hash, const QMetaObject &mo); QByteArray checksum(bool *ok); - -protected: - void destroy() override; - void clear() override; - private: friend class QQmlEnginePrivate; friend class QQmlCompiler; @@ -493,9 +488,6 @@ private: _hasPropertyOverrides |= isOverride; } -public: - QV4::ExecutionEngine *engine; - private: QQmlPropertyCache *_parent; int propertyIndexCacheStart; diff --git a/src/qml/qml/qqmlvmemetaobject.cpp b/src/qml/qml/qqmlvmemetaobject.cpp index 490a4e19ab..1638b5d272 100644 --- a/src/qml/qml/qqmlvmemetaobject.cpp +++ b/src/qml/qml/qqmlvmemetaobject.cpp @@ -311,24 +311,25 @@ QAbstractDynamicMetaObject *QQmlInterceptorMetaObject::toDynamicMetaObject(QObje return this; } -QQmlVMEMetaObject::QQmlVMEMetaObject(QObject *obj, +QQmlVMEMetaObject::QQmlVMEMetaObject(QV4::ExecutionEngine *engine, + QObject *obj, QQmlPropertyCache *cache, QV4::CompiledData::CompilationUnit *qmlCompilationUnit, int qmlObjectId) : QQmlInterceptorMetaObject(obj, cache), + engine(engine), ctxt(QQmlData::get(obj, true)->outerContext), aliasEndpoints(0), compilationUnit(qmlCompilationUnit), compiledObject(0) { + Q_ASSERT(engine); QQmlData::get(obj)->hasVMEMetaObject = true; if (compilationUnit && qmlObjectId >= 0) { compiledObject = compilationUnit->data->objectAt(qmlObjectId); if (compiledObject->nProperties || compiledObject->nFunctions) { - Q_ASSERT(cache && cache->engine); - QV4::ExecutionEngine *v4 = cache->engine; uint size = compiledObject->nProperties + compiledObject->nFunctions; if (size) { - QV4::Heap::MemberData *data = QV4::MemberData::allocate(v4, size); - propertyAndMethodStorage.set(v4, data); + QV4::Heap::MemberData *data = QV4::MemberData::allocate(engine, size); + propertyAndMethodStorage.set(engine, data); std::fill(data->data, data->data + data->size, QV4::Encode::undefined()); } @@ -385,56 +386,56 @@ void QQmlVMEMetaObject::writeProperty(int id, const QString& v) { QV4::MemberData *md = propertyAndMethodStorageAsMemberData(); if (md) - *(md->data() + id) = cache->engine->newString(v); + *(md->data() + id) = engine->newString(v); } void QQmlVMEMetaObject::writeProperty(int id, const QUrl& v) { QV4::MemberData *md = propertyAndMethodStorageAsMemberData(); if (md) - *(md->data() + id) = cache->engine->newVariantObject(QVariant::fromValue(v)); + *(md->data() + id) = engine->newVariantObject(QVariant::fromValue(v)); } void QQmlVMEMetaObject::writeProperty(int id, const QDate& v) { QV4::MemberData *md = propertyAndMethodStorageAsMemberData(); if (md) - *(md->data() + id) = cache->engine->newVariantObject(QVariant::fromValue(v)); + *(md->data() + id) = engine->newVariantObject(QVariant::fromValue(v)); } void QQmlVMEMetaObject::writeProperty(int id, const QDateTime& v) { QV4::MemberData *md = propertyAndMethodStorageAsMemberData(); if (md) - *(md->data() + id) = cache->engine->newVariantObject(QVariant::fromValue(v)); + *(md->data() + id) = engine->newVariantObject(QVariant::fromValue(v)); } void QQmlVMEMetaObject::writeProperty(int id, const QPointF& v) { QV4::MemberData *md = propertyAndMethodStorageAsMemberData(); if (md) - *(md->data() + id) = cache->engine->newVariantObject(QVariant::fromValue(v)); + *(md->data() + id) = engine->newVariantObject(QVariant::fromValue(v)); } void QQmlVMEMetaObject::writeProperty(int id, const QSizeF& v) { QV4::MemberData *md = propertyAndMethodStorageAsMemberData(); if (md) - *(md->data() + id) = cache->engine->newVariantObject(QVariant::fromValue(v)); + *(md->data() + id) = engine->newVariantObject(QVariant::fromValue(v)); } void QQmlVMEMetaObject::writeProperty(int id, const QRectF& v) { QV4::MemberData *md = propertyAndMethodStorageAsMemberData(); if (md) - *(md->data() + id) = cache->engine->newVariantObject(QVariant::fromValue(v)); + *(md->data() + id) = engine->newVariantObject(QVariant::fromValue(v)); } void QQmlVMEMetaObject::writeProperty(int id, QObject* v) { QV4::MemberData *md = propertyAndMethodStorageAsMemberData(); if (md) - *(md->data() + id) = QV4::QObjectWrapper::wrap(cache->engine, v); + *(md->data() + id) = QV4::QObjectWrapper::wrap(engine, v); QQmlVMEVariantQObjectPtr *guard = getQObjectGuardForProperty(id); if (v && !guard) { @@ -451,7 +452,7 @@ int QQmlVMEMetaObject::readPropertyAsInt(int id) const if (!md) return 0; - QV4::Scope scope(cache->engine); + QV4::Scope scope(engine); QV4::ScopedValue sv(scope, *(md->data() + id)); if (!sv->isInt32()) return 0; @@ -464,7 +465,7 @@ bool QQmlVMEMetaObject::readPropertyAsBool(int id) const if (!md) return false; - QV4::Scope scope(cache->engine); + QV4::Scope scope(engine); QV4::ScopedValue sv(scope, *(md->data() + id)); if (!sv->isBoolean()) return false; @@ -477,7 +478,7 @@ double QQmlVMEMetaObject::readPropertyAsDouble(int id) const if (!md) return 0.0; - QV4::Scope scope(cache->engine); + QV4::Scope scope(engine); QV4::ScopedValue sv(scope, *(md->data() + id)); if (!sv->isDouble()) return 0.0; @@ -490,7 +491,7 @@ QString QQmlVMEMetaObject::readPropertyAsString(int id) const if (!md) return QString(); - QV4::Scope scope(cache->engine); + QV4::Scope scope(engine); QV4::ScopedValue sv(scope, *(md->data() + id)); if (QV4::String *s = sv->stringValue()) return s->toQString(); @@ -503,7 +504,7 @@ QUrl QQmlVMEMetaObject::readPropertyAsUrl(int id) const if (!md) return QUrl(); - QV4::Scope scope(cache->engine); + QV4::Scope scope(engine); QV4::ScopedValue sv(scope, *(md->data() + id)); const QV4::VariantObject *v = sv->as(); if (!v || v->d()->data().type() != QVariant::Url) @@ -517,7 +518,7 @@ QDate QQmlVMEMetaObject::readPropertyAsDate(int id) const if (!md) return QDate(); - QV4::Scope scope(cache->engine); + QV4::Scope scope(engine); QV4::ScopedValue sv(scope, *(md->data() + id)); const QV4::VariantObject *v = sv->as(); if (!v || v->d()->data().type() != QVariant::Date) @@ -531,7 +532,7 @@ QDateTime QQmlVMEMetaObject::readPropertyAsDateTime(int id) if (!md) return QDateTime(); - QV4::Scope scope(cache->engine); + QV4::Scope scope(engine); QV4::ScopedValue sv(scope, *(md->data() + id)); const QV4::VariantObject *v = sv->as(); if (!v || v->d()->data().type() != QVariant::DateTime) @@ -545,7 +546,7 @@ QSizeF QQmlVMEMetaObject::readPropertyAsSizeF(int id) const if (!md) return QSizeF(); - QV4::Scope scope(cache->engine); + QV4::Scope scope(engine); QV4::ScopedValue sv(scope, *(md->data() + id)); const QV4::VariantObject *v = sv->as(); if (!v || v->d()->data().type() != QVariant::SizeF) @@ -559,7 +560,7 @@ QPointF QQmlVMEMetaObject::readPropertyAsPointF(int id) const if (!md) return QPointF(); - QV4::Scope scope(cache->engine); + QV4::Scope scope(engine); QV4::ScopedValue sv(scope, *(md->data() + id)); const QV4::VariantObject *v = sv->as(); if (!v || v->d()->data().type() != QVariant::PointF) @@ -573,7 +574,7 @@ QObject* QQmlVMEMetaObject::readPropertyAsQObject(int id) const if (!md) return 0; - QV4::Scope scope(cache->engine); + QV4::Scope scope(engine); QV4::ScopedValue sv(scope, *(md->data() + id)); const QV4::QObjectWrapper *wrapper = sv->as(); if (!wrapper) @@ -587,11 +588,11 @@ QList *QQmlVMEMetaObject::readPropertyAsList(int id) const if (!md) return 0; - QV4::Scope scope(cache->engine); + QV4::Scope scope(engine); QV4::Scoped v(scope, *(md->data() + id)); if (!v || (int)v->d()->data().userType() != qMetaTypeId >()) { QVariant variant(qVariantFromValue(QList())); - v = cache->engine->newVariantObject(variant); + v = engine->newVariantObject(variant); *(md->data() + id) = v; } return static_cast *>(v->d()->data().data()); @@ -603,7 +604,7 @@ QRectF QQmlVMEMetaObject::readPropertyAsRectF(int id) const if (!md) return QRectF(); - QV4::Scope scope(cache->engine); + QV4::Scope scope(engine); QV4::ScopedValue sv(scope, *(md->data() + id)); const QV4::VariantObject *v = sv->as(); if (!v || v->d()->data().type() != QVariant::RectF) @@ -817,7 +818,7 @@ int QQmlVMEMetaObject::metaCall(QObject *o, QMetaObject::Call c, int _id, void * if (QV4::MemberData *md = propertyAndMethodStorageAsMemberData()) { QV4::VariantObject *v = (md->data() + id)->as(); if (!v) { - *(md->data() + id) = cache->engine->newVariantObject(QVariant()); + *(md->data() + id) = engine->newVariantObject(QVariant()); v = (md->data() + id)->as(); QQml_valueTypeProvider()->initValueType(fallbackMetaType, v->d()->data()); } @@ -1013,7 +1014,7 @@ QVariant QQmlVMEMetaObject::readPropertyAsVariant(int id) const const QV4::VariantObject *v = (md->data() + id)->as(); if (v) return v->d()->data(); - return cache->engine->toVariant(*(md->data() + id), -1); + return engine->toVariant(*(md->data() + id), -1); } return QVariant(); } @@ -1073,8 +1074,8 @@ void QQmlVMEMetaObject::writeProperty(int id, const QVariant &value) // And, if the new value is a scarce resource, we need to ensure that it does not get // automatically released by the engine until no other references to it exist. - QV4::Scope scope(cache->engine); - QV4::ScopedValue newv(scope, cache->engine->fromVariant(value)); + QV4::Scope scope(engine); + QV4::ScopedValue newv(scope, engine->fromVariant(value)); QV4::Scoped v(scope, newv); if (!!v) v->addVmePropertyReference(); @@ -1099,7 +1100,7 @@ void QQmlVMEMetaObject::writeProperty(int id, const QVariant &value) v->d()->data() != value); if (v) v->removeVmePropertyReference(); - *(md->data() + id) = cache->engine->newVariantObject(value); + *(md->data() + id) = engine->newVariantObject(value); v = static_cast(md->data() + id); v->addVmePropertyReference(); } @@ -1163,15 +1164,13 @@ void QQmlVMEMetaObject::setVMEProperty(int index, const QV4::Value &v) void QQmlVMEMetaObject::ensureQObjectWrapper() { - Q_ASSERT(cache && cache->engine); - QV4::ExecutionEngine *v4 = cache->engine; - QV4::QObjectWrapper::wrap(v4, object); + Q_ASSERT(cache); + QV4::QObjectWrapper::wrap(engine, object); } void QQmlVMEMetaObject::mark(QV4::ExecutionEngine *e) { - QV4::ExecutionEngine *v4 = cache ? cache->engine : 0; - if (v4 != e) + if (engine != e) return; propertyAndMethodStorage.markOnce(e); diff --git a/src/qml/qml/qqmlvmemetaobject_p.h b/src/qml/qml/qqmlvmemetaobject_p.h index bb6fede7c8..ede1dd74f9 100644 --- a/src/qml/qml/qqmlvmemetaobject_p.h +++ b/src/qml/qml/qqmlvmemetaobject_p.h @@ -144,7 +144,7 @@ class QQmlVMEMetaObjectEndpoint; class Q_QML_PRIVATE_EXPORT QQmlVMEMetaObject : public QQmlInterceptorMetaObject { public: - QQmlVMEMetaObject(QObject *obj, QQmlPropertyCache *cache, QV4::CompiledData::CompilationUnit *qmlCompilationUnit, int qmlObjectId); + QQmlVMEMetaObject(QV4::ExecutionEngine *engine, QObject *obj, QQmlPropertyCache *cache, QV4::CompiledData::CompilationUnit *qmlCompilationUnit, int qmlObjectId); ~QQmlVMEMetaObject(); bool aliasTarget(int index, QObject **target, int *coreIndex, int *valueTypeIndex) const; @@ -164,6 +164,7 @@ protected: int metaCall(QObject *o, QMetaObject::Call _c, int _id, void **_a) Q_DECL_OVERRIDE; public: + QV4::ExecutionEngine *engine; QQmlGuardedContextData ctxt; inline int propOffset() const; -- cgit v1.2.3 From c6b2dd879d02b21b18f80faab541f8f04286685a Mon Sep 17 00:00:00 2001 From: Simon Hausmann Date: Fri, 23 Jun 2017 13:36:13 +0200 Subject: Move property cache from the engine to QQmlType Now that the property cache is independent of a specific engine, we can cache them in QQmlType instead of caching them per engine. This simplifies the logic and avoids duplicated property caches when multiple engines are running. Task-number: QTBUG-61536 Change-Id: I6f082e1e7495ae0f5b92559e8d0a3437c56e303a Reviewed-by: Lars Knoll --- src/qml/qml/qqmlmetatype.cpp | 29 +++++++++++++++++++++++++++++ src/qml/qml/qqmlmetatype_p.h | 3 +++ src/qml/qml/qqmlpropertycache_p.h | 2 ++ 3 files changed, 34 insertions(+) (limited to 'src/qml/qml') diff --git a/src/qml/qml/qqmlmetatype.cpp b/src/qml/qml/qqmlmetatype.cpp index 3e29222200..a2b6913943 100644 --- a/src/qml/qml/qqmlmetatype.cpp +++ b/src/qml/qml/qqmlmetatype.cpp @@ -110,6 +110,9 @@ struct QQmlMetaTypeData QString typeRegistrationNamespace; QStringList typeRegistrationFailures; + + QHash propertyCaches; + QQmlPropertyCache *propertyCache(const QMetaObject *metaObject); }; class QQmlTypeModulePrivate @@ -151,6 +154,9 @@ QQmlMetaTypeData::~QQmlMetaTypeData() for (TypeModules::const_iterator i = uriToModule.constBegin(), cend = uriToModule.constEnd(); i != cend; ++i) delete *i; + for (QHash::Iterator it = propertyCaches.begin(), end = propertyCaches.end(); + it != end; ++it) + (*it)->release(); } class QQmlTypePrivate @@ -1981,6 +1987,29 @@ QQmlType QQmlMetaType::qmlTypeFromIndex(int idx) return data->types.at(idx); } +QQmlPropertyCache *QQmlMetaTypeData::propertyCache(const QMetaObject *metaObject) +{ + if (QQmlPropertyCache *rv = propertyCaches.value(metaObject)) + return rv; + + if (!metaObject->superClass()) { + QQmlPropertyCache *rv = new QQmlPropertyCache(metaObject); + propertyCaches.insert(metaObject, rv); + return rv; + } + QQmlPropertyCache *super = propertyCache(metaObject->superClass()); + QQmlPropertyCache *rv = super->copyAndAppend(metaObject); + propertyCaches.insert(metaObject, rv); + return rv; +} + +QQmlPropertyCache *QQmlMetaType::propertyCache(const QMetaObject *metaObject) +{ + QMutexLocker lock(metaTypeDataLock()); + QQmlMetaTypeData *data = metaTypeData(); + return data->propertyCache(metaObject); +} + /*! 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 d17172a917..c577a9cc18 100644 --- a/src/qml/qml/qqmlmetatype_p.h +++ b/src/qml/qml/qqmlmetatype_p.h @@ -70,6 +70,7 @@ class QQmlTypeModule; class QHashedString; class QHashedStringRef; class QMutex; +class QQmlPropertyCache; namespace QV4 { struct String; } @@ -89,6 +90,8 @@ public: static QQmlType qmlType(const QUrl &url, bool includeNonFileImports = false); static QQmlType qmlTypeFromIndex(int); + static QQmlPropertyCache *propertyCache(const QMetaObject *metaObject); + static QMetaProperty defaultProperty(const QMetaObject *); static QMetaProperty defaultProperty(QObject *); static QMetaMethod defaultMethod(const QMetaObject *); diff --git a/src/qml/qml/qqmlpropertycache_p.h b/src/qml/qml/qqmlpropertycache_p.h index 6444d8800a..8fdc95af3a 100644 --- a/src/qml/qml/qqmlpropertycache_p.h +++ b/src/qml/qml/qqmlpropertycache_p.h @@ -511,6 +511,8 @@ private: QByteArray _checksum; }; +typedef QQmlRefPointer QQmlPropertyCachePtr; + // QQmlMetaObject serves as a wrapper around either QMetaObject or QQmlPropertyCache. // This is necessary as we delay creation of QMetaObject for synthesized QObjects, but // we don't want to needlessly generate QQmlPropertyCaches every time we encounter a -- cgit v1.2.3 From aa6120cc3524b8d603e92e952aece7494a5d8f02 Mon Sep 17 00:00:00 2001 From: Simon Hausmann Date: Fri, 23 Jun 2017 17:19:26 +0200 Subject: 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 --- src/qml/qml/qqmlengine.cpp | 105 ---------------------------- src/qml/qml/qqmlengine_p.h | 8 +-- src/qml/qml/qqmlmetatype.cpp | 143 ++++++++++++++++++++++++++++++++++++++ src/qml/qml/qqmlmetatype_p.h | 1 + src/qml/qml/qqmlpropertycache_p.h | 1 + 5 files changed, 146 insertions(+), 112 deletions(-) (limited to 'src/qml/qml') 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, 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 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 - // * automatic 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, QQmlPropertyCache *> typePropertyCache; QHash m_qmlLists; QHash 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 propertyCaches; QQmlPropertyCache *propertyCache(const QMetaObject *metaObject); + QQmlPropertyCache *propertyCache(const QQmlType &type, int minorVersion); }; class QQmlTypeModulePrivate @@ -226,6 +227,17 @@ public: mutable QStringHash enums; static QHash attachedPropertyIds; + + struct PropertyCacheByMinorVersion + { + PropertyCacheByMinorVersion() : cache(nullptr), minorVersion(-1) {} + explicit PropertyCacheByMinorVersion(QQmlPropertyCache *pc, int ver) : cache(pc), minorVersion(ver) {} + QQmlPropertyCachePtr cache; + int minorVersion; + }; + QVector 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 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(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 + // * automatic 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(type.key())->setPropertyCacheForMinorVersion(minorVersion, raw); + + if (hasCopied) + raw->release(); + + if (minorVersion != maxMinorVersion) + const_cast(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 friend class QQmlPropertyCacheAliasCreator; friend class QQmlComponentAndAliasResolver; friend class QQmlMetaObject; + friend struct QQmlMetaTypeData; inline QQmlPropertyCache *copy(int reserve); -- cgit v1.2.3 From e61dca72682c9f65c6ab6254fc7e80b49be3ad43 Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Mon, 26 Jun 2017 13:45:56 +0200 Subject: Change data structures in QQmlMetaTypeData Make sure any QQmlType stored in the meta type data has a refcount of 1. This should now make it possible to clean out unused types by iterating over the list of types and removing those that have a refcount of 1. Some care is still needed for C++ registered types, that will need to get one more refcount, so we don't accidentally remove them. Task-number: QTBUG-61536 Change-Id: Id2a18dae5ddcb815f34013f5fde1f05d2d9d0214 Reviewed-by: Simon Hausmann Reviewed-by: Lars Knoll --- src/qml/qml/qqmlmetatype.cpp | 238 +++++++++++++++++++--------------------- src/qml/qml/qqmlmetatype_p.h | 13 +-- src/qml/qml/qqmltypewrapper.cpp | 2 +- 3 files changed, 117 insertions(+), 136 deletions(-) (limited to 'src/qml/qml') diff --git a/src/qml/qml/qqmlmetatype.cpp b/src/qml/qml/qqmlmetatype.cpp index 9dd0c14723..36d70f24c8 100644 --- a/src/qml/qml/qqmlmetatype.cpp +++ b/src/qml/qml/qqmlmetatype.cpp @@ -69,18 +69,18 @@ struct QQmlMetaTypeData { QQmlMetaTypeData(); ~QQmlMetaTypeData(); - QList types; - typedef QHash Ids; + QList types; + typedef QHash Ids; Ids idToType; - typedef QHash Names; + typedef QHash Names; Names nameToType; - typedef QHash Files; //For file imported composite types only + typedef QHash Files; //For file imported composite types only Files urlToType; Files urlToNonFileImportType; // For non-file imported composite and composite // singleton types. This way we can locate any // of them by url, even if it was registered as // a module via QQmlPrivate::RegisterCompositeType - typedef QHash MetaObjects; + typedef QHash MetaObjects; MetaObjects metaObjectToType; typedef QHash StringConverters; StringConverters stringConverters; @@ -130,10 +130,10 @@ public: int maxMinorVersion; bool locked; - void add(QQmlType *); + void add(QQmlTypePrivate *); - QStringHash > typeHash; - QList types; + QStringHash > typeHash; + QList types; }; Q_GLOBAL_STATIC(QQmlMetaTypeData, metaTypeData) @@ -150,9 +150,6 @@ QQmlMetaTypeData::QQmlMetaTypeData() QQmlMetaTypeData::~QQmlMetaTypeData() { - for (int i = 0; i < types.count(); ++i) - delete types.at(i); - for (TypeModules::const_iterator i = uriToModule.constBegin(), cend = uriToModule.constEnd(); i != cend; ++i) delete *i; for (QHash::Iterator it = propertyCaches.begin(), end = propertyCaches.end(); @@ -494,27 +491,6 @@ QQmlType::~QQmlType() delete d; } -QQmlType::QQmlType(QQmlType *otherPointer) - : d(0) -{ - if (otherPointer) { - d = otherPointer->d; - if (d) - d->refCount.ref(); - } -} - -QQmlType &QQmlType::operator =(QQmlType *otherPointer) { - if (otherPointer && otherPointer->d != d) { - if (d && !d->refCount.deref()) - delete d; - d = otherPointer->d; - if (d) - d->refCount.ref(); - } - return *this; -} - QHashedString QQmlType::module() const { if (!d) @@ -556,7 +532,7 @@ bool QQmlType::availableInVersion(const QHashedStringRef &module, int vmajor, in QQmlType QQmlType::superType() const { if (!d) - return 0; + return QQmlType(); if (!d->haveSuperType && d->baseMetaObject) { const QMetaObject *mo = d->baseMetaObject->superClass(); while (mo && !d->superType.isValid()) { @@ -573,10 +549,10 @@ QQmlType QQmlType::resolveCompositeBaseType(QQmlEnginePrivate *engine) const { Q_ASSERT(isComposite()); if (!engine || !d) - return 0; + return QQmlType(); QQmlRefPointer td(engine->typeLoader.getType(sourceUrl()), QQmlRefPointer::Adopt); if (td.isNull() || !td->isComplete()) - return 0; + return QQmlType(); QV4::CompiledData::CompilationUnit *compilationUnit = td->compilationUnit(); const QMetaObject *mo = compilationUnit->rootPropertyCache()->firstCppMetaObject(); return QQmlMetaType::qmlType(mo); @@ -709,18 +685,18 @@ void QQmlTypePrivate::init() const mo = mo->d.superdata; while(mo) { - QQmlType *t = metaTypeData()->metaObjectToType.value(mo); + QQmlTypePrivate *t = metaTypeData()->metaObjectToType.value(mo); if (t) { - if (t->d->regType == QQmlType::CppType) { - if (t->d->extraData.cd->extFunc) { + if (t->regType == QQmlType::CppType) { + if (t->extraData.cd->extFunc) { QMetaObjectBuilder builder; - clone(builder, t->d->extraData.cd->extMetaObject, t->d->baseMetaObject, baseMetaObject); + clone(builder, t->extraData.cd->extMetaObject, t->baseMetaObject, baseMetaObject); builder.setFlags(QMetaObjectBuilder::DynamicMetaObject); QMetaObject *mmo = builder.toMetaObject(); mmo->d.superdata = baseMetaObject; if (!metaObjects.isEmpty()) metaObjects.constLast().metaObject->d.superdata = mmo; - QQmlProxyMetaObject::ProxyData data = { mmo, t->d->extraData.cd->extFunc, 0, 0 }; + QQmlProxyMetaObject::ProxyData data = { mmo, t->extraData.cd->extFunc, 0, 0 }; metaObjects << data; } } @@ -1178,14 +1154,16 @@ int QQmlTypeModule::maximumMinorVersion() const return d->maxMinorVersion; } -void QQmlTypeModulePrivate::add(QQmlType *type) +void QQmlTypeModulePrivate::add(QQmlTypePrivate *type) { - minMinorVersion = qMin(minMinorVersion, type->minorVersion()); - maxMinorVersion = qMax(maxMinorVersion, type->minorVersion()); + int minVersion = type->version_min; + minMinorVersion = qMin(minMinorVersion, minVersion); + maxMinorVersion = qMax(maxMinorVersion, minVersion); - QList &list = typeHash[type->elementName()]; + QList &list = typeHash[type->elementName]; for (int ii = 0; ii < list.count(); ++ii) { - if (list.at(ii)->minorVersion() < type->minorVersion()) { + Q_ASSERT(list.at(ii)); + if (list.at(ii)->version_min < minVersion) { list.insert(ii, type); return; } @@ -1197,11 +1175,11 @@ QQmlType QQmlTypeModule::type(const QHashedStringRef &name, int minor) const { QMutexLocker lock(metaTypeDataLock()); - QList *types = d->typeHash.value(name); + QList *types = d->typeHash.value(name); if (types) { for (int ii = 0; ii < types->count(); ++ii) - if (types->at(ii)->minorVersion() <= minor) - return types->at(ii); + if (types->at(ii)->version_min <= minor) + return QQmlType(types->at(ii)); } return QQmlType(); @@ -1211,11 +1189,11 @@ QQmlType QQmlTypeModule::type(const QV4::String *name, int minor) const { QMutexLocker lock(metaTypeDataLock()); - QList *types = d->typeHash.value(name); + QList *types = d->typeHash.value(name); if (types) { for (int ii = 0; ii < types->count(); ++ii) - if (types->at(ii)->minorVersion() <= minor) - return types->at(ii); + if (types->at(ii)->version_min <= minor) + return QQmlType(types->at(ii)); } return QQmlType(); @@ -1275,9 +1253,6 @@ void qmlClearTypeRegistrations() // Declared in qqml.h QMutexLocker lock(metaTypeDataLock()); QQmlMetaTypeData *data = metaTypeData(); - for (int i = 0; i < data->types.count(); ++i) - delete data->types.at(i); - for (QQmlMetaTypeData::TypeModules::const_iterator i = data->uriToModule.constBegin(), cend = data->uriToModule.constEnd(); i != cend; ++i) delete *i; @@ -1315,14 +1290,16 @@ int registerInterface(const QQmlPrivate::RegisterInterface &interface) int index = data->types.count(); - QQmlType *type = new QQmlType(index, interface); + QQmlType type(index, interface); + QQmlTypePrivate *priv = type.priv(); + Q_ASSERT(priv); data->types.append(type); - data->idToType.insert(type->typeId(), type); - data->idToType.insert(type->qListTypeId(), type); + data->idToType.insert(priv->typeId, priv); + data->idToType.insert(priv->listId, priv); // XXX No insertMulti, so no multi-version interfaces? - if (!type->elementName().isEmpty()) - data->nameToType.insert(type->elementName(), type); + if (!priv->elementName.isEmpty()) + data->nameToType.insert(priv->elementName, priv); if (data->interfaces.size() <= interface.typeId) data->interfaces.resize(interface.typeId + 16); @@ -1413,32 +1390,34 @@ QQmlTypeModule *getTypeModule(const QHashedString &uri, int majorVersion, QQmlMe } // NOTE: caller must hold a QMutexLocker on "data" -void addTypeToData(QQmlType *type, QQmlMetaTypeData *data) +void addTypeToData(QQmlTypePrivate *type, QQmlMetaTypeData *data) { - if (!type->elementName().isEmpty()) - data->nameToType.insertMulti(type->elementName(), type); + Q_ASSERT(type); + + if (!type->elementName.isEmpty()) + data->nameToType.insertMulti(type->elementName, type); - if (type->baseMetaObject()) - data->metaObjectToType.insertMulti(type->baseMetaObject(), type); + if (type->baseMetaObject) + data->metaObjectToType.insertMulti(type->baseMetaObject, type); - if (type->typeId()) { - data->idToType.insert(type->typeId(), type); - if (data->objects.size() <= type->typeId()) - data->objects.resize(type->typeId() + 16); - data->objects.setBit(type->typeId(), true); + if (type->typeId) { + data->idToType.insert(type->typeId, type); + if (data->objects.size() <= type->typeId) + data->objects.resize(type->typeId + 16); + data->objects.setBit(type->typeId, true); } - if (type->qListTypeId()) { - if (data->lists.size() <= type->qListTypeId()) - data->lists.resize(type->qListTypeId() + 16); - data->lists.setBit(type->qListTypeId(), true); - data->idToType.insert(type->qListTypeId(), type); + if (type->listId) { + if (data->lists.size() <= type->listId) + data->lists.resize(type->listId + 16); + data->lists.setBit(type->listId, true); + data->idToType.insert(type->listId, type); } - if (!type->module().isEmpty()) { - const QHashedString &mod = type->module(); + if (!type->module.isEmpty()) { + const QHashedString &mod = type->module; - QQmlTypeModule *module = getTypeModule(mod, type->majorVersion(), data); + QQmlTypeModule *module = getTypeModule(mod, type->version_maj, data); Q_ASSERT(module); module->d->add(type); } @@ -1454,12 +1433,12 @@ int registerType(const QQmlPrivate::RegisterType &type) int index = data->types.count(); - QQmlType *dtype = new QQmlType(index, elementName, type); + QQmlType dtype(index, elementName, type); data->types.append(dtype); - addTypeToData(dtype, data); + addTypeToData(dtype.priv(), data); if (!type.typeId) - data->idToType.insert(dtype->typeId(), dtype); + data->idToType.insert(dtype.typeId(), dtype.priv()); return index; } @@ -1474,10 +1453,10 @@ int registerSingletonType(const QQmlPrivate::RegisterSingletonType &type) int index = data->types.count(); - QQmlType *dtype = new QQmlType(index, typeName, type); + QQmlType dtype(index, typeName, type); data->types.append(dtype); - addTypeToData(dtype, data); + addTypeToData(dtype.priv(), data); return index; } @@ -1496,13 +1475,13 @@ int registerCompositeSingletonType(const QQmlPrivate::RegisterCompositeSingleton int index = data->types.count(); - QQmlType *dtype = new QQmlType(index, typeName, type); + QQmlType dtype(index, typeName, type); data->types.append(dtype); - addTypeToData(dtype, data); + addTypeToData(dtype.priv(), data); QQmlMetaTypeData::Files *files = fileImport ? &(data->urlToType) : &(data->urlToNonFileImportType); - files->insertMulti(type.url, dtype); + files->insertMulti(type.url, dtype.priv()); return index; } @@ -1521,12 +1500,12 @@ int registerCompositeType(const QQmlPrivate::RegisterCompositeType &type) int index = data->types.count(); - QQmlType *dtype = new QQmlType(index, typeName, type); + QQmlType dtype(index, typeName, type); data->types.append(dtype); - addTypeToData(dtype, data); + addTypeToData(dtype.priv(), data); QQmlMetaTypeData::Files *files = fileImport ? &(data->urlToType) : &(data->urlToNonFileImportType); - files->insertMulti(type.url, dtype); + files->insertMulti(type.url, dtype.priv()); return index; } @@ -1602,8 +1581,8 @@ bool QQmlMetaType::namespaceContainsRegistrations(const QString &uri, int majorV // Has any type previously been installed to this namespace? QHashedString nameSpace(uri); - for (const QQmlType *type : data->types) - if (type->module() == nameSpace && type->majorVersion() == majorVersion) + for (const QQmlType &type : data->types) + if (type.module() == nameSpace && type.majorVersion() == majorVersion) return true; return false; @@ -1735,9 +1714,9 @@ int QQmlMetaType::listType(int id) { QMutexLocker lock(metaTypeDataLock()); QQmlMetaTypeData *data = metaTypeData(); - QQmlType *type = data->idToType.value(id); - if (type && type->qListTypeId() == id) - return type->typeId(); + QQmlTypePrivate *type = data->idToType.value(id); + if (type && type->listId == id) + return type->typeId; else return 0; } @@ -1747,9 +1726,9 @@ int QQmlMetaType::attachedPropertiesFuncId(QQmlEnginePrivate *engine, const QMet QMutexLocker lock(metaTypeDataLock()); QQmlMetaTypeData *data = metaTypeData(); - QQmlType *type = data->metaObjectToType.value(mo); - if (type && type->attachedPropertiesFunction(engine)) - return type->attachedPropertiesId(engine); + QQmlType type(data->metaObjectToType.value(mo)); + if (type.attachedPropertiesFunction(engine)) + return type.attachedPropertiesId(engine); else return -1; } @@ -1760,7 +1739,7 @@ QQmlAttachedPropertiesFunc QQmlMetaType::attachedPropertiesFuncById(QQmlEnginePr return 0; QMutexLocker lock(metaTypeDataLock()); QQmlMetaTypeData *data = metaTypeData(); - return data->types.at(id)->attachedPropertiesFunction(engine); + return data->types.at(id).attachedPropertiesFunction(engine); } QMetaProperty QQmlMetaType::defaultProperty(const QMetaObject *metaObject) @@ -1843,10 +1822,10 @@ const char *QQmlMetaType::interfaceIId(int userType) { QMutexLocker lock(metaTypeDataLock()); QQmlMetaTypeData *data = metaTypeData(); - QQmlType *type = data->idToType.value(userType); + QQmlType type(data->idToType.value(userType)); lock.unlock(); - if (type && type->isInterface() && type->typeId() == userType) - return type->interfaceIId(); + if (type.isInterface() && type.typeId() == userType) + return type.interfaceIId(); else return 0; } @@ -1903,7 +1882,7 @@ QQmlType QQmlMetaType::qmlType(const QString &qualifiedName, int version_major, { int slash = qualifiedName.indexOf(QLatin1Char('/')); if (slash <= 0) - return 0; + return QQmlType(); QHashedStringRef module(qualifiedName.constData(), slash); QHashedStringRef name(qualifiedName.constData() + slash + 1, qualifiedName.length() - slash - 1); @@ -1923,9 +1902,10 @@ QQmlType QQmlMetaType::qmlType(const QHashedStringRef &name, const QHashedString QQmlMetaTypeData::Names::ConstIterator it = data->nameToType.constFind(name); while (it != data->nameToType.cend() && it.key() == name) { + QQmlType t(*it); // XXX version_major<0 just a kludge for QQmlPropertyPrivate::initProperty - if (version_major < 0 || module.isEmpty() || (*it)->availableInVersion(module, version_major,version_minor)) - return *(*it); + if (version_major < 0 || module.isEmpty() || t.availableInVersion(module, version_major,version_minor)) + return t; ++it; } @@ -1941,7 +1921,7 @@ QQmlType QQmlMetaType::qmlType(const QMetaObject *metaObject) QMutexLocker lock(metaTypeDataLock()); QQmlMetaTypeData *data = metaTypeData(); - return data->metaObjectToType.value(metaObject); + return QQmlType(data->metaObjectToType.value(metaObject)); } /*! @@ -1957,13 +1937,13 @@ QQmlType QQmlMetaType::qmlType(const QMetaObject *metaObject, const QHashedStrin QQmlMetaTypeData::MetaObjects::const_iterator it = data->metaObjectToType.constFind(metaObject); while (it != data->metaObjectToType.cend() && it.key() == metaObject) { - QQmlType *t = *it; - if (version_major < 0 || module.isEmpty() || t->availableInVersion(module, version_major,version_minor)) + QQmlType t(*it); + if (version_major < 0 || module.isEmpty() || t.availableInVersion(module, version_major,version_minor)) return t; ++it; } - return 0; + return QQmlType(); } /*! @@ -1975,11 +1955,11 @@ QQmlType QQmlMetaType::qmlType(int userType) QMutexLocker lock(metaTypeDataLock()); QQmlMetaTypeData *data = metaTypeData(); - QQmlType *type = data->idToType.value(userType); - if (type && type->typeId() == userType) - return type; + QQmlTypePrivate *type = data->idToType.value(userType); + if (type && type->typeId == userType) + return QQmlType(type); else - return 0; + return QQmlType(); } /*! @@ -1993,12 +1973,12 @@ QQmlType QQmlMetaType::qmlType(const QUrl &url, bool includeNonFileImports /* = QMutexLocker lock(metaTypeDataLock()); QQmlMetaTypeData *data = metaTypeData(); - QQmlType *type = data->urlToType.value(url); - if (!type && includeNonFileImports) - type = data->urlToNonFileImportType.value(url); + QQmlType type(data->urlToType.value(url)); + if (!type.isValid() && includeNonFileImports) + type = QQmlType(data->urlToNonFileImportType.value(url)); - if (type && type->sourceUrl() == url) - return *type; + if (type.sourceUrl() == url) + return type; else return QQmlType(); } @@ -2014,7 +1994,7 @@ QQmlType QQmlMetaType::qmlTypeFromIndex(int idx) QQmlMetaTypeData *data = metaTypeData(); if (idx < 0 || idx >= data->types.count()) - return 0; + return QQmlType(); return data->types.at(idx); } @@ -2060,7 +2040,7 @@ QQmlPropertyCache *QQmlMetaTypeData::propertyCache(const QQmlType &type, int min maxMinorVersion = qMax(maxMinorVersion, t.minorVersion()); types << t; } else { - types << 0; + types << QQmlType(); } metaObject = metaObject->superClass(); @@ -2165,7 +2145,8 @@ QList QQmlMetaType::qmlTypeNames() names.reserve(data->nameToType.count()); QQmlMetaTypeData::Names::ConstIterator it = data->nameToType.cbegin(); while (it != data->nameToType.cend()) { - names += (*it)->qmlTypeName(); + QQmlType t(*it); + names += t.qmlTypeName(); ++it; } @@ -2175,18 +2156,22 @@ QList QQmlMetaType::qmlTypeNames() /*! Returns the list of registered QML types. */ -QList QQmlMetaType::qmlTypes() +QList QQmlMetaType::qmlTypes() { QMutexLocker lock(metaTypeDataLock()); - QQmlMetaTypeData *data = metaTypeData(); + const QQmlMetaTypeData *data = metaTypeData(); + + QList types; + for (QQmlTypePrivate *t : data->nameToType) + types.append(QQmlType(t)); - return data->nameToType.values(); + return types; } /*! Returns the list of all registered types. */ -QList QQmlMetaType::qmlAllTypes() +QList QQmlMetaType::qmlAllTypes() { QMutexLocker lock(metaTypeDataLock()); QQmlMetaTypeData *data = metaTypeData(); @@ -2203,9 +2188,10 @@ QList QQmlMetaType::qmlSingletonTypes() QQmlMetaTypeData *data = metaTypeData(); QList retn; - for (const auto type : qAsConst(data->nameToType)) { - if (type->isSingleton()) - retn.append(*type); + for (const auto t : qAsConst(data->nameToType)) { + QQmlType type(t); + if (type.isSingleton()) + retn.append(type); } return retn; } diff --git a/src/qml/qml/qqmlmetatype_p.h b/src/qml/qml/qqmlmetatype_p.h index 43eda2b4f1..0077306a64 100644 --- a/src/qml/qml/qqmlmetatype_p.h +++ b/src/qml/qml/qqmlmetatype_p.h @@ -78,9 +78,9 @@ class Q_QML_PRIVATE_EXPORT QQmlMetaType { public: static QList qmlTypeNames(); - static QList qmlTypes(); + static QList qmlTypes(); static QList qmlSingletonTypes(); - static QList qmlAllTypes(); + static QList qmlAllTypes(); static QQmlType qmlType(const QString &qualifiedName, int, int); static QQmlType qmlType(const QHashedStringRef &name, const QHashedStringRef &module, int, int); @@ -148,10 +148,6 @@ public: explicit QQmlType(QQmlTypePrivate *priv); ~QQmlType(); - // ### get rid of these two again - QQmlType(QQmlType *otherPointer); - QQmlType &operator =(QQmlType *otherPointer); - bool operator ==(const QQmlType &other) const { return d == other.d; } @@ -238,7 +234,7 @@ public: int enumValue(QQmlEnginePrivate *engine, const QHashedCStringRef &, bool *ok) const; int enumValue(QQmlEnginePrivate *engine, const QV4::String *, bool *ok) const; - QQmlTypePrivate *handle() const { return d; } + QQmlTypePrivate *priv() const { return d; } static void refHandle(QQmlTypePrivate *priv); static void derefHandle(QQmlTypePrivate *priv); private: @@ -246,7 +242,6 @@ private: QQmlType resolveCompositeBaseType(QQmlEnginePrivate *engine) const; int resolveCompositeEnumValue(QQmlEnginePrivate *engine, const QString &name, bool *ok) const; friend class QQmlTypePrivate; - friend struct QQmlMetaTypeData; enum RegistrationType { CppType = 0, @@ -296,7 +291,7 @@ public: private: //Used by register functions and creates the QQmlTypeModule for them friend QQmlTypeModule *getTypeModule(const QHashedString &uri, int majorVersion, QQmlMetaTypeData *data); - friend void addTypeToData(QQmlType* type, QQmlMetaTypeData *data); + friend void addTypeToData(QQmlTypePrivate *type, QQmlMetaTypeData *data); friend struct QQmlMetaTypeData; friend Q_QML_EXPORT void qmlClearTypeRegistrations(); friend class QQmlTypeModulePrivate; diff --git a/src/qml/qml/qqmltypewrapper.cpp b/src/qml/qml/qqmltypewrapper.cpp index 6fab7697f8..ba07b77c72 100644 --- a/src/qml/qml/qqmltypewrapper.cpp +++ b/src/qml/qml/qqmltypewrapper.cpp @@ -112,7 +112,7 @@ ReturnedValue QmlTypeWrapper::create(QV4::ExecutionEngine *engine, QObject *o, c Scoped w(scope, engine->memoryManager->allocObject()); w->d()->mode = mode; w->d()->object = o; - w->d()->typePrivate = t.handle(); + w->d()->typePrivate = t.priv(); QQmlType::refHandle(w->d()->typePrivate); return w.asReturnedValue(); } -- cgit v1.2.3 From 4d393779e7a6ec09267f40420f39f8dc28ed7aef Mon Sep 17 00:00:00 2001 From: Simon Hausmann Date: Mon, 26 Jun 2017 14:28:57 +0200 Subject: Remove unused variable QQmlTypeModulePrivate::types is not used (anymore?). Task-number: QTBUG-61536 Change-Id: Ia7af542e6969c167d1f05a460e0926398f56f380 Reviewed-by: Lars Knoll --- src/qml/qml/qqmlmetatype.cpp | 1 - 1 file changed, 1 deletion(-) (limited to 'src/qml/qml') diff --git a/src/qml/qml/qqmlmetatype.cpp b/src/qml/qml/qqmlmetatype.cpp index 36d70f24c8..59ed86f31a 100644 --- a/src/qml/qml/qqmlmetatype.cpp +++ b/src/qml/qml/qqmlmetatype.cpp @@ -133,7 +133,6 @@ public: void add(QQmlTypePrivate *); QStringHash > typeHash; - QList types; }; Q_GLOBAL_STATIC(QQmlMetaTypeData, metaTypeData) -- cgit v1.2.3 From 48c09a85ce397979c7e706e3694c879ffe456e09 Mon Sep 17 00:00:00 2001 From: Simon Hausmann Date: Mon, 26 Jun 2017 14:52:22 +0200 Subject: Remove unused types on engine destruction The QML engine destructor as well as trimComponentCache() do now clean out unused composite types that the engine registered internally. This helps avoid 'static' leaks, when more and more types would get registered by the engine. Task-number: QTBUG-61536 Change-Id: I5b32af4b88fbf626de8c0bfbaedb2285b09e3679 Reviewed-by: Lars Knoll --- src/qml/qml/qqmlengine.cpp | 2 + src/qml/qml/qqmlimport.cpp | 4 +- src/qml/qml/qqmlmetatype.cpp | 251 ++++++++++++++++++++++++++++------------- src/qml/qml/qqmlmetatype_p.h | 39 ++++--- src/qml/qml/qqmltypeloader.cpp | 3 + 5 files changed, 201 insertions(+), 98 deletions(-) (limited to 'src/qml/qml') diff --git a/src/qml/qml/qqmlengine.cpp b/src/qml/qml/qqmlengine.cpp index 6f5dcc0746..3003d18efc 100644 --- a/src/qml/qml/qqmlengine.cpp +++ b/src/qml/qml/qqmlengine.cpp @@ -694,6 +694,8 @@ QQmlEnginePrivate::~QQmlEnginePrivate() if (incubationController) incubationController->d = 0; incubationController = 0; + QQmlMetaType::freeUnusedTypesAndCaches(); + for (auto iter = m_compositeTypes.cbegin(), end = m_compositeTypes.cend(); iter != end; ++iter) { iter.value()->isRegisteredWithEngine = false; diff --git a/src/qml/qml/qqmlimport.cpp b/src/qml/qml/qqmlimport.cpp index 89c7fd3214..e197efe72b 100644 --- a/src/qml/qml/qqmlimport.cpp +++ b/src/qml/qml/qqmlimport.cpp @@ -183,7 +183,7 @@ QQmlType fetchOrCreateTypeForUrl(const QString &urlString, const QHashedStringRe minorVersion, buf.constData() }; - ret = QQmlMetaType::qmlTypeFromIndex(QQmlPrivate::qmlregister(QQmlPrivate::CompositeSingletonRegistration, ®)); + ret = QQmlMetaType::registerCompositeSingletonType(reg); } else { QQmlPrivate::RegisterCompositeType reg = { url, @@ -192,7 +192,7 @@ QQmlType fetchOrCreateTypeForUrl(const QString &urlString, const QHashedStringRe minorVersion, buf.constData() }; - ret = QQmlMetaType::qmlTypeFromIndex(QQmlPrivate::qmlregister(QQmlPrivate::CompositeRegistration, ®)); + ret = QQmlMetaType::registerCompositeType(reg); } // This means that the type couldn't be found by URL, but could not be diff --git a/src/qml/qml/qqmlmetatype.cpp b/src/qml/qml/qqmlmetatype.cpp index 59ed86f31a..efe6e1c3be 100644 --- a/src/qml/qml/qqmlmetatype.cpp +++ b/src/qml/qml/qqmlmetatype.cpp @@ -69,7 +69,9 @@ struct QQmlMetaTypeData { QQmlMetaTypeData(); ~QQmlMetaTypeData(); + void registerType(QQmlTypePrivate *priv); QList types; + QSet undeletableTypes; typedef QHash Ids; Ids idToType; typedef QHash Names; @@ -131,8 +133,10 @@ public: bool locked; void add(QQmlTypePrivate *); + void remove(const QQmlTypePrivate *type); - QStringHash > typeHash; + typedef QStringHash > TypeHash; + TypeHash typeHash; }; Q_GLOBAL_STATIC(QQmlMetaTypeData, metaTypeData) @@ -226,7 +230,7 @@ public: struct PropertyCacheByMinorVersion { - PropertyCacheByMinorVersion() : cache(nullptr), minorVersion(-1) {} + PropertyCacheByMinorVersion() : cache(Q_NULLPTR), minorVersion(-1) {} explicit PropertyCacheByMinorVersion(QQmlPropertyCache *pc, int ver) : cache(pc), minorVersion(ver) {} QQmlPropertyCachePtr cache; int minorVersion; @@ -236,6 +240,19 @@ public: void setPropertyCacheForMinorVersion(int minorVersion, QQmlPropertyCache *cache); }; +void QQmlMetaTypeData::registerType(QQmlTypePrivate *priv) +{ + for (int i = 0; i < types.count(); ++i) { + if (!types.at(i).isValid()) { + types[i] = QQmlType(priv); + priv->index = i; + return; + } + } + types.append(QQmlType(priv)); + priv->index = types.count() - 1; +} + void QQmlType::SingletonInstanceInfo::init(QQmlEngine *e) { QV4::ExecutionEngine *v4 = QV8Engine::getV4(e->handle()); @@ -347,21 +364,23 @@ QQmlTypePrivate::~QQmlTypePrivate() } } -QQmlType::QQmlType(int index, const QQmlPrivate::RegisterInterface &interface) +QQmlType::QQmlType(QQmlMetaTypeData *data, const QQmlPrivate::RegisterInterface &interface) : d(new QQmlTypePrivate(InterfaceType)) { d->iid = interface.iid; d->typeId = interface.typeId; d->listId = interface.listId; - d->index = index; d->isSetup = true; d->version_maj = 0; d->version_min = 0; + data->registerType(d); } -QQmlType::QQmlType(int index, const QString &elementName, const QQmlPrivate::RegisterSingletonType &type) +QQmlType::QQmlType(QQmlMetaTypeData *data, const QString &elementName, const QQmlPrivate::RegisterSingletonType &type) : d(new QQmlTypePrivate(SingletonType)) { + data->registerType(d); + d->elementName = elementName; d->module = QString::fromUtf8(type.uri); @@ -377,8 +396,6 @@ QQmlType::QQmlType(int index, const QString &elementName, const QQmlPrivate::Reg d->revision = type.revision; } - d->index = index; - d->extraData.sd->singletonInstanceInfo = new SingletonInstanceInfo; d->extraData.sd->singletonInstanceInfo->scriptCallback = type.scriptApi; d->extraData.sd->singletonInstanceInfo->qobjectCallback = type.qobjectApi; @@ -387,25 +404,27 @@ QQmlType::QQmlType(int index, const QString &elementName, const QQmlPrivate::Reg = (type.qobjectApi && type.version >= 1) ? type.instanceMetaObject : 0; } -QQmlType::QQmlType(int index, const QString &elementName, const QQmlPrivate::RegisterCompositeSingletonType &type) +QQmlType::QQmlType(QQmlMetaTypeData *data, const QString &elementName, const QQmlPrivate::RegisterCompositeSingletonType &type) : d(new QQmlTypePrivate(CompositeSingletonType)) { + data->registerType(d); + d->elementName = elementName; d->module = QString::fromUtf8(type.uri); d->version_maj = type.versionMajor; d->version_min = type.versionMinor; - d->index = index; - d->extraData.sd->singletonInstanceInfo = new SingletonInstanceInfo; d->extraData.sd->singletonInstanceInfo->url = type.url; d->extraData.sd->singletonInstanceInfo->typeName = QString::fromUtf8(type.typeName); } -QQmlType::QQmlType(int index, const QString &elementName, const QQmlPrivate::RegisterType &type) +QQmlType::QQmlType(QQmlMetaTypeData *data, const QString &elementName, const QQmlPrivate::RegisterType &type) : d(new QQmlTypePrivate(CppType)) { + data->registerType(d); + d->elementName = elementName; d->module = QString::fromUtf8(type.uri); @@ -424,7 +443,7 @@ QQmlType::QQmlType(int index, const QString &elementName, const QQmlPrivate::Reg if (d->extraData.cd->attachedPropertiesType) { QHash::Iterator iter = d->attachedPropertyIds.find(d->baseMetaObject); if (iter == d->attachedPropertyIds.end()) - iter = d->attachedPropertyIds.insert(d->baseMetaObject, index); + iter = d->attachedPropertyIds.insert(d->baseMetaObject, d->index); d->extraData.cd->attachedPropertiesId = *iter; } else { d->extraData.cd->attachedPropertiesId = -1; @@ -434,16 +453,16 @@ QQmlType::QQmlType(int index, const QString &elementName, const QQmlPrivate::Reg d->extraData.cd->propertyValueInterceptorCast = type.valueInterceptorCast; d->extraData.cd->extFunc = type.extensionObjectCreate; d->extraData.cd->customParser = type.customParser; - d->index = index; if (type.extensionMetaObject) d->extraData.cd->extMetaObject = type.extensionMetaObject; } -QQmlType::QQmlType(int index, const QString &elementName, const QQmlPrivate::RegisterCompositeType &type) +QQmlType::QQmlType(QQmlMetaTypeData *data, const QString &elementName, const QQmlPrivate::RegisterCompositeType &type) : d(new QQmlTypePrivate(CompositeType)) { - d->index = index; + data->registerType(d); + d->elementName = elementName; d->module = QString::fromUtf8(type.uri); @@ -772,7 +791,7 @@ QQmlPropertyCache *QQmlTypePrivate::propertyCacheForMinorVersion(int minorVersio for (int i = 0; i < propertyCaches.count(); ++i) if (propertyCaches.at(i).minorVersion == minorVersion) return propertyCaches.at(i).cache; - return nullptr; + return Q_NULLPTR; } void QQmlTypePrivate::setPropertyCacheForMinorVersion(int minorVersion, QQmlPropertyCache *cache) @@ -1123,6 +1142,27 @@ void QQmlType::derefHandle(QQmlTypePrivate *priv) delete priv; } +namespace { +template +void removeQQmlTypePrivate(QQmlTypeContainer &container, const QQmlTypePrivate *reference) +{ + for (typename QQmlTypeContainer::iterator it = container.begin(); it != container.end();) { + if (*it == reference) + it = container.erase(it); + else + ++it; + } +} + +struct IsQQmlTypePrivate +{ + const QQmlTypePrivate *reference; + explicit IsQQmlTypePrivate(const QQmlTypePrivate *ref) : reference(ref) {} + + bool operator()(const QQmlTypePrivate *priv) const { return reference == priv; } +}; +} + QQmlTypeModule::QQmlTypeModule() : d(new QQmlTypeModulePrivate) { @@ -1170,6 +1210,24 @@ void QQmlTypeModulePrivate::add(QQmlTypePrivate *type) list.append(type); } +void QQmlTypeModulePrivate::remove(const QQmlTypePrivate *type) +{ + for (TypeHash::ConstIterator elementIt = typeHash.begin(); elementIt != typeHash.end();) { + QList &list = typeHash[elementIt.key()]; + + removeQQmlTypePrivate(list, type); + +#if 0 + if (list.isEmpty()) + elementIt = typeHash.erase(elementIt); + else + ++elementIt; +#else + ++elementIt; +#endif + } +} + QQmlType QQmlTypeModule::type(const QHashedStringRef &name, int minor) const { QMutexLocker lock(metaTypeDataLock()); @@ -1269,7 +1327,7 @@ void qmlClearTypeRegistrations() // Declared in qqml.h #endif } -int registerAutoParentFunction(QQmlPrivate::RegisterAutoParent &autoparent) +static int registerAutoParentFunction(QQmlPrivate::RegisterAutoParent &autoparent) { QMutexLocker lock(metaTypeDataLock()); QQmlMetaTypeData *data = metaTypeData(); @@ -1279,7 +1337,7 @@ int registerAutoParentFunction(QQmlPrivate::RegisterAutoParent &autoparent) return data->parentFunctions.count() - 1; } -int registerInterface(const QQmlPrivate::RegisterInterface &interface) +QQmlType registerInterface(const QQmlPrivate::RegisterInterface &interface) { if (interface.version > 0) qFatal("qmlRegisterType(): Cannot mix incompatible QML versions."); @@ -1287,13 +1345,10 @@ int registerInterface(const QQmlPrivate::RegisterInterface &interface) QMutexLocker lock(metaTypeDataLock()); QQmlMetaTypeData *data = metaTypeData(); - int index = data->types.count(); - - QQmlType type(index, interface); + QQmlType type(data, interface); QQmlTypePrivate *priv = type.priv(); Q_ASSERT(priv); - data->types.append(type); data->idToType.insert(priv->typeId, priv); data->idToType.insert(priv->listId, priv); // XXX No insertMulti, so no multi-version interfaces? @@ -1307,7 +1362,7 @@ int registerInterface(const QQmlPrivate::RegisterInterface &interface) data->interfaces.setBit(interface.typeId, true); data->lists.setBit(interface.listId, true); - return index; + return type; } QString registrationTypeString(QQmlType::RegistrationType typeType) @@ -1422,45 +1477,39 @@ void addTypeToData(QQmlTypePrivate *type, QQmlMetaTypeData *data) } } -int registerType(const QQmlPrivate::RegisterType &type) +QQmlType registerType(const QQmlPrivate::RegisterType &type) { QMutexLocker lock(metaTypeDataLock()); QQmlMetaTypeData *data = metaTypeData(); QString elementName = QString::fromUtf8(type.elementName); if (!checkRegistration(QQmlType::CppType, data, type.uri, elementName, type.versionMajor)) - return -1; - - int index = data->types.count(); + return QQmlType(); - QQmlType dtype(index, elementName, type); + QQmlType dtype(data, elementName, type); - data->types.append(dtype); addTypeToData(dtype.priv(), data); if (!type.typeId) data->idToType.insert(dtype.typeId(), dtype.priv()); - return index; + return dtype; } -int registerSingletonType(const QQmlPrivate::RegisterSingletonType &type) +QQmlType registerSingletonType(const QQmlPrivate::RegisterSingletonType &type) { QMutexLocker lock(metaTypeDataLock()); QQmlMetaTypeData *data = metaTypeData(); QString typeName = QString::fromUtf8(type.typeName); if (!checkRegistration(QQmlType::SingletonType, data, type.uri, typeName, type.versionMajor)) - return -1; - - int index = data->types.count(); + return QQmlType(); - QQmlType dtype(index, typeName, type); + QQmlType dtype(data, typeName, type); - data->types.append(dtype); addTypeToData(dtype.priv(), data); - return index; + return dtype; } -int registerCompositeSingletonType(const QQmlPrivate::RegisterCompositeSingletonType &type) +QQmlType QQmlMetaType::registerCompositeSingletonType(const QQmlPrivate::RegisterCompositeSingletonType &type) { // Assumes URL is absolute and valid. Checking of user input should happen before the URL enters type. QMutexLocker lock(metaTypeDataLock()); @@ -1470,22 +1519,19 @@ int registerCompositeSingletonType(const QQmlPrivate::RegisterCompositeSingleton if (*(type.uri) == '\0') fileImport = true; if (!checkRegistration(QQmlType::CompositeSingletonType, data, fileImport ? 0 : type.uri, typeName)) - return -1; - - int index = data->types.count(); + return QQmlType(); - QQmlType dtype(index, typeName, type); + QQmlType dtype(data, typeName, type); - data->types.append(dtype); addTypeToData(dtype.priv(), data); QQmlMetaTypeData::Files *files = fileImport ? &(data->urlToType) : &(data->urlToNonFileImportType); files->insertMulti(type.url, dtype.priv()); - return index; + return dtype; } -int registerCompositeType(const QQmlPrivate::RegisterCompositeType &type) +QQmlType QQmlMetaType::registerCompositeType(const QQmlPrivate::RegisterCompositeType &type) { // Assumes URL is absolute and valid. Checking of user input should happen before the URL enters type. QMutexLocker lock(metaTypeDataLock()); @@ -1495,18 +1541,15 @@ int registerCompositeType(const QQmlPrivate::RegisterCompositeType &type) if (*(type.uri) == '\0') fileImport = true; if (!checkRegistration(QQmlType::CompositeType, data, fileImport?0:type.uri, typeName, type.versionMajor)) - return -1; - - int index = data->types.count(); + return QQmlType(); - QQmlType dtype(index, typeName, type); - data->types.append(dtype); + QQmlType dtype(data, typeName, type); addTypeToData(dtype.priv(), data); QQmlMetaTypeData::Files *files = fileImport ? &(data->urlToType) : &(data->urlToNonFileImportType); files->insertMulti(type.url, dtype.priv()); - return index; + return dtype; } int registerQmlUnitCacheHook(const QQmlPrivate::RegisterQmlUnitCacheHook &hookRegistration) @@ -1525,22 +1568,30 @@ the future without adding exported symbols. */ int QQmlPrivate::qmlregister(RegistrationType type, void *data) { - if (type == TypeRegistration) { - return registerType(*reinterpret_cast(data)); - } else if (type == InterfaceRegistration) { - return registerInterface(*reinterpret_cast(data)); - } else if (type == AutoParentRegistration) { + if (type == AutoParentRegistration) return registerAutoParentFunction(*reinterpret_cast(data)); - } else if (type == SingletonRegistration) { - return registerSingletonType(*reinterpret_cast(data)); - } else if (type == CompositeRegistration) { - return registerCompositeType(*reinterpret_cast(data)); - } else if (type == CompositeSingletonRegistration) { - return registerCompositeSingletonType(*reinterpret_cast(data)); - } else if (type == QmlUnitCacheHookRegistration) { + else if (type == QmlUnitCacheHookRegistration) return registerQmlUnitCacheHook(*reinterpret_cast(data)); - } - return -1; + + QQmlType dtype; + if (type == TypeRegistration) + dtype = registerType(*reinterpret_cast(data)); + else if (type == InterfaceRegistration) + dtype = registerInterface(*reinterpret_cast(data)); + else if (type == SingletonRegistration) + dtype = registerSingletonType(*reinterpret_cast(data)); + else if (type == CompositeRegistration) + dtype = QQmlMetaType::registerCompositeType(*reinterpret_cast(data)); + else if (type == CompositeSingletonRegistration) + dtype = QQmlMetaType::registerCompositeSingletonType(*reinterpret_cast(data)); + else + return -1; + + QMutexLocker lock(metaTypeDataLock()); + QQmlMetaTypeData *typeData = metaTypeData(); + typeData->undeletableTypes.insert(dtype); + + return dtype.index(); } //From qqml.h @@ -1982,21 +2033,6 @@ QQmlType QQmlMetaType::qmlType(const QUrl &url, bool includeNonFileImports /* = return QQmlType(); } -/*! - Returns the type (if any) with the given \a index in the global type store. - This is for use when you just got the index back from a qmlRegister function. - Returns null if the index is out of bounds. -*/ -QQmlType QQmlMetaType::qmlTypeFromIndex(int idx) -{ - QMutexLocker lock(metaTypeDataLock()); - QQmlMetaTypeData *data = metaTypeData(); - - if (idx < 0 || idx >= data->types.count()) - return QQmlType(); - return data->types.at(idx); -} - QQmlPropertyCache *QQmlMetaTypeData::propertyCache(const QMetaObject *metaObject) { if (QQmlPropertyCache *rv = propertyCaches.value(metaObject)) @@ -2132,6 +2168,61 @@ QQmlPropertyCache *QQmlMetaType::propertyCache(const QQmlType &type, int minorVe return data->propertyCache(type, minorVersion); } +void QQmlMetaType::freeUnusedTypesAndCaches() +{ + QMutexLocker lock(metaTypeDataLock()); + QQmlMetaTypeData *data = metaTypeData(); + + { + bool deletedAtLeastOneType; + do { + deletedAtLeastOneType = false; + QList::Iterator it = data->types.begin(); + while (it != data->types.end()) { + const QQmlTypePrivate *d = (*it).priv(); + if (d && d->refCount == 1) { + deletedAtLeastOneType = true; + + removeQQmlTypePrivate(data->idToType, d); + removeQQmlTypePrivate(data->nameToType, d); + removeQQmlTypePrivate(data->urlToType, d); + removeQQmlTypePrivate(data->urlToNonFileImportType, d); + removeQQmlTypePrivate(data->metaObjectToType, d); + + for (QQmlMetaTypeData::TypeModules::Iterator module = data->uriToModule.begin(); module != data->uriToModule.end(); ++module) { + QQmlTypeModulePrivate *modulePrivate = (*module)->priv(); + modulePrivate->remove(d); + } + + *it = QQmlType(); + } else { + ++it; + } + } + } while (deletedAtLeastOneType); + } + + { + bool deletedAtLeastOneCache; + do { + deletedAtLeastOneCache = false; + QHash::Iterator it = data->propertyCaches.begin(); + while (it != data->propertyCaches.end()) { + + if ((*it)->count() == 1) { + QQmlPropertyCache *pc = Q_NULLPTR; + qSwap(pc, *it); + it = data->propertyCaches.erase(it); + pc->release(); + deletedAtLeastOneCache = true; + } else { + ++it; + } + } + } while (deletedAtLeastOneCache); + } +} + /*! 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 0077306a64..c0fbdd5060 100644 --- a/src/qml/qml/qqmlmetatype_p.h +++ b/src/qml/qml/qqmlmetatype_p.h @@ -77,6 +77,9 @@ namespace QV4 { struct String; } class Q_QML_PRIVATE_EXPORT QQmlMetaType { public: + static QQmlType registerCompositeSingletonType(const QQmlPrivate::RegisterCompositeSingletonType &type); + static QQmlType registerCompositeType(const QQmlPrivate::RegisterCompositeType &type); + static QList qmlTypeNames(); static QList qmlTypes(); static QList qmlSingletonTypes(); @@ -88,11 +91,12 @@ public: static QQmlType qmlType(const QMetaObject *metaObject, const QHashedStringRef &module, int version_major, int version_minor); static QQmlType qmlType(int); static QQmlType qmlType(const QUrl &url, bool includeNonFileImports = false); - static QQmlType qmlTypeFromIndex(int); static QQmlPropertyCache *propertyCache(const QMetaObject *metaObject); static QQmlPropertyCache *propertyCache(const QQmlType &type, int minorVersion); + static void freeUnusedTypesAndCaches(); + static QMetaProperty defaultProperty(const QMetaObject *); static QMetaProperty defaultProperty(QObject *); static QMetaMethod defaultMethod(const QMetaObject *); @@ -237,11 +241,6 @@ public: QQmlTypePrivate *priv() const { return d; } static void refHandle(QQmlTypePrivate *priv); static void derefHandle(QQmlTypePrivate *priv); -private: - QQmlType superType() const; - QQmlType resolveCompositeBaseType(QQmlEnginePrivate *engine) const; - int resolveCompositeEnumValue(QQmlEnginePrivate *engine, const QString &name, bool *ok) const; - friend class QQmlTypePrivate; enum RegistrationType { CppType = 0, @@ -250,21 +249,28 @@ private: CompositeType = 3, CompositeSingletonType = 4 }; + +private: + QQmlType superType() const; + QQmlType resolveCompositeBaseType(QQmlEnginePrivate *engine) const; + int resolveCompositeEnumValue(QQmlEnginePrivate *engine, const QString &name, bool *ok) const; + friend class QQmlTypePrivate; + friend QString registrationTypeString(RegistrationType); friend bool checkRegistration(RegistrationType, QQmlMetaTypeData *, const char *, const QString &, int); - friend int registerType(const QQmlPrivate::RegisterType &); - friend int registerSingletonType(const QQmlPrivate::RegisterSingletonType &); - friend int registerInterface(const QQmlPrivate::RegisterInterface &); - friend int registerCompositeType(const QQmlPrivate::RegisterCompositeType &); - friend int registerCompositeSingletonType(const QQmlPrivate::RegisterCompositeSingletonType &); + friend QQmlType registerType(const QQmlPrivate::RegisterType &); + friend QQmlType registerSingletonType(const QQmlPrivate::RegisterSingletonType &); + friend QQmlType registerInterface(const QQmlPrivate::RegisterInterface &); friend int registerQmlUnitCacheHook(const QQmlPrivate::RegisterQmlUnitCacheHook &); friend uint qHash(const QQmlType &t, uint seed); friend Q_QML_EXPORT void qmlClearTypeRegistrations(); - QQmlType(int, const QQmlPrivate::RegisterInterface &); - QQmlType(int, const QString &, const QQmlPrivate::RegisterSingletonType &); - QQmlType(int, const QString &, const QQmlPrivate::RegisterType &); - QQmlType(int, const QString &, const QQmlPrivate::RegisterCompositeType &); - QQmlType(int, const QString &, const QQmlPrivate::RegisterCompositeSingletonType &); + friend class QQmlMetaType; + + QQmlType(QQmlMetaTypeData *data, const QQmlPrivate::RegisterInterface &); + QQmlType(QQmlMetaTypeData *data, const QString &, const QQmlPrivate::RegisterSingletonType &); + QQmlType(QQmlMetaTypeData *data, const QString &, const QQmlPrivate::RegisterType &); + QQmlType(QQmlMetaTypeData *data, const QString &, const QQmlPrivate::RegisterCompositeType &); + QQmlType(QQmlMetaTypeData *data, const QString &, const QQmlPrivate::RegisterCompositeSingletonType &); QQmlTypePrivate *d; }; @@ -288,6 +294,7 @@ public: QQmlType type(const QHashedStringRef &, int) const; QQmlType type(const QV4::String *, int) const; + QQmlTypeModulePrivate *priv() { return d; } private: //Used by register functions and creates the QQmlTypeModule for them friend QQmlTypeModule *getTypeModule(const QHashedString &uri, int majorVersion, QQmlMetaTypeData *data); diff --git a/src/qml/qml/qqmltypeloader.cpp b/src/qml/qml/qqmltypeloader.cpp index fbb04af165..2825e0d698 100644 --- a/src/qml/qml/qqmltypeloader.cpp +++ b/src/qml/qml/qqmltypeloader.cpp @@ -1947,6 +1947,7 @@ void QQmlTypeLoader::clearCache() m_qmldirCache.clear(); m_importDirCache.clear(); m_importQmlDirCache.clear(); + QQmlMetaType::freeUnusedTypesAndCaches(); } void QQmlTypeLoader::updateTypeCacheTrimThreshold() @@ -1988,6 +1989,8 @@ void QQmlTypeLoader::trimCache() updateTypeCacheTrimThreshold(); + QQmlMetaType::freeUnusedTypesAndCaches(); + // TODO: release any scripts which are no longer referenced by any types } -- cgit v1.2.3 From d621573d121348fed943dfe73ec9a89b27a92e52 Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Tue, 27 Jun 2017 08:55:01 +0200 Subject: Move the m_qmlLists member in the QML engine to QQmlMetaType This is a pure metatype id to metatype id mapping, nothing in there is specific to a QML engine instance. Thus move the mapping to QQmlMetaType and make it global for all engines. Task-number: QTBUG-61536 Change-Id: I3792567bc9f585e3e0fbbad94efd1ec3a0db3de0 Reviewed-by: Simon Hausmann --- src/qml/qml/qqmlengine.cpp | 47 +++++---------------------------------- src/qml/qml/qqmlengine_p.h | 1 - src/qml/qml/qqmlmetatype.cpp | 52 +++++++++++++++++++++++++++++++++++++++++++- src/qml/qml/qqmlmetatype_p.h | 4 ++++ 4 files changed, 61 insertions(+), 43 deletions(-) (limited to 'src/qml/qml') diff --git a/src/qml/qml/qqmlengine.cpp b/src/qml/qml/qqmlengine.cpp index 3003d18efc..9676feb279 100644 --- a/src/qml/qml/qqmlengine.cpp +++ b/src/qml/qml/qqmlengine.cpp @@ -2215,26 +2215,17 @@ QQmlMetaType::TypeCategory QQmlEnginePrivate::typeCategory(int t) const Locker locker(this); if (m_compositeTypes.contains(t)) return QQmlMetaType::Object; - else if (m_qmlLists.contains(t)) - return QQmlMetaType::List; - else - return QQmlMetaType::typeCategory(t); + return QQmlMetaType::typeCategory(t); } bool QQmlEnginePrivate::isList(int t) const { - Locker locker(this); - return m_qmlLists.contains(t) || QQmlMetaType::isList(t); + return QQmlMetaType::isList(t); } int QQmlEnginePrivate::listType(int t) const { - Locker locker(this); - QHash::ConstIterator iter = m_qmlLists.constFind(t); - if (iter != m_qmlLists.cend()) - return *iter; - else - return QQmlMetaType::listType(t); + return QQmlMetaType::listType(t); } QQmlMetaObject QQmlEnginePrivate::rawMetaObjectForType(int t) const @@ -2289,46 +2280,20 @@ QQmlPropertyCache *QQmlEnginePrivate::rawPropertyCacheForType(int t) void QQmlEnginePrivate::registerInternalCompositeType(QV4::CompiledData::CompilationUnit *compilationUnit) { - QByteArray name = compilationUnit->rootPropertyCache()->className(); - - QByteArray ptr = name + '*'; - QByteArray lst = "QQmlListProperty<" + name + '>'; - - int ptr_type = QMetaType::registerNormalizedType(ptr, - QtMetaTypePrivate::QMetaTypeFunctionHelper::Destruct, - QtMetaTypePrivate::QMetaTypeFunctionHelper::Construct, - sizeof(QObject*), - static_cast >(QtPrivate::QMetaTypeTypeFlags::Flags), - 0); - int lst_type = QMetaType::registerNormalizedType(lst, - QtMetaTypePrivate::QMetaTypeFunctionHelper >::Destruct, - QtMetaTypePrivate::QMetaTypeFunctionHelper >::Construct, - sizeof(QQmlListProperty), - static_cast >(QtPrivate::QMetaTypeTypeFlags >::Flags), - static_cast(0)); - - compilationUnit->metaTypeId = ptr_type; - compilationUnit->listMetaTypeId = lst_type; compilationUnit->isRegisteredWithEngine = true; Locker locker(this); - m_qmlLists.insert(lst_type, ptr_type); // The QQmlCompiledData is not referenced here, but it is removed from this // hash in the QQmlCompiledData destructor - m_compositeTypes.insert(ptr_type, compilationUnit); + m_compositeTypes.insert(compilationUnit->metaTypeId, compilationUnit); } void QQmlEnginePrivate::unregisterInternalCompositeType(QV4::CompiledData::CompilationUnit *compilationUnit) { - int ptr_type = compilationUnit->metaTypeId; - int lst_type = compilationUnit->listMetaTypeId; + compilationUnit->isRegisteredWithEngine = false; Locker locker(this); - m_qmlLists.remove(lst_type); - m_compositeTypes.remove(ptr_type); - - QMetaType::unregisterType(ptr_type); - QMetaType::unregisterType(lst_type); + m_compositeTypes.remove(compilationUnit->metaTypeId); } bool QQmlEnginePrivate::isTypeLoaded(const QUrl &url) const diff --git a/src/qml/qml/qqmlengine_p.h b/src/qml/qml/qqmlengine_p.h index 48c865abe5..da8ea24ea0 100644 --- a/src/qml/qml/qqmlengine_p.h +++ b/src/qml/qml/qqmlengine_p.h @@ -261,7 +261,6 @@ public: private: // 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 m_qmlLists; QHash m_compositeTypes; static bool s_designerMode; diff --git a/src/qml/qml/qqmlmetatype.cpp b/src/qml/qml/qqmlmetatype.cpp index efe6e1c3be..ca0522aa99 100644 --- a/src/qml/qml/qqmlmetatype.cpp +++ b/src/qml/qml/qqmlmetatype.cpp @@ -113,6 +113,8 @@ struct QQmlMetaTypeData QString typeRegistrationNamespace; QStringList typeRegistrationFailures; + QHash qmlLists; + QHash propertyCaches; QQmlPropertyCache *propertyCache(const QMetaObject *metaObject); QQmlPropertyCache *propertyCache(const QQmlType &type, int minorVersion); @@ -1552,6 +1554,47 @@ QQmlType QQmlMetaType::registerCompositeType(const QQmlPrivate::RegisterComposit return dtype; } +void QQmlMetaType::registerInternalCompositeType(QV4::CompiledData::CompilationUnit *compilationUnit) +{ + QByteArray name = compilationUnit->rootPropertyCache()->className(); + + QByteArray ptr = name + '*'; + QByteArray lst = "QQmlListProperty<" + name + '>'; + + int ptr_type = QMetaType::registerNormalizedType(ptr, + QtMetaTypePrivate::QMetaTypeFunctionHelper::Destruct, + QtMetaTypePrivate::QMetaTypeFunctionHelper::Construct, + sizeof(QObject*), + static_cast >(QtPrivate::QMetaTypeTypeFlags::Flags), + 0); + int lst_type = QMetaType::registerNormalizedType(lst, + QtMetaTypePrivate::QMetaTypeFunctionHelper >::Destruct, + QtMetaTypePrivate::QMetaTypeFunctionHelper >::Construct, + sizeof(QQmlListProperty), + static_cast >(QtPrivate::QMetaTypeTypeFlags >::Flags), + static_cast(0)); + + compilationUnit->metaTypeId = ptr_type; + compilationUnit->listMetaTypeId = lst_type; + + QMutexLocker lock(metaTypeDataLock()); + QQmlMetaTypeData *d = metaTypeData(); + d->qmlLists.insert(lst_type, ptr_type); +} + +void QQmlMetaType::unregisterInternalCompositeType(QV4::CompiledData::CompilationUnit *compilationUnit) +{ + int ptr_type = compilationUnit->metaTypeId; + int lst_type = compilationUnit->listMetaTypeId; + + QMutexLocker lock(metaTypeDataLock()); + QQmlMetaTypeData *d = metaTypeData(); + d->qmlLists.remove(lst_type); + + QMetaType::unregisterType(ptr_type); + QMetaType::unregisterType(lst_type); +} + int registerQmlUnitCacheHook(const QQmlPrivate::RegisterQmlUnitCacheHook &hookRegistration) { if (hookRegistration.version > 0) @@ -1764,6 +1807,9 @@ int QQmlMetaType::listType(int id) { QMutexLocker lock(metaTypeDataLock()); QQmlMetaTypeData *data = metaTypeData(); + QHash::ConstIterator iter = data->qmlLists.constFind(id); + if (iter != data->qmlLists.cend()) + return *iter; QQmlTypePrivate *type = data->idToType.value(id); if (type && type->listId == id) return type->typeId; @@ -1853,7 +1899,9 @@ QQmlMetaType::TypeCategory QQmlMetaType::typeCategory(int userType) QMutexLocker lock(metaTypeDataLock()); QQmlMetaTypeData *data = metaTypeData(); - if (userType < data->objects.size() && data->objects.testBit(userType)) + if (data->qmlLists.contains(userType)) + return List; + else if (userType < data->objects.size() && data->objects.testBit(userType)) return Object; else if (userType < data->lists.size() && data->lists.testBit(userType)) return List; @@ -1884,6 +1932,8 @@ bool QQmlMetaType::isList(int userType) { QMutexLocker lock(metaTypeDataLock()); QQmlMetaTypeData *data = metaTypeData(); + if (data->qmlLists.contains(userType)) + return true; return userType >= 0 && userType < data->lists.size() && data->lists.testBit(userType); } diff --git a/src/qml/qml/qqmlmetatype_p.h b/src/qml/qml/qqmlmetatype_p.h index c0fbdd5060..ac2133ba30 100644 --- a/src/qml/qml/qqmlmetatype_p.h +++ b/src/qml/qml/qqmlmetatype_p.h @@ -71,6 +71,7 @@ class QHashedString; class QHashedStringRef; class QMutex; class QQmlPropertyCache; +class QQmlCompiledData; namespace QV4 { struct String; } @@ -80,6 +81,9 @@ public: static QQmlType registerCompositeSingletonType(const QQmlPrivate::RegisterCompositeSingletonType &type); static QQmlType registerCompositeType(const QQmlPrivate::RegisterCompositeType &type); + static void registerInternalCompositeType(QV4::CompiledData::CompilationUnit *compilationUnit); + static void unregisterInternalCompositeType(QV4::CompiledData::CompilationUnit *compilationUnit); + static QList qmlTypeNames(); static QList qmlTypes(); static QList qmlSingletonTypes(); -- cgit v1.2.3 From d28e7e47e0ddcbb889ced731f8666996caf045b1 Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Mon, 26 Jun 2017 11:49:34 +0200 Subject: Fix void * usage in our internal APIs Task-number: QTBUG-61536 Change-Id: Ia2b5cfeab093d8be91728032528788dd238c2872 Reviewed-by: Simon Hausmann --- src/qml/qml/qqmlimport.cpp | 3 ++- src/qml/qml/qqmltypenamecache.cpp | 32 ++++++++++------------ src/qml/qml/qqmltypenamecache_p.h | 57 +++++++++++++++++++-------------------- src/qml/qml/qqmltypewrapper.cpp | 2 +- src/qml/qml/qqmltypewrapper_p.h | 4 +-- 5 files changed, 46 insertions(+), 52 deletions(-) (limited to 'src/qml/qml') diff --git a/src/qml/qml/qqmlimport.cpp b/src/qml/qml/qqmlimport.cpp index e197efe72b..0bd7317470 100644 --- a/src/qml/qml/qqmlimport.cpp +++ b/src/qml/qml/qqmlimport.cpp @@ -420,13 +420,14 @@ void QQmlImports::populateCache(QQmlTypeNameCache *cache) const const QQmlImportNamespace &set = *ns; // positioning is important; we must create the namespace even if there is no module. - QQmlTypeNameCache::Import &typeimport = cache->m_namedImports[set.prefix]; + QQmlImportRef &typeimport = cache->m_namedImports[set.prefix]; typeimport.m_qualifier = set.prefix; for (int ii = set.imports.count() - 1; ii >= 0; --ii) { const QQmlImportInstance *import = set.imports.at(ii); QQmlTypeModule *module = QQmlMetaType::typeModule(import->uri, import->majversion); if (module) { + QQmlImportRef &typeimport = cache->m_namedImports[set.prefix]; typeimport.modules.append(QQmlTypeModuleVersion(module, import->minversion)); } } diff --git a/src/qml/qml/qqmltypenamecache.cpp b/src/qml/qml/qqmltypenamecache.cpp index a8f55d2e48..72307c2800 100644 --- a/src/qml/qml/qqmltypenamecache.cpp +++ b/src/qml/qml/qqmltypenamecache.cpp @@ -55,7 +55,7 @@ QQmlTypeNameCache::~QQmlTypeNameCache() void QQmlTypeNameCache::add(const QHashedString &name, const QUrl &url, const QHashedString &nameSpace) { if (nameSpace.length() != 0) { - Import *i = m_namedImports.value(nameSpace); + QQmlImportRef *i = m_namedImports.value(nameSpace); Q_ASSERT(i != 0); i->compositeSingletons.insert(name, url); return; @@ -69,12 +69,12 @@ void QQmlTypeNameCache::add(const QHashedString &name, const QUrl &url, const QH void QQmlTypeNameCache::add(const QHashedString &name, int importedScriptIndex, const QHashedString &nameSpace) { - Import import; + QQmlImportRef import; import.scriptIndex = importedScriptIndex; import.m_qualifier = name; if (nameSpace.length() != 0) { - Import *i = m_namedImports.value(nameSpace); + QQmlImportRef *i = m_namedImports.value(nameSpace); Q_ASSERT(i != 0); m_namespacedImports[i].insert(name, import); return; @@ -112,22 +112,20 @@ QQmlTypeNameCache::Result QQmlTypeNameCache::query(const QHashedStringRef &name) } QQmlTypeNameCache::Result QQmlTypeNameCache::query(const QHashedStringRef &name, - const void *importNamespace) const + const QQmlImportRef *importNamespace) const { - Q_ASSERT(importNamespace); - const Import *i = static_cast(importNamespace); - Q_ASSERT(i->scriptIndex == -1); + Q_ASSERT(importNamespace && importNamespace->scriptIndex == -1); - Result result = typeSearch(i->modules, name); + Result result = typeSearch(importNamespace->modules, name); if (!result.isValid()) - result = query(i->compositeSingletons, name); + result = query(importNamespace->compositeSingletons, name); if (!result.isValid()) { // Look up types from the imports of this document // ### it would be nice if QQmlImports allowed us to resolve a namespace // first, and then types on it. - QString qualifiedTypeName = i->m_qualifier + QLatin1Char('.') + name.toString(); + QString qualifiedTypeName = importNamespace->m_qualifier + QLatin1Char('.') + name.toString(); QQmlImportNamespace *typeNamespace = 0; QList errors; QQmlType t; @@ -166,29 +164,27 @@ QQmlTypeNameCache::Result QQmlTypeNameCache::query(const QV4::String *name) cons return result; } -QQmlTypeNameCache::Result QQmlTypeNameCache::query(const QV4::String *name, const void *importNamespace) const +QQmlTypeNameCache::Result QQmlTypeNameCache::query(const QV4::String *name, const QQmlImportRef *importNamespace) const { - Q_ASSERT(importNamespace); - const Import *i = static_cast(importNamespace); - Q_ASSERT(i->scriptIndex == -1); + Q_ASSERT(importNamespace && importNamespace->scriptIndex == -1); - QMap >::const_iterator it = m_namespacedImports.constFind(i); + QMap >::const_iterator it = m_namespacedImports.constFind(importNamespace); if (it != m_namespacedImports.constEnd()) { Result r = query(*it, name); if (r.isValid()) return r; } - Result r = typeSearch(i->modules, name); + Result r = typeSearch(importNamespace->modules, name); if (!r.isValid()) - r = query(i->compositeSingletons, name); + r = query(importNamespace->compositeSingletons, name); if (!r.isValid()) { // Look up types from the imports of this document // ### it would be nice if QQmlImports allowed us to resolve a namespace // first, and then types on it. - QString qualifiedTypeName = i->m_qualifier + QLatin1Char('.') + name->toQStringNoThrow(); + QString qualifiedTypeName = importNamespace->m_qualifier + QLatin1Char('.') + name->toQStringNoThrow(); QQmlImportNamespace *typeNamespace = 0; QList errors; QQmlType t; diff --git a/src/qml/qml/qqmltypenamecache_p.h b/src/qml/qml/qqmltypenamecache_p.h index 0705166ec2..7e2cbec4b5 100644 --- a/src/qml/qml/qqmltypenamecache_p.h +++ b/src/qml/qml/qqmltypenamecache_p.h @@ -62,6 +62,23 @@ QT_BEGIN_NAMESPACE +struct QQmlImportRef { + inline QQmlImportRef() + : scriptIndex(-1) + {} + // Imported module + QVector modules; + + // Or, imported script + int scriptIndex; + + // Or, imported compositeSingletons + QStringHash compositeSingletons; + + // The qualifier of this import + QString m_qualifier; +}; + class QQmlType; class QQmlEngine; class QQmlTypeNameCache : public QQmlRefCount @@ -77,7 +94,7 @@ public: struct Result { inline Result(); - inline Result(const void *importNamespace); + inline Result(const QQmlImportRef *importNamespace); inline Result(const QQmlType &type); inline Result(int scriptIndex); inline Result(const Result &); @@ -85,42 +102,27 @@ public: inline bool isValid() const; QQmlType type; - const void *importNamespace; + const QQmlImportRef *importNamespace; int scriptIndex; }; Result query(const QHashedStringRef &) const; - Result query(const QHashedStringRef &, const void *importNamespace) const; + Result query(const QHashedStringRef &, const QQmlImportRef *importNamespace) const; Result query(const QV4::String *) const; - Result query(const QV4::String *, const void *importNamespace) const; + Result query(const QV4::String *, const QQmlImportRef *importNamespace) const; private: friend class QQmlImports; - struct Import { - inline Import(); - // Imported module - QVector modules; - - // Or, imported script - int scriptIndex; - - // Or, imported compositeSingletons - QStringHash compositeSingletons; - - // The qualifier of this import - QString m_qualifier; - }; - template - Result query(const QStringHash &imports, Key key) const + Result query(const QStringHash &imports, Key key) const { - Import *i = imports.value(key); + QQmlImportRef *i = imports.value(key); if (i) { Q_ASSERT(!i->m_qualifier.isEmpty()); if (i->scriptIndex != -1) { return Result(i->scriptIndex); } else { - return Result(static_cast(i)); + return Result(i); } } @@ -152,8 +154,8 @@ private: return Result(); } - QStringHash m_namedImports; - QMap > m_namespacedImports; + QStringHash m_namedImports; + QMap > m_namespacedImports; QVector m_anonymousImports; QStringHash m_anonymousCompositeSingletons; QQmlImports m_imports; @@ -164,7 +166,7 @@ QQmlTypeNameCache::Result::Result() { } -QQmlTypeNameCache::Result::Result(const void *importNamespace) +QQmlTypeNameCache::Result::Result(const QQmlImportRef *importNamespace) : importNamespace(importNamespace), scriptIndex(-1) { } @@ -189,11 +191,6 @@ bool QQmlTypeNameCache::Result::isValid() const return type.isValid() || importNamespace || scriptIndex != -1; } -QQmlTypeNameCache::Import::Import() -: scriptIndex(-1) -{ -} - bool QQmlTypeNameCache::isEmpty() const { return m_namedImports.isEmpty() && m_anonymousImports.isEmpty() diff --git a/src/qml/qml/qqmltypewrapper.cpp b/src/qml/qml/qqmltypewrapper.cpp index ba07b77c72..d4e1910a72 100644 --- a/src/qml/qml/qqmltypewrapper.cpp +++ b/src/qml/qml/qqmltypewrapper.cpp @@ -119,7 +119,7 @@ ReturnedValue QmlTypeWrapper::create(QV4::ExecutionEngine *engine, QObject *o, c // Returns a type wrapper for importNamespace (of t) on o. This allows nested resolution of a type in a // namespace. -ReturnedValue QmlTypeWrapper::create(QV4::ExecutionEngine *engine, QObject *o, QQmlTypeNameCache *t, const void *importNamespace, +ReturnedValue QmlTypeWrapper::create(QV4::ExecutionEngine *engine, QObject *o, QQmlTypeNameCache *t, const QQmlImportRef *importNamespace, Heap::QmlTypeWrapper::TypeNameMode mode) { Q_ASSERT(t); diff --git a/src/qml/qml/qqmltypewrapper_p.h b/src/qml/qml/qqmltypewrapper_p.h index c21a66424b..c06c485fb8 100644 --- a/src/qml/qml/qqmltypewrapper_p.h +++ b/src/qml/qml/qqmltypewrapper_p.h @@ -80,7 +80,7 @@ struct QmlTypeWrapper : Object { QQmlTypePrivate *typePrivate; QQmlTypeNameCache *typeNamespace; - const void *importNamespace; + const QQmlImportRef *importNamespace; }; } @@ -97,7 +97,7 @@ struct Q_QML_EXPORT QmlTypeWrapper : Object static ReturnedValue create(ExecutionEngine *, QObject *, const QQmlType &, Heap::QmlTypeWrapper::TypeNameMode = Heap::QmlTypeWrapper::IncludeEnums); - static ReturnedValue create(ExecutionEngine *, QObject *, QQmlTypeNameCache *, const void *, + static ReturnedValue create(ExecutionEngine *, QObject *, QQmlTypeNameCache *, const QQmlImportRef *, Heap::QmlTypeWrapper::TypeNameMode = Heap::QmlTypeWrapper::IncludeEnums); -- cgit v1.2.3 From a4be64a06c94765f995d49be00eb8fc9bed83958 Mon Sep 17 00:00:00 2001 From: Simon Hausmann Date: Thu, 29 Jun 2017 14:56:05 +0200 Subject: Reduce memory consumption of stat() cache in QML type loader The m_importDirCache caches the result of QDir/File::exists across paths. By changing the data structure to a QCache we impose a limit on the size of the entries and thus the memory consumption for long running programs that access many qml files. Task-number: QTBUG-61536 Change-Id: I20c4dc77260fe353c13da570b7e1bbd3f47d4b79 Reviewed-by: Lars Knoll --- src/qml/qml/qqmltypeloader.cpp | 40 ++++++++++++++++++---------------------- src/qml/qml/qqmltypeloader_p.h | 4 ++-- 2 files changed, 20 insertions(+), 24 deletions(-) (limited to 'src/qml/qml') diff --git a/src/qml/qml/qqmltypeloader.cpp b/src/qml/qml/qqmltypeloader.cpp index 2825e0d698..efa4ed2f79 100644 --- a/src/qml/qml/qqmltypeloader.cpp +++ b/src/qml/qml/qqmltypeloader.cpp @@ -1778,23 +1778,21 @@ QString QQmlTypeLoader::absoluteFilePath(const QString &path) #endif int lastSlash = path.lastIndexOf(QLatin1Char('/')); - QStringRef dirPath(&path, 0, lastSlash); + QString dirPath(path.left(lastSlash)); - StringSet **fileSet = m_importDirCache.value(QHashedStringRef(dirPath.constData(), dirPath.length())); - if (!fileSet) { - QHashedString dirPathString(dirPath.toString()); - bool exists = QDir(dirPathString).exists(); - QStringHash *files = exists ? new QStringHash : 0; - m_importDirCache.insert(dirPathString, files); - fileSet = m_importDirCache.value(dirPathString); + if (!m_importDirCache.contains(dirPath)) { + bool exists = QDir(dirPath).exists(); + QCache *entry = exists ? new QCache : 0; + m_importDirCache.insert(dirPath, entry); } - if (!(*fileSet)) + QCache *fileSet = m_importDirCache.object(dirPath); + if (!fileSet) return QString(); QString absoluteFilePath; - QHashedStringRef fileName(path.constData()+lastSlash+1, path.length()-lastSlash-1); + QString fileName(path.mid(lastSlash+1, path.length()-lastSlash-1)); - bool *value = (*fileSet)->value(fileName); + bool *value = fileSet->object(fileName); if (value) { if (*value) absoluteFilePath = path; @@ -1808,7 +1806,7 @@ QString QQmlTypeLoader::absoluteFilePath(const QString &path) #else exists = QFile::exists(path); #endif - (*fileSet)->insert(fileName.toString(), exists); + fileSet->insert(fileName, new bool(exists)); if (exists) absoluteFilePath = path; } @@ -1843,18 +1841,16 @@ bool QQmlTypeLoader::directoryExists(const QString &path) int length = path.length(); if (path.endsWith(QLatin1Char('/'))) --length; - QStringRef dirPath(&path, 0, length); + QString dirPath(path.left(length)); - StringSet **fileSet = m_importDirCache.value(QHashedStringRef(dirPath.constData(), dirPath.length())); - if (!fileSet) { - QHashedString dirPathString(dirPath.toString()); - bool exists = QDir(dirPathString).exists(); - QStringHash *files = exists ? new QStringHash : 0; - m_importDirCache.insert(dirPathString, files); - fileSet = m_importDirCache.value(dirPathString); + if (!m_importDirCache.contains(dirPath)) { + bool exists = QDir(dirPath).exists(); + QCache *files = exists ? new QCache : 0; + m_importDirCache.insert(dirPath, files); } - return (*fileSet); + QCache *fileSet = m_importDirCache.object(dirPath); + return fileSet != 0; } @@ -1938,7 +1934,7 @@ void QQmlTypeLoader::clearCache() (*iter)->release(); for (QmldirCache::Iterator iter = m_qmldirCache.begin(), end = m_qmldirCache.end(); iter != end; ++iter) (*iter)->release(); - qDeleteAll(m_importDirCache); + qDeleteAll(m_importQmlDirCache); m_typeCache.clear(); diff --git a/src/qml/qml/qqmltypeloader_p.h b/src/qml/qml/qqmltypeloader_p.h index 762fcdac65..05923f77e8 100644 --- a/src/qml/qml/qqmltypeloader_p.h +++ b/src/qml/qml/qqmltypeloader_p.h @@ -55,6 +55,7 @@ #include #include #include +#include #if QT_CONFIG(qml_network) #include #endif @@ -362,8 +363,7 @@ private: typedef QHash TypeCache; typedef QHash ScriptCache; typedef QHash QmldirCache; - typedef QStringHash StringSet; - typedef QStringHash ImportDirCache; + typedef QCache > ImportDirCache; typedef QStringHash ImportQmlDirCache; QQmlEngine *m_engine; -- cgit v1.2.3 From 2aabfa28a5fa4a7a0a5c5f47872df19f84551fab Mon Sep 17 00:00:00 2001 From: Simon Hausmann Date: Thu, 20 Jul 2017 11:42:45 +0200 Subject: Avoid meta-object creation when looking up QML properties in the property cache When looking up QML properties in the property cache, we also need to verify that they should be visible in the QML context they are requested from, i.e. if the revision of the object in that context has the property visible or not. That requires retrieving the VME meta-object for QML declared properties. We can retrieve that directly from the QObjectPrivate instead of going through the potential meta-object builder creation path. Task-number: QTBUG-61536 Change-Id: I695921d625169de5c58941087464beb5367fb2db Reviewed-by: Lars Knoll --- src/qml/qml/qqmlpropertycache.cpp | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) (limited to 'src/qml/qml') diff --git a/src/qml/qml/qqmlpropertycache.cpp b/src/qml/qml/qqmlpropertycache.cpp index 9a495e6fa3..019fa654d1 100644 --- a/src/qml/qml/qqmlpropertycache.cpp +++ b/src/qml/qml/qqmlpropertycache.cpp @@ -764,7 +764,11 @@ void QQmlPropertyCache::invalidate(const QMetaObject *metaObject) QQmlPropertyData *QQmlPropertyCache::findProperty(StringCache::ConstIterator it, QObject *object, QQmlContextData *context) const { QQmlData *data = (object ? QQmlData::get(object) : 0); - const QQmlVMEMetaObject *vmemo = (data && data->hasVMEMetaObject ? static_cast(object->metaObject()) : 0); + const QQmlVMEMetaObject *vmemo = 0; + if (data && data->hasVMEMetaObject) { + QObjectPrivate *op = QObjectPrivate::get(object); + vmemo = static_cast(op->metaObject); + } return findProperty(it, vmemo, context); } @@ -808,9 +812,9 @@ QQmlPropertyData *QQmlPropertyCache::findProperty(StringCache::ConstIterator it, } if (vmemo) { - const int methodCount = vmemo->methodCount(); - const int signalCount = vmemo->signalCount(); - const int propertyCount = vmemo->propertyCount(); + const int methodCount = vmemo->cache->methodCount(); + const int signalCount = vmemo->cache->signalCount(); + const int propertyCount = vmemo->cache->propertyCount(); // Ensure that the property we resolve to is accessible from this meta-object do { -- cgit v1.2.3