aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml/qml/qqmlvmemetaobject.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/qml/qml/qqmlvmemetaobject.cpp')
-rw-r--r--src/qml/qml/qqmlvmemetaobject.cpp78
1 files changed, 66 insertions, 12 deletions
diff --git a/src/qml/qml/qqmlvmemetaobject.cpp b/src/qml/qml/qqmlvmemetaobject.cpp
index ecb86e2f10..aa9f4bc1bd 100644
--- a/src/qml/qml/qqmlvmemetaobject.cpp
+++ b/src/qml/qml/qqmlvmemetaobject.cpp
@@ -48,6 +48,7 @@
#include "qqmlcontext_p.h"
#include "qqmlbinding_p.h"
#include "qqmlpropertyvalueinterceptor_p.h"
+#include <qqmlinfo.h>
#include <private/qqmlglobal_p.h>
@@ -60,6 +61,8 @@
#include <private/qqmlpropertycachecreator_p.h>
#include <private/qqmlpropertycachemethodarguments_p.h>
+#include <climits> // for CHAR_BIT
+
QT_BEGIN_NAMESPACE
class ResolvedList
@@ -67,13 +70,22 @@ class ResolvedList
Q_DISABLE_COPY_MOVE(ResolvedList)
public:
- ResolvedList(QQmlListProperty<QObject> *prop) :
- m_metaObject(static_cast<QQmlVMEMetaObject *>(QObjectPrivate::get(prop->object)->metaObject)),
- m_id(quintptr(prop->data))
+ ResolvedList(QQmlListProperty<QObject> *prop)
{
+ // see QQmlVMEMetaObject::metaCall for how this was constructed
+ auto encodedIndex = quintptr(prop->data);
+ constexpr quintptr usableBits = sizeof(quintptr) * CHAR_BIT;
+ quintptr inheritanceDepth = encodedIndex >> (usableBits / 2);
+ m_id = encodedIndex & ((quintptr(1) << (usableBits / 2)) - 1);
+
+ // walk up to the correct meta object if necessary
+ auto mo = prop->object->metaObject();
+ while (inheritanceDepth--)
+ mo = mo->superClass();
+ m_metaObject = static_cast<QQmlVMEMetaObject *>(const_cast<QMetaObject *>(mo));
Q_ASSERT(m_metaObject);
+ Q_ASSERT( ::strstr(m_metaObject->property(m_metaObject->propOffset() + m_id).typeName(), "QQmlListProperty") );
Q_ASSERT(m_metaObject->object == prop->object);
- Q_ASSERT(m_id <= quintptr(std::numeric_limits<int>::max() - m_metaObject->methodOffset()));
// readPropertyAsList() with checks transformed into Q_ASSERT
// and without allocation.
@@ -136,6 +148,20 @@ static void list_clear(QQmlListProperty<QObject> *prop)
resolved.activateSignal();
}
+static void list_replace(QQmlListProperty<QObject> *prop, int index, QObject *o)
+{
+ const ResolvedList resolved(prop);
+ resolved.list()->replace(index, o);
+ resolved.activateSignal();
+}
+
+static void list_removeLast(QQmlListProperty<QObject> *prop)
+{
+ const ResolvedList resolved(prop);
+ resolved.list()->removeLast();
+ resolved.activateSignal();
+}
+
QQmlVMEVariantQObjectPtr::QQmlVMEVariantQObjectPtr()
: QQmlGuard<QObject>(nullptr), m_target(nullptr), m_index(-1)
{
@@ -289,11 +315,13 @@ bool QQmlInterceptorMetaObject::intercept(QMetaObject::Call c, int id, void **a)
continue;
const int valueIndex = vi->m_propertyIndex.valueTypeIndex();
- int type = QQmlData::get(object)->propertyCache->property(id)->propType();
+ const QQmlData *data = QQmlData::get(object);
+ const int type = data->propertyCache->property(id)->propType();
if (type != QMetaType::UnknownType) {
if (valueIndex != -1) {
- QQmlValueType *valueType = QQmlValueTypeFactory::valueType(type);
+ QQmlGadgetPtrWrapper *valueType = QQmlGadgetPtrWrapper::instance(
+ data->context->engine, type);
Q_ASSERT(valueType);
//
@@ -327,7 +355,7 @@ bool QQmlInterceptorMetaObject::intercept(QMetaObject::Call c, int id, void **a)
// (7) Issue the interceptor call with the new component value.
//
- QMetaProperty valueProp = valueType->metaObject()->property(valueIndex);
+ QMetaProperty valueProp = valueType->property(valueIndex);
QVariant newValue(type, a[0]);
valueType->read(object, id);
@@ -731,11 +759,37 @@ int QQmlVMEMetaObject::metaCall(QObject *o, QMetaObject::Call c, int _id, void *
break;
case QV4::CompiledData::BuiltinType::InvalidBuiltin:
if (property.isList) {
+ // when reading from the list, we need to find the correct MetaObject,
+ // namely this. However, obejct->metaObject might point to any MetaObject
+ // down the inheritance hierarchy, so we need to store how far we have
+ // to go down
+ // To do this, we encode the hierarchy depth together with the id of the
+ // property in a single quintptr, with the first half storing the depth
+ // and the second half storing the property id
+ auto mo = object->metaObject();
+ quintptr inheritanceDepth = 0u;
+ while (mo && mo != this) {
+ mo = mo->superClass();
+ ++inheritanceDepth;
+ }
+ constexpr quintptr usableBits = sizeof(quintptr) * CHAR_BIT;
+ if (Q_UNLIKELY(inheritanceDepth >= (quintptr(1) << quintptr(usableBits / 2u) ) )) {
+ qmlWarning(object) << "Too many objects in inheritance hierarchy for list property";
+ return -1;
+ }
+ if (Q_UNLIKELY(quintptr(id) >= (quintptr(1) << quintptr(usableBits / 2) ) )) {
+ qmlWarning(object) << "Too many properties in object for list property";
+ return -1;
+ }
+ quintptr encodedIndex = (inheritanceDepth << (usableBits/2)) + id;
+
+
readPropertyAsList(id); // Initializes if necessary
*static_cast<QQmlListProperty<QObject> *>(a[0])
= QQmlListProperty<QObject>(
- object, reinterpret_cast<void *>(quintptr(id)),
- list_append, list_count, list_at, list_clear);
+ object, reinterpret_cast<void *>(quintptr(encodedIndex)),
+ list_append, list_count, list_at,
+ list_clear, list_replace, list_removeLast);
} else {
*reinterpret_cast<QObject **>(a[0]) = readPropertyAsQObject(id);
}
@@ -879,9 +933,9 @@ int QQmlVMEMetaObject::metaCall(QObject *o, QMetaObject::Call c, int _id, void *
return -1;
const QQmlPropertyData *pd = targetDData->propertyCache->property(coreIndex);
// Value type property or deep alias
- QQmlValueType *valueType = QQmlValueTypeFactory::valueType(pd->propType());
+ QQmlGadgetPtrWrapper *valueType = QQmlGadgetPtrWrapper::instance(
+ ctxt->engine, pd->propType());
if (valueType) {
-
valueType->read(target, coreIndex);
int rv = QMetaObject::metacall(valueType, c, valueTypePropertyIndex, a);
@@ -1184,7 +1238,7 @@ void QQmlVMEMetaObject::ensureQObjectWrapper()
void QQmlVMEMetaObject::mark(QV4::MarkStack *markStack)
{
- if (engine != markStack->engine)
+ if (engine != markStack->engine())
return;
propertyAndMethodStorage.markOnce(markStack);