aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml/jsruntime/qv4engine.cpp
diff options
context:
space:
mode:
authorUlf Hermann <ulf.hermann@qt.io>2021-03-11 11:07:58 +0100
committerUlf Hermann <ulf.hermann@qt.io>2021-03-13 10:08:48 +0100
commiteb2386a04260966c5d1f13941f7a10154e11625a (patch)
tree2bbe824419230c62de6d88f255f45819c757a62b /src/qml/jsruntime/qv4engine.cpp
parenta9c93e2716a097c637515aded49a3308e257204b (diff)
Optimize ExecutionEngine::metaTypeToJS()
We almost never need to construct a QVariant to do this. Constructing a QVariant is excessively expensive if you have something simple like an integer. This also fixes the unexpected "unwrapping" of variants when we pass them through QJSValue. [ChangeLog][QtQml][Important Behavior Changes] If you create a QJSValue from a nested QVariant (that is, a QVariant containing another QVariant), then, when retrieving its contents again, the outer variant is not unwrapped anymore. Rather, you get exactly the value you've passed in. Change-Id: I8c16eed4f13e8cfdeced0756eef593b3b8e84dd1 Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
Diffstat (limited to 'src/qml/jsruntime/qv4engine.cpp')
-rw-r--r--src/qml/jsruntime/qv4engine.cpp50
1 files changed, 32 insertions, 18 deletions
diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp
index 0c95950400..4897454cec 100644
--- a/src/qml/jsruntime/qv4engine.cpp
+++ b/src/qml/jsruntime/qv4engine.cpp
@@ -1722,12 +1722,18 @@ static QVariant objectToVariant(QV4::ExecutionEngine *e, const QV4::Object *o, V
return result;
}
-QV4::ReturnedValue QV4::ExecutionEngine::fromVariant(const QVariant &variant)
-{
- const QMetaType metaType = variant.metaType();
- int type = metaType.id();
- const void *ptr = variant.constData();
-
+/*!
+ \internal
+
+ Transform the given \a metaType and \a ptr into a JavaScript representation. You can pass an
+ optional \a variant in order to avoid the construction of a new QVariant in case the value
+ has to be stored as a variant object. In that case, the contents of \a variant have to be
+ exactly the same as \a metaType and \a ptr.
+ */
+QV4::ReturnedValue ExecutionEngine::fromData(
+ const QMetaType &metaType, const void *ptr, const QVariant *variant)
+{
+ const int type = metaType.id();
if (type < QMetaType::User) {
switch (QMetaType::Type(type)) {
case QMetaType::UnknownType:
@@ -1783,7 +1789,8 @@ QV4::ReturnedValue QV4::ExecutionEngine::fromVariant(const QVariant &variant)
{
bool succeeded = false;
QV4::Scope scope(this);
- QV4::ScopedValue retn(scope, QV4::SequencePrototype::fromVariant(this, variant, &succeeded));
+ QV4::ScopedValue retn(
+ scope, QV4::SequencePrototype::fromData(this, metaType, ptr, &succeeded));
if (succeeded)
return retn->asReturnedValue();
return QV4::Encode(newArrayObject(*reinterpret_cast<const QStringList *>(ptr)));
@@ -1806,13 +1813,13 @@ QV4::ReturnedValue QV4::ExecutionEngine::fromVariant(const QVariant &variant)
case QMetaType::QPixmap:
case QMetaType::QImage:
// Scarce value types
- return QV4::Encode(newVariantObject(variant));
+ return QV4::Encode(newVariantObject(variant ? *variant : QVariant(metaType, ptr)));
default:
break;
}
if (const QMetaObject *vtmo = QQmlMetaType::metaObjectForMetaType(metaType))
- return QV4::QQmlValueTypeWrapper::create(this, variant, vtmo, metaType);
+ return QV4::QQmlValueTypeWrapper::create(this, ptr, vtmo, metaType);
} else {
QV4::Scope scope(this);
if (type == qMetaTypeId<QQmlListReference>()) {
@@ -1852,25 +1859,32 @@ QV4::ReturnedValue QV4::ExecutionEngine::fromVariant(const QVariant &variant)
#if QT_CONFIG(qml_sequence_object)
bool succeeded = false;
- QV4::ScopedValue retn(scope, QV4::SequencePrototype::fromVariant(this, variant, &succeeded));
+ QV4::ScopedValue retn(scope, QV4::SequencePrototype::fromData(this, metaType, ptr, &succeeded));
if (succeeded)
return retn->asReturnedValue();
#endif
- if (QMetaType::canConvert(variant.metaType(), QMetaType::fromType<QSequentialIterable>())) {
- QSequentialIterable lst = variant.value<QSequentialIterable>();
+
+ if (QMetaType::canConvert(metaType, QMetaType::fromType<QSequentialIterable>())) {
+ QSequentialIterable lst;
+ QMetaType::convert(metaType, ptr, QMetaType::fromType<QSequentialIterable>(), &lst);
return sequentialIterableToJS(this, lst);
}
if (const QMetaObject *vtmo = QQmlMetaType::metaObjectForMetaType(metaType))
- return QV4::QQmlValueTypeWrapper::create(this, variant, vtmo, metaType);
+ return QV4::QQmlValueTypeWrapper::create(this, ptr, vtmo, metaType);
}
// XXX TODO: To be compatible, we still need to handle:
// + QObjectList
// + QList<int>
- return QV4::Encode(newVariantObject(variant));
+ return QV4::Encode(newVariantObject(variant ? *variant : QVariant(metaType, ptr)));
+}
+
+QV4::ReturnedValue QV4::ExecutionEngine::fromVariant(const QVariant &variant)
+{
+ return fromData(variant.metaType(), variant.constData(), &variant);
}
QVariantMap ExecutionEngine::variantMapFromJS(const Object *o)
@@ -1940,13 +1954,13 @@ QV4::ReturnedValue ExecutionEngine::metaTypeToJS(QMetaType type, const void *dat
{
Q_ASSERT(data != nullptr);
- QVariant variant(type, data);
- if (QMetaType::Type(variant.userType()) == QMetaType::QVariant) {
+ if (type == QMetaType::fromType<QVariant>()) {
// unwrap it: this is tested in QJSEngine, and makes the most sense for
// end-user code too.
- return variantToJS(this, *reinterpret_cast<const QVariant*>(data));
+ return fromVariant(*reinterpret_cast<const QVariant*>(data));
}
- return fromVariant(variant);
+
+ return fromData(type, data);
}
int ExecutionEngine::maxJSStackSize() const