From e3adfe617511f6a6284674108816badabd0ffecf Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Thu, 19 Oct 2023 14:29:41 +0200 Subject: 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 --- src/qml/qml/qqmlvmemetaobject.cpp | 71 +++++++++++++++++++++++++++------------ 1 file changed, 49 insertions(+), 22 deletions(-) (limited to 'src/qml/qml/qqmlvmemetaobject.cpp') 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 *prop) if (auto *md = static_cast( m_metaObject->propertyAndMethodStorage.asManaged())) { - const auto *v = (md->data() + m_id)->as(); - Q_ASSERT(v); - Q_ASSERT(v->d()); - QVariant &data = v->d()->data(); - Q_ASSERT(data.userType() == qMetaTypeId>>()); - m_list = static_cast> *>(data.data()); + const QV4::Value *v = md->data() + m_id; + Q_ASSERT(v->as()); + m_list = static_cast(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::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 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 *prop, QObject *o) { const QQmlVMEResolvedList resolved(prop); - resolved.list()->append(o); + resolved.append(o); resolved.activateSignal(); } void QQmlVMEMetaObject::list_append_nosignal(QQmlListProperty *prop, QObject *o) { - QQmlVMEResolvedList(prop).list()->append(o); + QQmlVMEResolvedList(prop).append(o); } static qsizetype list_count(QQmlListProperty *prop) { - return QQmlVMEResolvedList(prop).list()->size(); + return QQmlVMEResolvedList(prop).size(); } static QObject *list_at(QQmlListProperty *prop, qsizetype index) { - return QQmlVMEResolvedList(prop).list()->at(index); + return QQmlVMEResolvedList(prop).at(index); } void QQmlVMEMetaObject::list_clear(QQmlListProperty *prop) { const QQmlVMEResolvedList resolved(prop); - resolved.list()->clear(); + resolved.clear(); resolved.activateSignal(); } void QQmlVMEMetaObject::list_clear_nosignal(QQmlListProperty *prop) { - QQmlVMEResolvedList(prop).list()->clear(); + QQmlVMEResolvedList(prop).clear(); } static void list_replace(QQmlListProperty *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 *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> *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 v(scope, *(md->data() + id)); - if (!v || v->d()->data().metaType() != QMetaType::fromType>>()) { - const QVector> guards; - v = engine->newVariantObject(QMetaType::fromType>>(), &guards); + QV4::ScopedObject v(scope, *(md->data() + id)); + if (!v) { + v = engine->newObject(); + v->arrayCreate(); md->set(engine, id, v); } - return static_cast> *>(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 *>(a[0]) = QQmlListProperty( object, reinterpret_cast(quintptr(encodedIndex)), -- cgit v1.2.3