From 13ae2db97e6d7714fecffc4d65bb785a734fcd35 Mon Sep 17 00:00:00 2001 From: Matthew Vogt Date: Fri, 17 Aug 2012 11:10:10 +1000 Subject: Reduce memory consumption in QV4Bindings::Binding As with QV8Bindings::Binding, access details from the QML IR instruction object rather than storing a copy of the values. Change-Id: I2b629ee1b06ed74c7b38e6d047ef6a98acd45086 Reviewed-by: Martin Jones --- src/qml/qml/qqmlcompiler.cpp | 5 --- src/qml/qml/qqmlvme.cpp | 4 +-- src/qml/qml/v4/qv4bindings.cpp | 75 +++++++++++++++++++++--------------------- src/qml/qml/v4/qv4bindings_p.h | 34 +++++++++---------- 4 files changed, 54 insertions(+), 64 deletions(-) (limited to 'src/qml') diff --git a/src/qml/qml/qqmlcompiler.cpp b/src/qml/qml/qqmlcompiler.cpp index 808e63388f..3805e98802 100644 --- a/src/qml/qml/qqmlcompiler.cpp +++ b/src/qml/qml/qqmlcompiler.cpp @@ -3664,9 +3664,6 @@ bool QQmlCompiler::completeComponentBuild() bool needsFallback = false; int index = bindingCompiler.compile(expr, enginePrivate, &needsFallback); if (index != -1) { - // Ensure the index value fits within the available space - Q_ASSERT(index < (1 << 15)); - binding.dataType = BindingReference::V4; binding.compiledIndex = index; binding.sharedIndex = -1; @@ -3736,8 +3733,6 @@ bool QQmlCompiler::completeComponentBuild() functionArray += expression.toUtf8(); lineNumber += expression.count(QLatin1Char('\n')); - // Ensure the index value fits within the available space - Q_ASSERT(ii < (1 << 15)); reference->sharedIndex = ii; } functionArray.append("]", 1); diff --git a/src/qml/qml/qqmlvme.cpp b/src/qml/qml/qqmlvme.cpp index d6b60f724c..e565321eb9 100644 --- a/src/qml/qml/qqmlvme.cpp +++ b/src/qml/qml/qqmlvme.cpp @@ -846,9 +846,7 @@ QObject *QQmlVME::run(QList *errors, if (instr.isRoot && BINDINGSKIPLIST.testBit(propertyIdx)) QML_NEXT_INSTR(StoreV4Binding); - QQmlAbstractBinding *binding = - CTXT->v4bindings->configBinding(instr.value, instr.fallbackValue, target, scope, instr.property, - instr.propType, instr.line, instr.column); + QQmlAbstractBinding *binding = CTXT->v4bindings->configBinding(target, scope, &instr); bindValues.push(binding); binding->m_mePtr = &bindValues.top(); diff --git a/src/qml/qml/v4/qv4bindings.cpp b/src/qml/qml/v4/qv4bindings.cpp index 643a6197fb..fb484546a2 100644 --- a/src/qml/qml/v4/qv4bindings.cpp +++ b/src/qml/qml/v4/qv4bindings.cpp @@ -298,21 +298,14 @@ QV4Bindings::~QV4Bindings() delete [] subscriptions; subscriptions = 0; } -QQmlAbstractBinding *QV4Bindings::configBinding(int index, int fallbackIndex, QObject *target, QObject *scope, - int property, int propType, quint16 line, quint16 column) +QQmlAbstractBinding *QV4Bindings::configBinding(QObject *target, QObject *scope, + const QQmlInstruction::instr_assignV4Binding *i) { - Q_ASSERT(propType <= std::numeric_limits::max()); + Binding *rv = bindings + i->value; - Binding *rv = bindings + index; - - rv->index = index; - rv->fallbackIndex = fallbackIndex; - rv->property = property; - rv->propType = propType; + rv->instruction = i; rv->target = target; rv->scope = scope; - rv->line = line; - rv->column = column; rv->parent = this; addref(); // This is decremented in Binding::destroy() @@ -325,8 +318,8 @@ void QV4Bindings::Binding::setEnabled(QQmlAbstractBinding *_This, { QV4Bindings::Binding *This = static_cast(_This); - if (This->enabled != e) { - This->enabled = e; + if (This->enabledFlag() != e) { + This->setEnabledFlag(e); if (e) update(_This, flags); } @@ -342,7 +335,7 @@ void QV4Bindings::Binding::destroy(QQmlAbstractBinding *_This) { QV4Bindings::Binding *This = static_cast(_This); - This->enabled = false; + This->setEnabledFlag(false); This->removeFromObject(); This->clear(); This->removeError(); @@ -354,7 +347,7 @@ int QV4Bindings::Binding::propertyIndex(const QQmlAbstractBinding *_This) const QV4Bindings::Binding *This = static_cast(_This); if (This->target.hasValue()) return This->target.constValue()->targetProperty; - else return This->property; + else return This->instruction->property; } QObject *QV4Bindings::Binding::object(const QQmlAbstractBinding *_This) @@ -402,7 +395,7 @@ void QV4Bindings::subscriptionNotify(int id) void QV4Bindings::run(Binding *binding, QQmlPropertyPrivate::WriteFlags flags) { - if (!binding->enabled) + if (!binding->enabledFlag()) return; QQmlContextData *context = QQmlAbstractExpression::context(); @@ -415,62 +408,68 @@ void QV4Bindings::run(Binding *binding, QQmlPropertyPrivate::WriteFlags flags) QQmlTrace trace("V4 Binding Update"); trace.addDetail("URL", context->url); - trace.addDetail("Line", binding->line); - trace.addDetail("Column", binding->column); + trace.addDetail("Line", binding->instruction->line); + trace.addDetail("Column", binding->instruction->column); + + QQmlBindingProfiler prof(context->urlString, binding->instruction->line, binding->instruction->column, QQmlProfilerService::V4Binding); - QQmlBindingProfiler prof(context->urlString, binding->line, binding->column, QQmlProfilerService::V4Binding); + const int propType = binding->instruction->propType; + const int property = binding->instruction->property; - if (binding->updating) { + if (binding->updatingFlag()) { QString name; - if (binding->propType) { - QQmlValueType *vt = QQmlValueTypeFactory::valueType(binding->propType); + if (propType) { + QQmlValueType *vt = QQmlValueTypeFactory::valueType(propType); Q_ASSERT(vt); - name = QLatin1String(binding->target->metaObject()->property(binding->property & 0x0000FFFF).name()); + name = QLatin1String(binding->target->metaObject()->property(property & 0x0000FFFF).name()); name.append(QLatin1Char('.')); - name.append(QLatin1String(vt->metaObject()->property(binding->property >> 16).name())); + name.append(QLatin1String(vt->metaObject()->property(property >> 16).name())); } else { - name = QLatin1String(binding->target->metaObject()->property(binding->property).name()); + name = QLatin1String(binding->target->metaObject()->property(property).name()); } qmlInfo(*binding->target) << tr("Binding loop detected for property \"%1\"").arg(name); return; } + int index = binding->instruction->value; + int fallbackIndex = binding->instruction->fallbackValue; + bool invalidated = false; - bool *inv = (binding->fallbackIndex != -1) ? &invalidated : 0; + bool *inv = (fallbackIndex != -1) ? &invalidated : 0; - binding->updating = true; - if (binding->propType) { - QQmlValueType *vt = QQmlValueTypeFactory::valueType(binding->propType); + binding->setUpdatingFlag(true); + if (propType) { + QQmlValueType *vt = QQmlValueTypeFactory::valueType(propType); Q_ASSERT(vt); - vt->read(*binding->target, binding->property & 0x0000FFFF); + vt->read(*binding->target, property & 0x0000FFFF); QObject *target = vt; - run(binding->index, binding->executedBlocks, context, binding, binding->scope, target, flags, inv); + run(index, binding->executedBlocks, context, binding, binding->scope, target, flags, inv); if (!invalidated) { - vt->write(*binding->target, binding->property & 0x0000FFFF, flags); + vt->write(*binding->target, property & 0x0000FFFF, flags); } } else { QQmlData *data = QQmlData::get(*binding->target); - QQmlPropertyData *propertyData = (data && data->propertyCache ? data->propertyCache->property(binding->property) : 0); + QQmlPropertyData *propertyData = (data && data->propertyCache ? data->propertyCache->property(property) : 0); if (propertyData && propertyData->isVarProperty()) { // We will allocate a V8 handle in this conversion/store v8::HandleScope handle_scope; v8::Context::Scope context_scope(QQmlEnginePrivate::get(context->engine)->v8engine()->context()); - run(binding->index, binding->executedBlocks, context, binding, binding->scope, *binding->target, flags, inv); + run(index, binding->executedBlocks, context, binding, binding->scope, *binding->target, flags, inv); } else { - run(binding->index, binding->executedBlocks, context, binding, binding->scope, *binding->target, flags, inv); + run(index, binding->executedBlocks, context, binding, binding->scope, *binding->target, flags, inv); } } - binding->updating = false; + binding->setUpdatingFlag(false); if (invalidated) { // This binding is no longer valid - fallback to V8 - Q_ASSERT(binding->fallbackIndex > -1); - QQmlAbstractBinding *b = QQmlPropertyPrivate::activateSharedBinding(context, binding->fallbackIndex, flags); + Q_ASSERT(fallbackIndex > -1); + QQmlAbstractBinding *b = QQmlPropertyPrivate::activateSharedBinding(context, fallbackIndex, flags); Q_ASSERT(b == binding); b->destroy(); } diff --git a/src/qml/qml/v4/qv4bindings_p.h b/src/qml/qml/v4/qv4bindings_p.h index eae5703c50..0553e575a5 100644 --- a/src/qml/qml/v4/qv4bindings_p.h +++ b/src/qml/qml/v4/qv4bindings_p.h @@ -55,6 +55,7 @@ #include "private/qqmlexpression_p.h" #include "private/qqmlbinding_p.h" +#include "private/qqmlinstruction_p.h" #include "private/qv4instruction_p.h" #include "private/qpointervaluepair_p.h" @@ -71,17 +72,16 @@ public: QV4Bindings(const char *program, QQmlContextData *context); virtual ~QV4Bindings(); - QQmlAbstractBinding *configBinding(int index, int fallbackIndex, QObject *target, - QObject *scope, int property, int propType, - quint16 line, quint16 column); + QQmlAbstractBinding *configBinding(QObject *target, QObject *scope, + const QQmlInstruction::instr_assignV4Binding *); #ifdef QML_THREADED_INTERPRETER static void **getDecodeInstrTable(); #endif struct Binding : public QQmlAbstractBinding, public QQmlDelayedError { - Binding() : QQmlAbstractBinding(V4), index(-1), fallbackIndex(-1), enabled(false), - updating(0), property(0), propType(0), scope(0), target(0), executedBlocks(0), parent(0) {} + Binding() + : QQmlAbstractBinding(V4), target(0), scope(0), instruction(0), executedBlocks(0), parent(0) {} // Inherited from QQmlAbstractBinding static void destroy(QQmlAbstractBinding *); @@ -96,23 +96,21 @@ public: int targetProperty; }; - int index:15; - int fallbackIndex:15; - bool enabled:1; - bool updating:1; + QPointerValuePair target; + QObject *scope; - // Encoding of property is: coreIndex | (valueTypeIndex << 16) - // propType and valueTypeIndex are only set if the property is a value type property - int property; - quint16 propType; + // To save memory, we store flags inside the instruction pointer. + // instruction.flag1: enabled + // instruction.flag2: updating + QFlagPointer instruction; - QObject *scope; - quint16 line; - quint16 column; - QPointerValuePair target; quint32 executedBlocks; - QV4Bindings *parent; + + inline bool enabledFlag() const { return instruction.flag(); } + inline void setEnabledFlag(bool v) { instruction.setFlagValue(v); } + inline bool updatingFlag() const { return instruction.flag2(); } + inline void setUpdatingFlag(bool v) { instruction.setFlag2Value(v); } }; private: -- cgit v1.2.3