diff options
author | Ulf Hermann <ulf.hermann@qt.io> | 2023-10-19 14:29:41 +0200 |
---|---|---|
committer | Ulf Hermann <ulf.hermann@qt.io> | 2023-10-24 18:44:54 +0200 |
commit | e3adfe617511f6a6284674108816badabd0ffecf (patch) | |
tree | 80b9fdec53778d8e7ddba4ae4ffabb2acb9e3dec /src/qml/qml/qqmlvmemetaobject.cpp | |
parent | 360b5091f35127164f8655d60a21702a92985b06 (diff) |
QtQml: Do not gc objects stored in QML-declared list properties
To this end, store the lists in a somewhat more straight forward way. We
can just use a plain Object since that already has array data. The array
data will integrate with garbage collection as usual.
Pick-to: 6.6 6.5
Fixes: QTBUG-117793
Change-Id: Ia5455fe62c526d69864d5569cd954bad09d4e911
Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
Diffstat (limited to 'src/qml/qml/qqmlvmemetaobject.cpp')
-rw-r--r-- | src/qml/qml/qqmlvmemetaobject.cpp | 71 |
1 files changed, 49 insertions, 22 deletions
diff --git a/src/qml/qml/qqmlvmemetaobject.cpp b/src/qml/qml/qqmlvmemetaobject.cpp index 27b8af299f..8d524e2e5d 100644 --- a/src/qml/qml/qqmlvmemetaobject.cpp +++ b/src/qml/qml/qqmlvmemetaobject.cpp @@ -56,16 +56,44 @@ QQmlVMEResolvedList::QQmlVMEResolvedList(QQmlListProperty<QObject> *prop) if (auto *md = static_cast<QV4::MemberData *>( m_metaObject->propertyAndMethodStorage.asManaged())) { - const auto *v = (md->data() + m_id)->as<QV4::VariantObject>(); - Q_ASSERT(v); - Q_ASSERT(v->d()); - QVariant &data = v->d()->data(); - Q_ASSERT(data.userType() == qMetaTypeId<QVector<QQmlGuard<QObject>>>()); - m_list = static_cast<QVector<QQmlGuard<QObject>> *>(data.data()); + const QV4::Value *v = md->data() + m_id; + Q_ASSERT(v->as<QV4::Object>()); + m_list = static_cast<QV4::Heap::Object *>(v->heapObject()); Q_ASSERT(m_list); } } +void QQmlVMEResolvedList::append(QObject *o) const +{ + QV4::Scope scope(m_list->internalClass->engine); + QV4::Heap::ArrayData *arrayData = m_list->arrayData; + + const uint length = arrayData->length(); + if (Q_UNLIKELY(length == std::numeric_limits<uint>::max())) { + scope.engine->throwRangeError(QLatin1String("Too many elements.")); + return; + } + + QV4::ScopedObject object(scope, m_list); + QV4::ArrayData::realloc(object, QV4::Heap::ArrayData::Simple, length + 1, false); + arrayData->vtable()->put( + object, length, QV4::QObjectWrapper::wrap(scope.engine, o)); +} + +QObject *QQmlVMEResolvedList::at(qsizetype i) const +{ + QV4::Scope scope(m_list->internalClass->engine); + QV4::Scoped<QV4::QObjectWrapper> result(scope, m_list->arrayData->get(i)); + return result ? result->object() : nullptr; +} + +void QQmlVMEResolvedList::replace(qsizetype i, QObject *o) const +{ + QV4::Scope scope(m_list->internalClass->engine); + QV4::ScopedObject object(scope, m_list); + m_list->arrayData->vtable()->put(object, i, QV4::QObjectWrapper::wrap(scope.engine, o)); +} + QQmlVMEResolvedList::~QQmlVMEResolvedList() = default; void QQmlVMEResolvedList::activateSignal() const @@ -76,48 +104,48 @@ void QQmlVMEResolvedList::activateSignal() const void QQmlVMEMetaObject::list_append(QQmlListProperty<QObject> *prop, QObject *o) { const QQmlVMEResolvedList resolved(prop); - resolved.list()->append(o); + resolved.append(o); resolved.activateSignal(); } void QQmlVMEMetaObject::list_append_nosignal(QQmlListProperty<QObject> *prop, QObject *o) { - QQmlVMEResolvedList(prop).list()->append(o); + QQmlVMEResolvedList(prop).append(o); } static qsizetype list_count(QQmlListProperty<QObject> *prop) { - return QQmlVMEResolvedList(prop).list()->size(); + return QQmlVMEResolvedList(prop).size(); } static QObject *list_at(QQmlListProperty<QObject> *prop, qsizetype index) { - return QQmlVMEResolvedList(prop).list()->at(index); + return QQmlVMEResolvedList(prop).at(index); } void QQmlVMEMetaObject::list_clear(QQmlListProperty<QObject> *prop) { const QQmlVMEResolvedList resolved(prop); - resolved.list()->clear(); + resolved.clear(); resolved.activateSignal(); } void QQmlVMEMetaObject::list_clear_nosignal(QQmlListProperty<QObject> *prop) { - QQmlVMEResolvedList(prop).list()->clear(); + QQmlVMEResolvedList(prop).clear(); } static void list_replace(QQmlListProperty<QObject> *prop, qsizetype index, QObject *o) { const QQmlVMEResolvedList resolved(prop); - resolved.list()->replace(index, o); + resolved.replace(index, o); resolved.activateSignal(); } static void list_removeLast(QQmlListProperty<QObject> *prop) { const QQmlVMEResolvedList resolved(prop); - resolved.list()->removeLast(); + resolved.removeLast(); resolved.activateSignal(); } @@ -648,20 +676,19 @@ QObject* QQmlVMEMetaObject::readPropertyAsQObject(int id) const return wrapper->object(); } -QVector<QQmlGuard<QObject>> *QQmlVMEMetaObject::readPropertyAsList(int id) const +void QQmlVMEMetaObject::initPropertyAsList(int id) const { QV4::MemberData *md = propertyAndMethodStorageAsMemberData(); if (!md) - return nullptr; + return; QV4::Scope scope(engine); - QV4::Scoped<QV4::VariantObject> v(scope, *(md->data() + id)); - if (!v || v->d()->data().metaType() != QMetaType::fromType<QVector<QQmlGuard<QObject>>>()) { - const QVector<QQmlGuard<QObject>> guards; - v = engine->newVariantObject(QMetaType::fromType<QVector<QQmlGuard<QObject>>>(), &guards); + QV4::ScopedObject v(scope, *(md->data() + id)); + if (!v) { + v = engine->newObject(); + v->arrayCreate(); md->set(engine, id, v); } - return static_cast<QVector<QQmlGuard<QObject>> *>(v->d()->data().data()); } QRectF QQmlVMEMetaObject::readPropertyAsRectF(int id) const @@ -742,7 +769,7 @@ int QQmlVMEMetaObject::metaCall(QObject *o, QMetaObject::Call c, int _id, void * } quintptr encodedIndex = (inheritanceDepth << idBits) + id; - readPropertyAsList(id); // Initializes if necessary + initPropertyAsList(id); *static_cast<QQmlListProperty<QObject> *>(a[0]) = QQmlListProperty<QObject>( object, reinterpret_cast<void *>(quintptr(encodedIndex)), |