aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml/qml/qqml.cpp
diff options
context:
space:
mode:
authorUlf Hermann <ulf.hermann@qt.io>2023-08-14 14:21:34 +0200
committerUlf Hermann <ulf.hermann@qt.io>2023-08-24 12:39:39 +0200
commitc86c13d491ec80cbdecba513959ca481a508cb72 (patch)
tree81aa463591d69d3e70e41664fbf8590ea4ee575c /src/qml/qml/qqml.cpp
parentbd9a8eb6dfdfb90f16739b7ec8bc5af4c79a2d65 (diff)
QtQml: Provide infrastructure for writing back lookups
Some of the "read" lookups we provide need to have a "write back" mode, too. It is just the inverse of the "read" operation. Task-number: QTBUG-116011 Change-Id: Icc5d5bed64a46abff06d052a56cfca9f18836d76 Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
Diffstat (limited to 'src/qml/qml/qqml.cpp')
-rw-r--r--src/qml/qml/qqml.cpp223
1 files changed, 180 insertions, 43 deletions
diff --git a/src/qml/qml/qqml.cpp b/src/qml/qml/qqml.cpp
index e7de0c85ca..0abd8ec261 100644
--- a/src/qml/qml/qqml.cpp
+++ b/src/qml/qml/qqml.cpp
@@ -883,57 +883,112 @@ static bool inherits(const QQmlPropertyCache *descendent, const QQmlPropertyCach
enum class ObjectPropertyResult { OK, NeedsInit, Deleted };
-template<bool StrictType = false>
-ObjectPropertyResult loadObjectProperty(
- QV4::Lookup *l, QObject *object, void *target, QQmlContextData *qmlContext)
+struct ObjectPropertyQmlData
+{
+ QQmlData *qmlData;
+ ObjectPropertyResult result;
+};
+
+template<bool StrictType>
+ObjectPropertyQmlData findObjectPropertyQmlData(QV4::Lookup *l, QObject *object)
{
QQmlData *qmlData = QQmlData::get(object);
if (!qmlData)
- return ObjectPropertyResult::NeedsInit;
+ return {qmlData, ObjectPropertyResult::NeedsInit};
if (qmlData->isQueuedForDeletion)
- return ObjectPropertyResult::Deleted;
+ return {qmlData, ObjectPropertyResult::Deleted};
Q_ASSERT(!QQmlData::wasDeleted(object));
const QQmlPropertyCache *propertyCache = l->qobjectLookup.propertyCache;
if (StrictType) {
if (qmlData->propertyCache.data() != propertyCache)
- return ObjectPropertyResult::NeedsInit;
+ return {qmlData, ObjectPropertyResult::NeedsInit};
} else if (!inherits(qmlData->propertyCache.data(), propertyCache)) {
- return ObjectPropertyResult::NeedsInit;
+ return {qmlData, ObjectPropertyResult::NeedsInit};
}
- const QQmlPropertyData *property = l->qobjectLookup.propertyData;
+ return {qmlData, ObjectPropertyResult::OK};
+}
- const int coreIndex = property->coreIndex();
- if (qmlData->hasPendingBindingBit(coreIndex))
- qmlData->flushPendingBinding(coreIndex);
+template<bool StrictType = false>
+ObjectPropertyResult loadObjectProperty(
+ QV4::Lookup *l, QObject *object, void *target, QQmlContextData *qmlContext)
+{
+ const ObjectPropertyQmlData data = findObjectPropertyQmlData<StrictType>(l, object);
+ if (data.result != ObjectPropertyResult::OK)
+ return data.result;
- captureObjectProperty(object, propertyCache, property, qmlContext);
- property->readProperty(object, target);
+ const QQmlPropertyData *propertyData = l->qobjectLookup.propertyData;
+ const int coreIndex = propertyData->coreIndex();
+ if (data.qmlData->hasPendingBindingBit(coreIndex))
+ data.qmlData->flushPendingBinding(coreIndex);
+
+ captureObjectProperty(object, l->qobjectLookup.propertyCache, propertyData, qmlContext);
+ propertyData->readProperty(object, target);
return ObjectPropertyResult::OK;
}
-static ObjectPropertyResult loadFallbackProperty(
- QV4::Lookup *l, QObject *object, void *target, QQmlContextData *qmlContext)
+template<bool StrictType = false>
+ObjectPropertyResult writeBackObjectProperty(QV4::Lookup *l, QObject *object, void *source)
+{
+ const ObjectPropertyQmlData data = findObjectPropertyQmlData<StrictType>(l, object);
+ if (data.result != ObjectPropertyResult::OK)
+ return data.result;
+
+ l->qobjectLookup.propertyData->writeProperty(object, source, {});
+ return ObjectPropertyResult::OK;
+}
+
+struct FallbackPropertyQmlData
+{
+ QQmlData *qmlData;
+ const QMetaObject *metaObject;
+ ObjectPropertyResult result;
+};
+
+static FallbackPropertyQmlData findFallbackPropertyQmlData(QV4::Lookup *l, QObject *object)
{
QQmlData *qmlData = QQmlData::get(object);
if (qmlData && qmlData->isQueuedForDeletion)
- return ObjectPropertyResult::Deleted;
+ return {qmlData, nullptr, ObjectPropertyResult::Deleted};
Q_ASSERT(!QQmlData::wasDeleted(object));
const QMetaObject *metaObject
= reinterpret_cast<const QMetaObject *>(l->qobjectFallbackLookup.metaObject - 1);
if (!metaObject || metaObject != object->metaObject())
- return ObjectPropertyResult::NeedsInit;
+ return {qmlData, nullptr, ObjectPropertyResult::NeedsInit};
+
+ return {qmlData, metaObject, ObjectPropertyResult::OK};
+}
+
+static ObjectPropertyResult loadFallbackProperty(
+ QV4::Lookup *l, QObject *object, void *target, QQmlContextData *qmlContext)
+{
+ const FallbackPropertyQmlData data = findFallbackPropertyQmlData(l, object);
+ if (data.result != ObjectPropertyResult::OK)
+ return data.result;
const int coreIndex = l->qobjectFallbackLookup.coreIndex;
- if (qmlData && qmlData->hasPendingBindingBit(coreIndex))
- qmlData->flushPendingBinding(coreIndex);
+ if (data.qmlData && data.qmlData->hasPendingBindingBit(coreIndex))
+ data.qmlData->flushPendingBinding(coreIndex);
captureFallbackProperty(object, coreIndex, l->qobjectFallbackLookup.notifyIndex,
l->qobjectFallbackLookup.isConstant, qmlContext);
void *a[] = { target, nullptr };
- metaObject->metacall(object, QMetaObject::ReadProperty, coreIndex, a);
+ data.metaObject->metacall(object, QMetaObject::ReadProperty, coreIndex, a);
+
+ return ObjectPropertyResult::OK;
+}
+
+static ObjectPropertyResult writeBackFallbackProperty(QV4::Lookup *l, QObject *object, void *source)
+{
+ const FallbackPropertyQmlData data = findFallbackPropertyQmlData(l, object);
+ if (data.result != ObjectPropertyResult::OK)
+ return data.result;
+
+ void *a[] = { source, nullptr };
+ data.metaObject->metacall(
+ object, QMetaObject::WriteProperty, l->qobjectFallbackLookup.coreIndex, a);
return ObjectPropertyResult::OK;
}
@@ -950,6 +1005,17 @@ ObjectPropertyResult loadObjectAsVariant(
return loadObjectProperty<true>(l, object, variant->data(), qmlContext);
}
+ObjectPropertyResult writeBackObjectAsVariant(QV4::Lookup *l, QObject *object, void *source)
+{
+ QVariant *variant = static_cast<QVariant *>(source);
+ const QMetaType propType = l->qobjectLookup.propertyData->propType();
+ if (propType == QMetaType::fromType<QVariant>())
+ return writeBackObjectProperty<true>(l, object, variant);
+
+ Q_ASSERT(variant->metaType() == propType);
+ return writeBackObjectProperty<true>(l, object, variant->data());
+}
+
ObjectPropertyResult loadFallbackAsVariant(
QV4::Lookup *l, QObject *object, void *target, QQmlContextData *qmlContext)
{
@@ -966,21 +1032,28 @@ ObjectPropertyResult loadFallbackAsVariant(
return loadFallbackProperty(l, object, variant->data(), qmlContext);
}
+ObjectPropertyResult writeBackFallbackAsVariant(QV4::Lookup *l, QObject *object, void *source)
+{
+ const QMetaObject *metaObject
+ = reinterpret_cast<const QMetaObject *>(l->qobjectFallbackLookup.metaObject - 1);
+ Q_ASSERT(metaObject);
+
+ QVariant *variant = static_cast<QVariant *>(source);
+ const QMetaType propType = metaObject->property(l->qobjectFallbackLookup.coreIndex).metaType();
+ if (propType == QMetaType::fromType<QVariant>())
+ return writeBackFallbackProperty(l, object, variant);
+
+ Q_ASSERT(variant->metaType() == propType);
+ return writeBackFallbackProperty(l, object, variant->data());
+}
+
template<bool StrictType, typename Op>
static ObjectPropertyResult changeObjectProperty(QV4::Lookup *l, QObject *object, Op op)
{
- const QQmlData *qmlData = QQmlData::get(object);
- if (!qmlData)
- return ObjectPropertyResult::NeedsInit;
- if (qmlData->isQueuedForDeletion)
- return ObjectPropertyResult::Deleted;
- Q_ASSERT(!QQmlData::wasDeleted(object));
- if (StrictType) {
- if (qmlData->propertyCache.data() != l->qobjectLookup.propertyCache)
- return ObjectPropertyResult::NeedsInit;
- } else if (!inherits(qmlData->propertyCache.data(), l->qobjectLookup.propertyCache)) {
- return ObjectPropertyResult::NeedsInit;
- }
+ const ObjectPropertyQmlData data = findObjectPropertyQmlData<StrictType>(l, object);
+ if (data.result != ObjectPropertyResult::OK)
+ return data.result;
+
const QQmlPropertyData *property = l->qobjectLookup.propertyData;
QQmlPropertyPrivate::removeBinding(object, QQmlPropertyIndex(property->coreIndex()));
op(property);
@@ -1006,20 +1079,14 @@ static ObjectPropertyResult storeObjectProperty(QV4::Lookup *l, QObject *object,
template<typename Op>
static ObjectPropertyResult changeFallbackProperty(QV4::Lookup *l, QObject *object, Op op)
{
- const QQmlData *qmlData = QQmlData::get(object);
- if (qmlData && qmlData->isQueuedForDeletion)
- return ObjectPropertyResult::Deleted;
- Q_ASSERT(!QQmlData::wasDeleted(object));
-
- const QMetaObject *metaObject
- = reinterpret_cast<const QMetaObject *>(l->qobjectFallbackLookup.metaObject - 1);
- if (!metaObject || metaObject != object->metaObject())
- return ObjectPropertyResult::NeedsInit;
+ const FallbackPropertyQmlData data = findFallbackPropertyQmlData(l, object);
+ if (data.result != ObjectPropertyResult::OK)
+ return data.result;
const int coreIndex = l->qobjectFallbackLookup.coreIndex;
QQmlPropertyPrivate::removeBinding(object, QQmlPropertyIndex(coreIndex));
- op(metaObject, coreIndex);
+ op(data.metaObject, coreIndex);
return ObjectPropertyResult::OK;
}
@@ -1698,6 +1765,29 @@ bool AOTCompiledContext::loadScopeObjectPropertyLookup(uint index, void *target)
Q_UNREACHABLE_RETURN(false);
}
+bool AOTCompiledContext::writeBackScopeObjectPropertyLookup(uint index, void *source) const
+{
+ QV4::Lookup *l = compilationUnit->runtimeLookups + index;
+
+ ObjectPropertyResult result = ObjectPropertyResult::NeedsInit;
+ if (l->qmlContextPropertyGetter == QV4::QQmlContextWrapper::lookupScopeObjectProperty)
+ result = writeBackObjectProperty(l, qmlScopeObject, source);
+ else if (l->qmlContextPropertyGetter == QV4::QQmlContextWrapper::lookupScopeFallbackProperty)
+ result = writeBackFallbackProperty(l, qmlScopeObject, source);
+ else
+ return false;
+
+ switch (result) {
+ case ObjectPropertyResult::NeedsInit:
+ return false;
+ case ObjectPropertyResult::Deleted: // Silently omit the write back. Same as interpreter
+ case ObjectPropertyResult::OK:
+ return true;
+ }
+
+ Q_UNREACHABLE_RETURN(false);
+}
+
void AOTCompiledContext::initLoadScopeObjectPropertyLookup(uint index, QMetaType type) const
{
QV4::ExecutionEngine *v4 = engine->handle();
@@ -1862,7 +1952,6 @@ void AOTCompiledContext::initLoadTypeLookup(uint index, uint importNamespace) co
bool AOTCompiledContext::getObjectLookup(uint index, QObject *object, void *target) const
{
-
QV4::Lookup *l = compilationUnit->runtimeLookups + index;
const auto doThrow = [&]() {
engine->handle()->throwTypeError(
@@ -1898,6 +1987,35 @@ bool AOTCompiledContext::getObjectLookup(uint index, QObject *object, void *targ
Q_UNREACHABLE_RETURN(false);
}
+bool AOTCompiledContext::writeBackObjectLookup(uint index, QObject *object, void *source) const
+{
+ QV4::Lookup *l = compilationUnit->runtimeLookups + index;
+ if (!object)
+ return true;
+
+ ObjectPropertyResult result = ObjectPropertyResult::NeedsInit;
+ if (l->getter == QV4::Lookup::getterQObject)
+ result = writeBackObjectProperty(l, object, source);
+ else if (l->getter == QV4::Lookup::getterFallback)
+ result = writeBackFallbackProperty(l, object, source);
+ else if (l->getter == QV4::Lookup::getterQObjectAsVariant)
+ result = writeBackObjectAsVariant(l, object, source);
+ else if (l->getter == QV4::Lookup::getterFallbackAsVariant)
+ result = writeBackFallbackAsVariant(l, object, source);
+ else
+ return false;
+
+ switch (result) {
+ case ObjectPropertyResult::NeedsInit:
+ return false;
+ case ObjectPropertyResult::Deleted: // Silently omit the write back
+ case ObjectPropertyResult::OK:
+ return true;
+ }
+
+ Q_UNREACHABLE_RETURN(false);
+}
+
void AOTCompiledContext::initGetObjectLookup(uint index, QObject *object, QMetaType type) const
{
QV4::ExecutionEngine *v4 = engine->handle();
@@ -1944,6 +2062,25 @@ bool AOTCompiledContext::getValueLookup(uint index, void *value, void *target) c
return true;
}
+bool AOTCompiledContext::writeBackValueLookup(uint index, void *value, void *source) const
+{
+ Q_ASSERT(value);
+
+ QV4::Lookup *l = compilationUnit->runtimeLookups + index;
+ if (l->getter != QV4::QQmlValueTypeWrapper::lookupGetter)
+ return false;
+
+ const QMetaObject *metaObject
+ = reinterpret_cast<const QMetaObject *>(l->qgadgetLookup.metaObject - 1);
+ Q_ASSERT(metaObject);
+
+ void *args[] = { source, nullptr };
+ metaObject->d.static_metacall(
+ reinterpret_cast<QObject*>(value), QMetaObject::WriteProperty,
+ l->qgadgetLookup.coreIndex, args);
+ return true;
+}
+
void AOTCompiledContext::initGetValueLookup(
uint index, const QMetaObject *metaObject, QMetaType type) const
{