diff options
author | Ulf Hermann <ulf.hermann@qt.io> | 2023-10-19 13:11:56 +0200 |
---|---|---|
committer | Ulf Hermann <ulf.hermann@qt.io> | 2023-10-24 18:44:54 +0200 |
commit | 360b5091f35127164f8655d60a21702a92985b06 (patch) | |
tree | 7b8788c573463b69fb0754fa7050a2bb55af3719 /src/qml/qml/qqmllistwrapper.cpp | |
parent | 5fc4c09a958c5f78aa9f69cee2c45eef9a5166b8 (diff) |
QtQml: Use array data for QmlListWrapper's "owned" mode
We don't want to get surprised by QObjects being deleted while we're
still holding on to them. Also, we want to mark them when gc'ing and we
want to use the write barrier when replacing them. We already have an
array data since QmlListWrapper is an object. Let's use it.
Pick-to: 6.6 6.5
Task-number: QTBUG-117793
Change-Id: I921514bc2de994884c41bd6af19a7c2ac746cd92
Reviewed-by: Semih Yavuz <semih.yavuz@qt.io>
Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
Diffstat (limited to 'src/qml/qml/qqmllistwrapper.cpp')
-rw-r--r-- | src/qml/qml/qqmllistwrapper.cpp | 87 |
1 files changed, 77 insertions, 10 deletions
diff --git a/src/qml/qml/qqmllistwrapper.cpp b/src/qml/qml/qqmllistwrapper.cpp index 1fa3a8a75b..7102c4ee16 100644 --- a/src/qml/qml/qqmllistwrapper.cpp +++ b/src/qml/qml/qqmllistwrapper.cpp @@ -22,11 +22,81 @@ using namespace Qt::StringLiterals; DEFINE_OBJECT_VTABLE(QmlListWrapper); -static void setCustomArrayData(Heap::QmlListWrapper *d) +static void setArrayData(Heap::QmlListWrapper *d) { QV4::Scope scope(d->internalClass->engine); QV4::ScopedObject o(scope, d); - o->setArrayType(Heap::ArrayData::Custom); + o->arrayCreate(); +} + +struct ListWrapperObject +{ + QV4::Scope scope; + QV4::ScopedObject object; + + ListWrapperObject(QQmlListProperty<QObject> *p) + : scope(static_cast<Heap::QmlListWrapper *>(p->data)->internalClass->engine) + , object(scope, static_cast<Heap::QmlListWrapper *>(p->data)) + { + Q_ASSERT(object); + Q_ASSERT(object->arrayData()); + } + + Heap::ArrayData *arrayData() const + { + return object->arrayData(); + } +}; + +static void appendWrapped(QQmlListProperty<QObject> *p, QObject *o) +{ + ListWrapperObject object(p); + Heap::ArrayData *arrayData = object.arrayData(); + + const uint length = arrayData->length(); + if (Q_UNLIKELY(length == std::numeric_limits<uint>::max())) { + object.scope.engine->throwRangeError(QLatin1String("Too many elements.")); + return; + } + + ArrayData::realloc(object.object, Heap::ArrayData::Simple, length + 1, false); + arrayData->vtable()->put( + object.object, length, QV4::QObjectWrapper::wrap(object.scope.engine, o)); +} + +static qsizetype countWrapped(QQmlListProperty<QObject> *p) +{ + ListWrapperObject object(p); + return object.arrayData()->length(); +} + +static QObject *atWrapped(QQmlListProperty<QObject> *p, qsizetype i) +{ + ListWrapperObject object(p); + QV4::Scoped<QObjectWrapper> result(object.scope, object.arrayData()->get(i)); + return result ? result->object() : nullptr; +} + +static void clearWrapped(QQmlListProperty<QObject> *p) +{ + ListWrapperObject object(p); + object.arrayData()->vtable()->truncate(object.object, 0); +} + +static void replaceWrapped(QQmlListProperty<QObject> *p, qsizetype i, QObject *o) +{ + ListWrapperObject object(p); + object.arrayData()->vtable()->put( + object.object, i, QV4::QObjectWrapper::wrap(object.scope.engine, o)); +} + +static void removeLastWrapped(QQmlListProperty<QObject> *p) +{ + ListWrapperObject object(p); + Heap::ArrayData *arrayData = object.arrayData(); + const uint length = arrayData->length(); + if (length > 0) + arrayData->vtable()->truncate(object.object, length - 1); } void Heap::QmlListWrapper::init(QMetaType propertyType) @@ -34,9 +104,11 @@ void Heap::QmlListWrapper::init(QMetaType propertyType) Object::init(); m_object.init(); m_propertyType = propertyType.iface(); - m_ownData = new QObjectList; - *property() = QQmlListProperty<QObject>(nullptr, m_ownData); - setCustomArrayData(this); + setArrayData(this); + *property() = QQmlListProperty<QObject>( + nullptr, this, + appendWrapped, countWrapped, atWrapped, + clearWrapped, replaceWrapped, removeLastWrapped); } void Heap::QmlListWrapper::init(QObject *object, int propertyId, QMetaType propertyType) @@ -44,10 +116,8 @@ void Heap::QmlListWrapper::init(QObject *object, int propertyId, QMetaType prope Object::init(); m_object.init(object); m_propertyType = propertyType.iface(); - m_ownData = nullptr; void *args[] = { property(), nullptr }; QMetaObject::metacall(object, QMetaObject::ReadProperty, propertyId, args); - setCustomArrayData(this); } void Heap::QmlListWrapper::init( @@ -56,15 +126,12 @@ void Heap::QmlListWrapper::init( Object::init(); m_object.init(object); m_propertyType = propertyType.iface(); - m_ownData = nullptr; *property() = list; - setCustomArrayData(this); } void Heap::QmlListWrapper::destroy() { m_object.destroy(); - delete m_ownData; Object::destroy(); } |