From: Frank Meerkoetter Date: Tue, 14 Jul 2015 20:38:51 +0000 (+0200) Subject: Store int/bool/double/string and sizef as QV4::Value in a Javascript array X-Git-Tag: v5.5.90+alpha1~61 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=7e61bc92a3dccbd4c04d0a69da950cfdc32e487b;p=platform%2Fupstream%2Fqtdeclarative.git 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 --- diff --git a/src/qml/qml/qqmlvmemetaobject.cpp b/src/qml/qml/qqmlvmemetaobject.cpp index 9f02c905f..5d8d5d0d5 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(); + if (!v || v->d()->data.type() != QVariant::SizeF) { + writeProperty(id, QSizeF()); + return QSizeF(); + } + return v->d()->data.value(); +} + 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(a[0]) = data[id].asInt(); + *reinterpret_cast(a[0]) = readPropertyAsInt(id); break; case QVariant::Bool: - *reinterpret_cast(a[0]) = data[id].asBool(); + *reinterpret_cast(a[0]) = readPropertyAsBool(id); break; case QVariant::Double: - *reinterpret_cast(a[0]) = data[id].asDouble(); + *reinterpret_cast(a[0]) = readPropertyAsDouble(id); break; case QVariant::String: - *reinterpret_cast(a[0]) = data[id].asQString(); + *reinterpret_cast(a[0]) = readPropertyAsString(id); break; case QVariant::Url: *reinterpret_cast(a[0]) = data[id].asQUrl(); @@ -713,7 +841,7 @@ int QQmlVMEMetaObject::metaCall(QMetaObject::Call c, int _id, void **a) *reinterpret_cast(a[0]) = data[id].asQRectF(); break; case QVariant::SizeF: - *reinterpret_cast(a[0]) = data[id].asQSizeF(); + *reinterpret_cast(a[0]) = readPropertyAsSizeF(id); break; case QVariant::PointF: *reinterpret_cast(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(a[0]) != data[id].asInt(); - data[id].setValue(*reinterpret_cast(a[0])); + needActivate = *reinterpret_cast(a[0]) != readPropertyAsInt(id); + writeProperty(id, *reinterpret_cast(a[0])); break; case QVariant::Bool: - needActivate = *reinterpret_cast(a[0]) != data[id].asBool(); - data[id].setValue(*reinterpret_cast(a[0])); + needActivate = *reinterpret_cast(a[0]) != readPropertyAsBool(id); + writeProperty(id, *reinterpret_cast(a[0])); break; case QVariant::Double: - needActivate = *reinterpret_cast(a[0]) != data[id].asDouble(); - data[id].setValue(*reinterpret_cast(a[0])); + needActivate = *reinterpret_cast(a[0]) != readPropertyAsDouble(id); + writeProperty(id, *reinterpret_cast(a[0])); break; case QVariant::String: - needActivate = *reinterpret_cast(a[0]) != data[id].asQString(); - data[id].setValue(*reinterpret_cast(a[0])); + needActivate = *reinterpret_cast(a[0]) != readPropertyAsString(id); + writeProperty(id, *reinterpret_cast(a[0])); break; case QVariant::Url: needActivate = *reinterpret_cast(a[0]) != data[id].asQUrl(); @@ -773,8 +901,8 @@ int QQmlVMEMetaObject::metaCall(QMetaObject::Call c, int _id, void **a) data[id].setValue(*reinterpret_cast(a[0])); break; case QVariant::SizeF: - needActivate = *reinterpret_cast(a[0]) != data[id].asQSizeF(); - data[id].setValue(*reinterpret_cast(a[0])); + needActivate = *reinterpret_cast(a[0]) != readPropertyAsSizeF(id); + writeProperty(id, *reinterpret_cast(a[0])); break; case QVariant::PointF: needActivate = *reinterpret_cast(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 a320163f2..a87feec04 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);