From b220a20552838fbafbbf126b9e50d148ae76518d Mon Sep 17 00:00:00 2001 From: Simon Hausmann Date: Fri, 10 Apr 2015 12:34:46 +0200 Subject: Speed up value type binding creation * Avoid calling QMetaType::construct/destruct(typeId, ...) as that requires repeated lookups in the type registry. Instead cache the constructor/destructor/etc. function addresses in the QQmlValueType singletons as QMetaType * Allocate memory for the gadget pointer lazily, to accommodate the common case of a value type binding by property reference. Change-Id: I98a3ac73453b8f80027c06401b4f29a9707949d2 Reviewed-by: Lars Knoll --- src/qml/qml/qqmlvaluetypewrapper.cpp | 76 ++++++++++++++++++++++-------------- 1 file changed, 46 insertions(+), 30 deletions(-) (limited to 'src/qml/qml/qqmlvaluetypewrapper.cpp') diff --git a/src/qml/qml/qqmlvaluetypewrapper.cpp b/src/qml/qml/qqmlvaluetypewrapper.cpp index d3a80f0ee2..90ffe0d525 100644 --- a/src/qml/qml/qqmlvaluetypewrapper.cpp +++ b/src/qml/qml/qqmlvaluetypewrapper.cpp @@ -79,27 +79,31 @@ using namespace QV4; Heap::QQmlValueTypeWrapper::QQmlValueTypeWrapper(ExecutionEngine *engine) : Heap::Object(engine) - , gadgetPtr(0) { } Heap::QQmlValueTypeWrapper::~QQmlValueTypeWrapper() { - if (gadgetPtr) - QMetaType::destroy(metaType, gadgetPtr); + if (gadgetPtr) { + valueType->metaType.destruct(gadgetPtr); + ::operator delete(gadgetPtr); + } } void Heap::QQmlValueTypeWrapper::setValue(const QVariant &value) const { - Q_ASSERT(metaType == value.userType()); - QMetaType::destruct(metaType, gadgetPtr); - QMetaType::construct(metaType, gadgetPtr, value.constData()); + Q_ASSERT(valueType->typeId == value.userType()); + if (gadgetPtr) + valueType->metaType.destruct(gadgetPtr); + if (!gadgetPtr) + gadgetPtr = ::operator new(valueType->metaType.sizeOf()); + valueType->metaType.construct(gadgetPtr, value.constData()); } QVariant Heap::QQmlValueTypeWrapper::toVariant() const { Q_ASSERT(gadgetPtr); - return QVariant(metaType, gadgetPtr); + return QVariant(valueType->typeId, gadgetPtr); } @@ -123,7 +127,7 @@ bool QQmlValueTypeReference::readReferenceValue() const QMetaObject::metacall(d()->object, QMetaObject::ReadProperty, d()->property, a); int variantReferenceType = variantReferenceValue.userType(); - if (variantReferenceType != d()->metaType) { + if (variantReferenceType != typeId()) { // This is a stale VariantReference. That is, the variant has been // overwritten with a different type in the meantime. // We need to modify this reference to the updated value type, if @@ -132,24 +136,27 @@ bool QQmlValueTypeReference::readReferenceValue() const QQmlPropertyCache *cache = 0; if (const QMetaObject *mo = QQmlValueTypeFactory::metaObjectForMetaType(variantReferenceType)) cache = QJSEnginePrivate::get(engine())->cache(mo); - if (d()->gadgetPtr) - QMetaType::destroy(d()->metaType, d()->gadgetPtr); - d()->gadgetPtr = 0; + if (d()->gadgetPtr) { + d()->valueType->metaType.destruct(d()->gadgetPtr); + ::operator delete(d()->gadgetPtr); + } + d()->gadgetPtr =0; d()->propertyCache = cache; - d()->metaType = variantReferenceType; - if (cache) { - d()->gadgetPtr = QMetaType::create(d()->metaType); - } else { + d()->valueType = QQmlValueTypeFactory::valueType(variantReferenceType); + if (!cache) return false; - } } else { return false; } } d()->setValue(variantReferenceValue); } else { + if (!d()->gadgetPtr) { + d()->gadgetPtr = ::operator new(d()->valueType->metaType.sizeOf()); + d()->valueType->metaType.construct(d()->gadgetPtr, 0); + } // value-type reference - void *args[] = { d()->gadget(), 0 }; + void *args[] = { d()->gadgetPtr, 0 }; QMetaObject::metacall(d()->object, QMetaObject::ReadProperty, d()->property, args); } return true; @@ -176,8 +183,8 @@ ReturnedValue QQmlValueTypeWrapper::create(ExecutionEngine *engine, QObject *obj r->setPrototype(proto); r->d()->object = object; r->d()->property = property; r->d()->propertyCache = QJSEnginePrivate::get(engine)->cache(metaObject); - r->d()->metaType = typeId; - r->d()->gadgetPtr = QMetaType::create(r->d()->metaType); + r->d()->valueType = QQmlValueTypeFactory::valueType(typeId); + r->d()->gadgetPtr = 0; return r->asReturnedValue(); } @@ -190,8 +197,8 @@ ReturnedValue QQmlValueTypeWrapper::create(ExecutionEngine *engine, const QVaria ScopedObject proto(scope, engine->qmlExtensions()->valueTypeWrapperPrototype); r->setPrototype(proto); r->d()->propertyCache = QJSEnginePrivate::get(engine)->cache(metaObject); - r->d()->metaType = typeId; - r->d()->gadgetPtr = QMetaType::create(r->d()->metaType); + r->d()->valueType = QQmlValueTypeFactory::valueType(typeId); + r->d()->gadgetPtr = 0; r->d()->setValue(value); return r->asReturnedValue(); } @@ -204,11 +211,15 @@ QVariant QQmlValueTypeWrapper::toVariant() const return d()->toVariant(); } -void QQmlValueTypeWrapper::toGadget(void *data) const +bool QQmlValueTypeWrapper::toGadget(void *data) const { - int typeId = d()->metaType; + if (const QQmlValueTypeReference *ref = as()) + if (!ref->readReferenceValue()) + return false; + const int typeId = d()->valueType->typeId; QMetaType::destruct(typeId, data); - QMetaType::construct(typeId, data, d()->gadget()); + QMetaType::construct(typeId, data, d()->gadgetPtr); + return true; } void QQmlValueTypeWrapper::destroy(Heap::Base *that) @@ -248,6 +259,11 @@ bool QQmlValueTypeWrapper::isEqual(const QVariant& value) return (value == d()->toVariant()); } +int QQmlValueTypeWrapper::typeId() const +{ + return d()->valueType->typeId; +} + ReturnedValue QQmlValueTypeWrapper::method_toString(CallContext *ctx) { Object *o = ctx->thisObject().asObject(); @@ -265,15 +281,15 @@ ReturnedValue QQmlValueTypeWrapper::method_toString(CallContext *ctx) // Prepare a buffer to pass to QMetaType::convert() QString convertResult; convertResult.~QString(); - if (QMetaType::convert(w->d()->gadgetPtr, w->d()->metaType, &convertResult, QMetaType::QString)) { + if (QMetaType::convert(w->d()->gadgetPtr, w->d()->valueType->typeId, &convertResult, QMetaType::QString)) { result = convertResult; } else { - result = QString::fromUtf8(QMetaType::typeName(w->d()->metaType)); + result = QString::fromUtf8(QMetaType::typeName(w->d()->valueType->typeId)); result += QLatin1Char('('); const QMetaObject *mo = w->d()->propertyCache->metaObject(); const int propCount = mo->propertyCount(); for (int i = 0; i < propCount; ++i) { - QVariant value = mo->property(i).readOnGadget(w->d()->gadget()); + QVariant value = mo->property(i).readOnGadget(w->d()->gadgetPtr); result += value.toString(); if (i < propCount - 1) result += QStringLiteral(", "); @@ -322,7 +338,7 @@ ReturnedValue QQmlValueTypeWrapper::get(Managed *m, String *name, bool *hasPrope int index = result->coreIndex; QQmlMetaObject::resolveGadgetMethodOrPropertyIndex(QMetaObject::ReadProperty, &metaObject, &index); - void *gadget = r->d()->gadget(); + void *gadget = r->d()->gadgetPtr; // These four types are the most common used by the value type wrappers VALUE_TYPE_LOAD(QMetaType::QReal, qreal, qreal); @@ -411,7 +427,7 @@ void QQmlValueTypeWrapper::put(Managed *m, String *name, const Value &value) if (property.isEnumType() && (QMetaType::Type)v.type() == QMetaType::Double) v = v.toInt(); - void *gadget = r->d()->gadget(); + void *gadget = r->d()->gadgetPtr; property.writeOnGadget(gadget, v); @@ -427,7 +443,7 @@ void QQmlValueTypeWrapper::put(Managed *m, String *name, const Value &value) } else { int flags = 0; int status = -1; - void *a[] = { r->d()->gadget(), 0, &status, &flags }; + void *a[] = { r->d()->gadgetPtr, 0, &status, &flags }; QMetaObject::metacall(reference->d()->object, QMetaObject::WriteProperty, reference->d()->property, a); } } -- cgit v1.2.3