aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFrank Meerkoetter <frank.meerkoetter@basyskom.com>2015-07-14 22:38:51 +0200
committerSimon Hausmann <simon.hausmann@theqtcompany.com>2015-08-18 20:25:19 +0000
commit7e61bc92a3dccbd4c04d0a69da950cfdc32e487b (patch)
treeb00ebc37e92a7ad2b252651d69edc285a7bb807f
parenta820a56eb5a8e4f21ca4a04efe816e40b5645cef (diff)
Store int/bool/double/string and sizef as QV4::Value in a Javascript array
This is the first patch in a series of patches removing the QQmlVMEVariant used for the storage of non-var properties. The overall goal is to reduce the memory usage of QML. The QQmlVMEVariant has a size of 8*sizeof(void*) + sizeof(int) which is quite an overhead for types such as int/bool or double. Change-Id: I301661d134724300942911a3d75258fe45356a7a Reviewed-by: Simon Hausmann <simon.hausmann@theqtcompany.com>
-rw-r--r--src/qml/qml/qqmlvmemetaobject.cpp185
-rw-r--r--src/qml/qml/qqmlvmemetaobject_p.h20
2 files changed, 189 insertions, 16 deletions
diff --git a/src/qml/qml/qqmlvmemetaobject.cpp b/src/qml/qml/qqmlvmemetaobject.cpp
index 9f02c905fc..5d8d5d0d54 100644
--- a/src/qml/qml/qqmlvmemetaobject.cpp
+++ b/src/qml/qml/qqmlvmemetaobject.cpp
@@ -516,7 +516,7 @@ QQmlVMEMetaObject::QQmlVMEMetaObject(QObject *obj,
: object(obj),
ctxt(QQmlData::get(obj, true)->outerContext), cache(cache), metaData(meta),
hasAssignedMetaObjectData(false), data(0), aliasEndpoints(0), firstVarPropertyIndex(-1),
- varPropertiesInitialized(false), interceptors(0), v8methods(0)
+ varPropertiesInitialized(false), propertiesInitialized(false), interceptors(0), v8methods(0)
{
QObjectPrivate *op = QObjectPrivate::get(obj);
@@ -583,6 +583,134 @@ QQmlVMEMetaObject::~QQmlVMEMetaObject()
qDeleteAll(varObjectGuards);
}
+void QQmlVMEMetaObject::writeProperty(int id, int v)
+{
+ if (!ensurePropertiesAllocated())
+ return;
+
+ QV4::Scope scope(properties.engine());
+ QV4::ScopedObject vp(scope, properties.value());
+ vp->putIndexed(id, QV4::Primitive::fromInt32(v));
+}
+
+void QQmlVMEMetaObject::writeProperty(int id, bool v)
+{
+ if (!ensurePropertiesAllocated())
+ return;
+
+ QV4::Scope scope(properties.engine());
+ QV4::ScopedObject vp(scope, properties.value());
+ vp->putIndexed(id, QV4::Primitive::fromBoolean(v));
+}
+
+void QQmlVMEMetaObject::writeProperty(int id, double v)
+{
+ if (!ensurePropertiesAllocated())
+ return;
+
+ QV4::Scope scope(properties.engine());
+ QV4::ScopedObject vp(scope, properties.value());
+ vp->putIndexed(id, QV4::Primitive::fromDouble(v));
+}
+
+void QQmlVMEMetaObject::writeProperty(int id, const QString& v)
+{
+ if (!ensurePropertiesAllocated())
+ return;
+
+ QV4::Scope scope(properties.engine());
+ QV4::ScopedObject vp(scope, properties.value());
+ QV4::ScopedValue s(scope, properties.engine()->newString(v));
+ vp->putIndexed(id, s);
+}
+
+void QQmlVMEMetaObject::writeProperty(int id, const QSizeF& v)
+{
+ if (!ensurePropertiesAllocated())
+ return;
+
+ QV4::Scope scope(properties.engine());
+ QV4::ScopedObject vp(scope, properties.value());
+ QV4::ScopedValue sv(scope, properties.engine()->newVariantObject(QVariant::fromValue(v)));
+ vp->putIndexed(id, sv);
+}
+
+int QQmlVMEMetaObject::readPropertyAsInt(int id)
+{
+ if (!ensurePropertiesAllocated())
+ return 0;
+
+ QV4::Scope scope(properties.engine());
+ QV4::ScopedObject vp(scope, properties.value());
+ QV4::ScopedValue sv(scope, vp->getIndexed(id));
+ if (!sv->isInt32()) {
+ writeProperty(id, int(0));
+ return 0;
+ }
+ return sv->integerValue();
+}
+
+bool QQmlVMEMetaObject::readPropertyAsBool(int id)
+{
+ if (!ensurePropertiesAllocated())
+ return false;
+
+ QV4::Scope scope(properties.engine());
+ QV4::ScopedObject vp(scope, properties.value());
+ QV4::ScopedValue sv(scope, vp->getIndexed(id));
+ if (!sv->isBoolean()) {
+ writeProperty(id, false);
+ return false;
+ }
+ return sv->booleanValue();
+}
+
+double QQmlVMEMetaObject::readPropertyAsDouble(int id)
+{
+ if (!ensurePropertiesAllocated())
+ return 0.0;
+
+ QV4::Scope scope(properties.engine());
+ QV4::ScopedObject vp(scope, properties.value());
+ QV4::ScopedValue sv(scope, vp->getIndexed(id));
+ if (!sv->isDouble()) {
+ writeProperty(id, 0.0);
+ return 0.0;
+ }
+ return sv->doubleValue();
+}
+
+QString QQmlVMEMetaObject::readPropertyAsString(int id)
+{
+ if (!ensurePropertiesAllocated())
+ return QString();
+
+ QV4::Scope scope(properties.engine());
+ QV4::ScopedObject vp(scope, properties.value());
+ QV4::ScopedValue sv(scope, vp->getIndexed(id));
+ if (!sv->isString()) {
+ writeProperty(id, QString());
+ return QString();
+ }
+ return sv->stringValue()->toQString();
+}
+
+QSizeF QQmlVMEMetaObject::readPropertyAsSizeF(int id)
+{
+ if (!ensurePropertiesAllocated())
+ return QSizeF();
+
+ QV4::Scope scope(properties.engine());
+ QV4::ScopedObject vp(scope, properties.value());
+ QV4::ScopedValue sv(scope, vp->getIndexed(id));
+ const QV4::VariantObject *v = sv->as<QV4::VariantObject>();
+ if (!v || v->d()->data.type() != QVariant::SizeF) {
+ writeProperty(id, QSizeF());
+ return QSizeF();
+ }
+ return v->d()->data.value<QSizeF>();
+}
+
int QQmlVMEMetaObject::metaCall(QMetaObject::Call c, int _id, void **a)
{
int id = _id;
@@ -689,16 +817,16 @@ int QQmlVMEMetaObject::metaCall(QMetaObject::Call c, int _id, void **a)
if (c == QMetaObject::ReadProperty) {
switch(t) {
case QVariant::Int:
- *reinterpret_cast<int *>(a[0]) = data[id].asInt();
+ *reinterpret_cast<int *>(a[0]) = readPropertyAsInt(id);
break;
case QVariant::Bool:
- *reinterpret_cast<bool *>(a[0]) = data[id].asBool();
+ *reinterpret_cast<bool *>(a[0]) = readPropertyAsBool(id);
break;
case QVariant::Double:
- *reinterpret_cast<double *>(a[0]) = data[id].asDouble();
+ *reinterpret_cast<double *>(a[0]) = readPropertyAsDouble(id);
break;
case QVariant::String:
- *reinterpret_cast<QString *>(a[0]) = data[id].asQString();
+ *reinterpret_cast<QString *>(a[0]) = readPropertyAsString(id);
break;
case QVariant::Url:
*reinterpret_cast<QUrl *>(a[0]) = data[id].asQUrl();
@@ -713,7 +841,7 @@ int QQmlVMEMetaObject::metaCall(QMetaObject::Call c, int _id, void **a)
*reinterpret_cast<QRectF *>(a[0]) = data[id].asQRectF();
break;
case QVariant::SizeF:
- *reinterpret_cast<QSizeF *>(a[0]) = data[id].asQSizeF();
+ *reinterpret_cast<QSizeF *>(a[0]) = readPropertyAsSizeF(id);
break;
case QVariant::PointF:
*reinterpret_cast<QPointF *>(a[0]) = data[id].asQPointF();
@@ -741,20 +869,20 @@ int QQmlVMEMetaObject::metaCall(QMetaObject::Call c, int _id, void **a)
switch(t) {
case QVariant::Int:
- needActivate = *reinterpret_cast<int *>(a[0]) != data[id].asInt();
- data[id].setValue(*reinterpret_cast<int *>(a[0]));
+ needActivate = *reinterpret_cast<int *>(a[0]) != readPropertyAsInt(id);
+ writeProperty(id, *reinterpret_cast<int *>(a[0]));
break;
case QVariant::Bool:
- needActivate = *reinterpret_cast<bool *>(a[0]) != data[id].asBool();
- data[id].setValue(*reinterpret_cast<bool *>(a[0]));
+ needActivate = *reinterpret_cast<bool *>(a[0]) != readPropertyAsBool(id);
+ writeProperty(id, *reinterpret_cast<bool *>(a[0]));
break;
case QVariant::Double:
- needActivate = *reinterpret_cast<double *>(a[0]) != data[id].asDouble();
- data[id].setValue(*reinterpret_cast<double *>(a[0]));
+ needActivate = *reinterpret_cast<double *>(a[0]) != readPropertyAsDouble(id);
+ writeProperty(id, *reinterpret_cast<double *>(a[0]));
break;
case QVariant::String:
- needActivate = *reinterpret_cast<QString *>(a[0]) != data[id].asQString();
- data[id].setValue(*reinterpret_cast<QString *>(a[0]));
+ needActivate = *reinterpret_cast<QString *>(a[0]) != readPropertyAsString(id);
+ writeProperty(id, *reinterpret_cast<QString *>(a[0]));
break;
case QVariant::Url:
needActivate = *reinterpret_cast<QUrl *>(a[0]) != data[id].asQUrl();
@@ -773,8 +901,8 @@ int QQmlVMEMetaObject::metaCall(QMetaObject::Call c, int _id, void **a)
data[id].setValue(*reinterpret_cast<QRectF *>(a[0]));
break;
case QVariant::SizeF:
- needActivate = *reinterpret_cast<QSizeF *>(a[0]) != data[id].asQSizeF();
- data[id].setValue(*reinterpret_cast<QSizeF *>(a[0]));
+ needActivate = *reinterpret_cast<QSizeF *>(a[0]) != readPropertyAsSizeF(id);
+ writeProperty(id, *reinterpret_cast<QSizeF *>(a[0]));
break;
case QVariant::PointF:
needActivate = *reinterpret_cast<QPointF *>(a[0]) != data[id].asQPointF();
@@ -1176,6 +1304,19 @@ bool QQmlVMEMetaObject::ensureVarPropertiesAllocated()
return !varProperties.isUndefined();
}
+bool QQmlVMEMetaObject::ensurePropertiesAllocated()
+{
+ if (!propertiesInitialized)
+ allocatePropertiesArray();
+
+ // in some situations, the QObject's v8object (and associated v8 data,
+ // such as the varProperties array) will have been cleaned up, but the
+ // QObject ptr will not yet have been deleted (eg, waiting on deleteLater).
+ // In this situation, the varProperties handle will be (and should remain)
+ // empty.
+ return !properties.isUndefined();
+}
+
void QQmlVMEMetaObject::ensureQObjectWrapper()
{
Q_ASSERT(ctxt && ctxt->engine);
@@ -1192,6 +1333,7 @@ void QQmlVMEMetaObject::mark(QV4::ExecutionEngine *e)
return;
varProperties.markOnce(e);
+ properties.markOnce(e);
// add references created by VMEVariant properties
int maxDataIdx = metaData->propertyCount - metaData->varPropertyCount;
@@ -1217,6 +1359,17 @@ void QQmlVMEMetaObject::allocateVarPropertiesArray()
varPropertiesInitialized = true;
}
+void QQmlVMEMetaObject::allocatePropertiesArray()
+{
+ QQmlEngine *qml = qmlEngine(object);
+ Q_ASSERT(qml);
+ QV4::ExecutionEngine *v4 = QV8Engine::getV4(qml->handle());
+ QV4::Scope scope(v4);
+ properties.set(scope.engine, v4->newArrayObject(metaData->propertyCount - metaData->varPropertyCount));
+ propertiesInitialized = true;
+}
+
+
bool QQmlVMEMetaObject::aliasTarget(int index, QObject **target, int *coreIndex, int *valueTypeIndex) const
{
Q_ASSERT(index >= propOffset() + metaData->propertyCount);
diff --git a/src/qml/qml/qqmlvmemetaobject_p.h b/src/qml/qml/qqmlvmemetaobject_p.h
index a320163f23..a87feec043 100644
--- a/src/qml/qml/qqmlvmemetaobject_p.h
+++ b/src/qml/qml/qqmlvmemetaobject_p.h
@@ -204,6 +204,26 @@ public:
inline void allocateVarPropertiesArray();
inline bool ensureVarPropertiesAllocated();
+ // temporary solution so I can experiment with storing
+ // properties in a JS array. Should be switched over to also
+ // use the 'varProperties' in the end.
+ QV4::WeakValue properties;
+ bool propertiesInitialized;
+ inline void allocatePropertiesArray();
+ inline bool ensurePropertiesAllocated();
+
+ int readPropertyAsInt(int id);
+ bool readPropertyAsBool(int id);
+ double readPropertyAsDouble(int id);
+ QString readPropertyAsString(int id);
+ QSizeF readPropertyAsSizeF(int id);
+
+ void writeProperty(int id, int v);
+ void writeProperty(int id, bool v);
+ void writeProperty(int id, double v);
+ void writeProperty(int id, const QString& v);
+ void writeProperty(int id, const QSizeF& v);
+
void ensureQObjectWrapper();
void mark(QV4::ExecutionEngine *e);