aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml/qml
diff options
context:
space:
mode:
authorMatthew Vogt <matthew.vogt@nokia.com>2012-06-04 14:43:38 +1000
committerQt by Nokia <qt-info@nokia.com>2012-07-09 01:36:23 +0200
commit49a3883e86b61d8facfeea9c43037d484cb50b92 (patch)
treeba1afdf6ddc3740f26c5e3c95cb2fffeb953abb4 /src/qml/qml
parent3095493a4ce4bec11b9381a3d1d23f17b313332c (diff)
Use V4 binding for non-final properties where possible
When a property referenced in a binding is not marked as final, do not automatically abort optimization. Instead generate both V4 and V8 binidngs, and only fall back to the V8 binding if necessary at run time. Change-Id: I1bcc7e2b495935c5d519a9a223f640c1972cdb4e Reviewed-by: Michael Brasser <michael.brasser@nokia.com>
Diffstat (limited to 'src/qml/qml')
-rw-r--r--src/qml/qml/qqmlcompiler.cpp41
-rw-r--r--src/qml/qml/qqmlcompiler_p.h3
-rw-r--r--src/qml/qml/qqmlinstruction_p.h2
-rw-r--r--src/qml/qml/qqmlproperty.cpp26
-rw-r--r--src/qml/qml/qqmlproperty_p.h2
-rw-r--r--src/qml/qml/qqmlpropertycache.cpp8
-rw-r--r--src/qml/qml/qqmlpropertycache_p.h44
-rw-r--r--src/qml/qml/qqmlvme.cpp4
-rw-r--r--src/qml/qml/v4/qv4bindings.cpp54
-rw-r--r--src/qml/qml/v4/qv4bindings_p.h13
-rw-r--r--src/qml/qml/v4/qv4compiler.cpp8
-rw-r--r--src/qml/qml/v4/qv4compiler_p.h2
-rw-r--r--src/qml/qml/v4/qv4compiler_p_p.h3
-rw-r--r--src/qml/qml/v4/qv4irbuilder.cpp37
-rw-r--r--src/qml/qml/v4/qv4irbuilder_p.h3
-rw-r--r--src/qml/qml/v8/qv8bindings.cpp3
-rw-r--r--src/qml/qml/v8/qv8bindings_p.h2
17 files changed, 181 insertions, 74 deletions
diff --git a/src/qml/qml/qqmlcompiler.cpp b/src/qml/qml/qqmlcompiler.cpp
index e17163528c..6f2792570f 100644
--- a/src/qml/qml/qqmlcompiler.cpp
+++ b/src/qml/qml/qqmlcompiler.cpp
@@ -3458,6 +3458,7 @@ void QQmlCompiler::genBindingAssignment(QQmlScript::Value *binding,
Instruction::StoreV4Binding store;
store.value = js.compiledIndex;
+ store.fallbackValue = js.sharedIndex;
store.context = js.bindingContext.stack;
store.owner = js.bindingContext.owner;
store.isAlias = prop->isAlias;
@@ -3473,11 +3474,18 @@ void QQmlCompiler::genBindingAssignment(QQmlScript::Value *binding,
store.line = binding->location.start.line;
store.column = binding->location.start.column;
output->addInstruction(store);
+
+ if (store.fallbackValue > -1) {
+ //also create v8 instruction (needed to properly configure the fallback v8 binding)
+ JSBindingReference &js = static_cast<JSBindingReference &>(*binding->bindingReference);
+ js.dataType = BindingReference::V8;
+ genBindingAssignment(binding, prop, obj, valueTypeProperty);
+ }
} else if (ref.dataType == BindingReference::V8) {
const JSBindingReference &js = static_cast<const JSBindingReference &>(ref);
Instruction::StoreV8Binding store;
- store.value = js.compiledIndex;
+ store.value = js.sharedIndex;
store.context = js.bindingContext.stack;
store.owner = js.bindingContext.owner;
store.isAlias = prop->isAlias;
@@ -3486,6 +3494,7 @@ void QQmlCompiler::genBindingAssignment(QQmlScript::Value *binding,
} else {
store.isRoot = (compileState->root == obj);
}
+ store.isFallback = js.compiledIndex > -1;
store.line = binding->location.start.line;
store.column = binding->location.start.column;
@@ -3514,6 +3523,7 @@ void QQmlCompiler::genBindingAssignment(QQmlScript::Value *binding,
} else {
store.isRoot = (compileState->root == obj);
}
+ store.isFallback = false;
Q_ASSERT(js.bindingContext.owner == 0 ||
(js.bindingContext.owner != 0 && valueTypeProperty));
@@ -3579,13 +3589,22 @@ bool QQmlCompiler::completeComponentBuild()
expr.property = binding.property;
expr.expression = binding.expression;
- int index = bindingCompiler.compile(expr, enginePrivate);
+ 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;
if (componentStats)
componentStats->componentStat.optimizedBindings.append(b->value->location);
- continue;
+
+ if (!needsFallback)
+ continue;
+
+ // Drop through. We need to create a V8 binding in case the V4 binding is invalidated
}
// Pre-rewrite the expression
@@ -3597,12 +3616,17 @@ bool QQmlCompiler::completeComponentBuild()
binding.rewrittenExpression = rewriteBinding(binding.expression.asAST(), expression, &isSharable);
if (isSharable && binding.property->type != qMetaTypeId<QQmlBinding*>()) {
- binding.dataType = BindingReference::V8;
sharedBindings.append(b);
- if (componentStats)
- componentStats->componentStat.sharedBindings.append(b->value->location);
+ if (!needsFallback) {
+ binding.dataType = BindingReference::V8;
+ binding.compiledIndex = -1;
+
+ if (componentStats)
+ componentStats->componentStat.sharedBindings.append(b->value->location);
+ }
} else {
+ Q_ASSERT(!needsFallback);
binding.dataType = BindingReference::QtScript;
if (componentStats)
@@ -3639,7 +3663,10 @@ bool QQmlCompiler::completeComponentBuild()
functionArray += expression.toUtf8();
lineNumber += expression.count(QLatin1Char('\n'));
- reference->compiledIndex = ii;
+
+ // 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/qqmlcompiler_p.h b/src/qml/qml/qqmlcompiler_p.h
index b919b53207..fc80ca9b6b 100644
--- a/src/qml/qml/qqmlcompiler_p.h
+++ b/src/qml/qml/qqmlcompiler_p.h
@@ -201,7 +201,8 @@ namespace QQmlCompilerTypes {
QQmlScript::Property *property;
QQmlScript::Value *value;
- int compiledIndex;
+ int compiledIndex:15;
+ int sharedIndex:15;
QString rewrittenExpression;
BindingContext bindingContext;
diff --git a/src/qml/qml/qqmlinstruction_p.h b/src/qml/qml/qqmlinstruction_p.h
index 8b7dc383f8..313aed137f 100644
--- a/src/qml/qml/qqmlinstruction_p.h
+++ b/src/qml/qml/qqmlinstruction_p.h
@@ -240,6 +240,7 @@ union QQmlInstruction
QML_INSTR_HEADER
unsigned int property;
int value;
+ int fallbackValue;
short context;
short owner;
bool isRoot;
@@ -255,6 +256,7 @@ union QQmlInstruction
short owner;
bool isRoot;
bool isAlias;
+ bool isFallback;
ushort line;
ushort column;
};
diff --git a/src/qml/qml/qqmlproperty.cpp b/src/qml/qml/qqmlproperty.cpp
index d0c2761373..132664ddb5 100644
--- a/src/qml/qml/qqmlproperty.cpp
+++ b/src/qml/qml/qqmlproperty.cpp
@@ -56,6 +56,7 @@
#include "qqmlvmemetaobject_p.h"
#include "qqmlexpression_p.h"
#include "qqmlvaluetypeproxybinding_p.h"
+#include <private/qv8bindings_p.h>
#include <QStringList>
#include <private/qmetaobject_p.h>
@@ -961,6 +962,31 @@ QQmlPropertyPrivate::setBindingNoEnable(QObject *object, int coreIndex, int valu
}
/*!
+ Activates a shared binding which was previously created but not added to the
+ object. This is needed when an optimized binding is invalidated.
+*/
+QQmlAbstractBinding *QQmlPropertyPrivate::activateSharedBinding(QQmlContextData *context,
+ int sharedIdx, WriteFlags flags)
+{
+ QQmlAbstractBinding *newBinding = 0;
+ newBinding = context->v8bindings->binding(sharedIdx);
+
+ if (!newBinding)
+ return newBinding;
+
+ // This binding now references the bindings object
+ context->v8bindings->addref();
+
+ QObject *object = newBinding->object();
+ int pi = newBinding->propertyIndex();
+
+ int core = pi & 0xFFFFFF;
+ int vt = (pi & 0xFF000000)?(pi >> 24):-1;
+
+ return setBinding(object, core, vt, newBinding, flags);
+}
+
+/*!
Returns the expression associated with this signal property, or 0 if no
signal expression exists.
*/
diff --git a/src/qml/qml/qqmlproperty_p.h b/src/qml/qml/qqmlproperty_p.h
index 36aa142677..0131e7e1a4 100644
--- a/src/qml/qml/qqmlproperty_p.h
+++ b/src/qml/qml/qqmlproperty_p.h
@@ -119,6 +119,8 @@ public:
static QQmlAbstractBinding *setBindingNoEnable(QObject *, int coreIndex,
int valueTypeIndex /* -1 */,
QQmlAbstractBinding *);
+ static QQmlAbstractBinding *activateSharedBinding(QQmlContextData *context,
+ int sharedIdx, WriteFlags flags);
static QQmlAbstractBinding *binding(QObject *, int coreIndex,
int valueTypeIndex /* -1 */);
diff --git a/src/qml/qml/qqmlpropertycache.cpp b/src/qml/qml/qqmlpropertycache.cpp
index d922b9942a..8570df78a1 100644
--- a/src/qml/qml/qqmlpropertycache.cpp
+++ b/src/qml/qml/qqmlpropertycache.cpp
@@ -347,6 +347,7 @@ void QQmlPropertyCache::appendProperty(const QString &name,
if (QQmlPropertyData **old = stringCache.value(string)) {
data.overrideIndexIsProperty = !(*old)->isFunction();
data.overrideIndex = (*old)->coreIndex;
+ (*old)->flags |= QQmlPropertyData::IsOverridden;
}
propertyIndexCache.append(data);
@@ -366,6 +367,7 @@ void QQmlPropertyCache::appendProperty(const QHashedCStringRef &name,
if (QQmlPropertyData **old = stringCache.value(name)) {
data.overrideIndexIsProperty = !(*old)->isFunction();
data.overrideIndex = (*old)->coreIndex;
+ (*old)->flags |= QQmlPropertyData::IsOverridden;
}
propertyIndexCache.append(data);
@@ -403,6 +405,7 @@ void QQmlPropertyCache::appendSignal(const QString &name, quint32 flags, int cor
if (QQmlPropertyData **old = stringCache.value(string)) {
data.overrideIndexIsProperty = !(*old)->isFunction();
data.overrideIndex = (*old)->coreIndex;
+ (*old)->flags |= QQmlPropertyData::IsOverridden;
}
methodIndexCache.append(data);
@@ -441,6 +444,7 @@ void QQmlPropertyCache::appendSignal(const QHashedCStringRef &name, quint32 flag
if (QQmlPropertyData **old = stringCache.value(name)) {
data.overrideIndexIsProperty = !(*old)->isFunction();
data.overrideIndex = (*old)->coreIndex;
+ (*old)->flags |= QQmlPropertyData::IsOverridden;
}
methodIndexCache.append(data);
@@ -477,6 +481,7 @@ void QQmlPropertyCache::appendMethod(const QString &name, quint32 flags, int cor
if (QQmlPropertyData **old = stringCache.value(string)) {
data.overrideIndexIsProperty = !(*old)->isFunction();
data.overrideIndex = (*old)->coreIndex;
+ (*old)->flags |= QQmlPropertyData::IsOverridden;
}
methodIndexCache.append(data);
@@ -510,6 +515,7 @@ void QQmlPropertyCache::appendMethod(const QHashedCStringRef &name, quint32 flag
if (QQmlPropertyData **old = stringCache.value(name)) {
data.overrideIndexIsProperty = !(*old)->isFunction();
data.overrideIndex = (*old)->coreIndex;
+ (*old)->flags |= QQmlPropertyData::IsOverridden;
}
methodIndexCache.append(data);
@@ -738,6 +744,7 @@ void QQmlPropertyCache::append(QQmlEngine *engine, const QMetaObject *metaObject
data->flags |= QQmlPropertyData::IsOverload;
data->overrideIndexIsProperty = !old->isFunction();
data->overrideIndex = old->coreIndex;
+ old->flags |= QQmlPropertyData::IsOverridden;
}
}
@@ -797,6 +804,7 @@ void QQmlPropertyCache::append(QQmlEngine *engine, const QMetaObject *metaObject
} else if (old) {
data->overrideIndexIsProperty = !old->isFunction();
data->overrideIndex = old->coreIndex;
+ old->flags |= QQmlPropertyData::IsOverridden;
}
}
}
diff --git a/src/qml/qml/qqmlpropertycache_p.h b/src/qml/qml/qqmlpropertycache_p.h
index 3e87fa3c7f..b62d34cefb 100644
--- a/src/qml/qml/qqmlpropertycache_p.h
+++ b/src/qml/qml/qqmlpropertycache_p.h
@@ -89,33 +89,34 @@ public:
IsResettable = 0x00000004, // Has RESET function
IsAlias = 0x00000008, // Is a QML alias to another property
IsFinal = 0x00000010, // Has FINAL flag
- IsDirect = 0x00000020, // Exists on a C++ QMetaObject
- HasAccessors = 0x00000040, // Has property accessors
+ IsOverridden = 0x00000020, // Is overridden by a extension property
+ IsDirect = 0x00000040, // Exists on a C++ QMetaObject
+ HasAccessors = 0x00000080, // Has property accessors
// These are mutualy exclusive
- IsFunction = 0x00000080, // Is an invokable
- IsQObjectDerived = 0x00000100, // Property type is a QObject* derived type
- IsEnumType = 0x00000200, // Property type is an enum
- IsQList = 0x00000400, // Property type is a QML list
- IsQmlBinding = 0x00000800, // Property type is a QQmlBinding*
- IsQJSValue = 0x00001000, // Property type is a QScriptValue
- IsV8Handle = 0x00002000, // Property type is a QQmlV8Handle
- IsVarProperty = 0x00004000, // Property type is a "var" property of VMEMO
- IsValueTypeVirtual = 0x00008000, // Property is a value type "virtual" property
- IsQVariant = 0x00010000, // Property is a QVariant
+ IsFunction = 0x00000100, // Is an invokable
+ IsQObjectDerived = 0x00000200, // Property type is a QObject* derived type
+ IsEnumType = 0x00000400, // Property type is an enum
+ IsQList = 0x00000800, // Property type is a QML list
+ IsQmlBinding = 0x00001000, // Property type is a QQmlBinding*
+ IsQJSValue = 0x00002000, // Property type is a QScriptValue
+ IsV8Handle = 0x00004000, // Property type is a QQmlV8Handle
+ IsVarProperty = 0x00008000, // Property type is a "var" property of VMEMO
+ IsValueTypeVirtual = 0x00010000, // Property is a value type "virtual" property
+ IsQVariant = 0x00020000, // Property is a QVariant
// Apply only to IsFunctions
- IsVMEFunction = 0x00020000, // Function was added by QML
- HasArguments = 0x00040000, // Function takes arguments
- IsSignal = 0x00080000, // Function is a signal
- IsVMESignal = 0x00100000, // Signal was added by QML
- IsV8Function = 0x00200000, // Function takes QQmlV8Function* args
- IsSignalHandler = 0x00400000, // Function is a signal handler
- IsOverload = 0x00800000, // Function is an overload of another function
- IsCloned = 0x01000000, // The function was marked as cloned
+ IsVMEFunction = 0x00040000, // Function was added by QML
+ HasArguments = 0x00080000, // Function takes arguments
+ IsSignal = 0x00100000, // Function is a signal
+ IsVMESignal = 0x00200000, // Signal was added by QML
+ IsV8Function = 0x00400000, // Function takes QQmlV8Function* args
+ IsSignalHandler = 0x00800000, // Function is a signal handler
+ IsOverload = 0x01000000, // Function is an overload of another function
+ IsCloned = 0x02000000, // The function was marked as cloned
// Internal QQmlPropertyCache flags
- NotFullyResolved = 0x02000000, // True if the type data is to be lazily resolved
+ NotFullyResolved = 0x04000000, // True if the type data is to be lazily resolved
// Flags that are set based on the propType field
PropTypeFlagMask = IsQObjectDerived | IsEnumType | IsQList | IsQmlBinding | IsQJSValue |
@@ -133,6 +134,7 @@ public:
bool isResettable() const { return flags & IsResettable; }
bool isAlias() const { return flags & IsAlias; }
bool isFinal() const { return flags & IsFinal; }
+ bool isOverridden() const { return flags & IsOverridden; }
bool isDirect() const { return flags & IsDirect; }
bool hasAccessors() const { return flags & HasAccessors; }
bool isFunction() const { return flags & IsFunction; }
diff --git a/src/qml/qml/qqmlvme.cpp b/src/qml/qml/qqmlvme.cpp
index b9924e384c..7a6d00835e 100644
--- a/src/qml/qml/qqmlvme.cpp
+++ b/src/qml/qml/qqmlvme.cpp
@@ -847,7 +847,7 @@ QObject *QQmlVME::run(QList<QQmlError> *errors,
QML_NEXT_INSTR(StoreV4Binding);
QQmlAbstractBinding *binding =
- CTXT->v4bindings->configBinding(instr.value, target, scope, property,
+ CTXT->v4bindings->configBinding(instr.value, instr.fallbackValue, target, scope, property,
instr.line, instr.column);
bindValues.push(binding);
binding->m_mePtr = &bindValues.top();
@@ -881,7 +881,7 @@ QObject *QQmlVME::run(QList<QQmlError> *errors,
QQmlAbstractBinding *binding = CTXT->v8bindings->configBinding(target, scope,
&instr);
- if (binding) {
+ if (binding && !instr.isFallback) {
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 f011bc8f26..c0e0f22fad 100644
--- a/src/qml/qml/v4/qv4bindings.cpp
+++ b/src/qml/qml/v4/qv4bindings.cpp
@@ -298,13 +298,14 @@ QV4Bindings::~QV4Bindings()
delete [] subscriptions; subscriptions = 0;
}
-QQmlAbstractBinding *QV4Bindings::configBinding(int index, QObject *target,
+QQmlAbstractBinding *QV4Bindings::configBinding(int index, int fallbackIndex, QObject *target,
QObject *scope, int property,
int line, int column)
{
Binding *rv = bindings + index;
rv->index = index;
+ rv->fallbackIndex = fallbackIndex;
rv->property = property;
rv->target = target;
rv->scope = scope;
@@ -436,6 +437,9 @@ void QV4Bindings::run(Binding *binding, QQmlPropertyPrivate::WriteFlags flags)
return;
}
+ bool invalidated = false;
+ bool *inv = (binding->fallbackIndex != -1) ? &invalidated : 0;
+
binding->updating = true;
if (binding->property & 0xFFFF0000) {
QQmlEnginePrivate *ep = QQmlEnginePrivate::get(context->engine);
@@ -445,9 +449,11 @@ void QV4Bindings::run(Binding *binding, QQmlPropertyPrivate::WriteFlags flags)
vt->read(*binding->target, binding->property & 0xFFFF);
QObject *target = vt;
- run(binding->index, binding->executedBlocks, context, binding, binding->scope, target, flags);
+ run(binding->index, binding->executedBlocks, context, binding, binding->scope, target, flags, inv);
- vt->write(*binding->target, binding->property & 0xFFFF, flags);
+ if (!invalidated) {
+ vt->write(*binding->target, binding->property & 0xFFFF, flags);
+ }
} else {
QQmlData *data = QQmlData::get(*binding->target);
QQmlPropertyData *propertyData = (data && data->propertyCache ? data->propertyCache->property(binding->property) : 0);
@@ -457,12 +463,20 @@ void QV4Bindings::run(Binding *binding, QQmlPropertyPrivate::WriteFlags flags)
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);
+ run(binding->index, binding->executedBlocks, context, binding, binding->scope, *binding->target, flags, inv);
} else {
- run(binding->index, binding->executedBlocks, context, binding, binding->scope, *binding->target, flags);
+ run(binding->index, binding->executedBlocks, context, binding, binding->scope, *binding->target, flags, inv);
}
}
binding->updating = 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(b == binding);
+ b->destroy();
+ }
}
@@ -765,6 +779,25 @@ inline quint32 QV4Bindings::toUint32(double n)
MARK_REGISTER(reg); \
}
+//TODO: avoid construction of name and name-based lookup
+#define INVALIDATION_CHECK(inv, obj, index) { \
+ if ((inv) != 0) { \
+ QQmlData *data = QQmlData::get((obj)); \
+ if (data && !data->propertyCache) { \
+ data->propertyCache = QQmlEnginePrivate::get(context->engine)->cache(object); \
+ if (data->propertyCache) data->propertyCache->addref(); \
+ } \
+ QQmlPropertyData *prop = (data && data->propertyCache) ? data->propertyCache->property((index)) : 0; \
+ if (prop && prop->isOverridden()) { \
+ int resolvedIndex = data->propertyCache->property(prop->name(obj))->coreIndex; \
+ if (index < resolvedIndex) { \
+ *(inv) = true; \
+ goto programExit; \
+ } \
+ } \
+ } \
+}
+
#ifdef QML_THREADED_INTERPRETER
void **QV4Bindings::getDecodeInstrTable()
{
@@ -774,7 +807,7 @@ void **QV4Bindings::getDecodeInstrTable()
quint32 executedBlocks = 0;
dummy->run(0, executedBlocks, 0, 0, 0, 0,
QQmlPropertyPrivate::BypassInterceptor,
- &decode_instr);
+ 0, &decode_instr);
dummy->release();
}
return decode_instr;
@@ -784,7 +817,8 @@ void **QV4Bindings::getDecodeInstrTable()
void QV4Bindings::run(int instrIndex, quint32 &executedBlocks,
QQmlContextData *context, QQmlDelayedError *error,
QObject *scope, QObject *output,
- QQmlPropertyPrivate::WriteFlags storeFlags
+ QQmlPropertyPrivate::WriteFlags storeFlags,
+ bool *invalidated
#ifdef QML_THREADED_INTERPRETER
,void ***table
#endif
@@ -857,8 +891,10 @@ void QV4Bindings::run(int instrIndex, quint32 &executedBlocks,
QObject *object = reg.getQObject();
if (!object) {
- reg.setUndefined();
+ THROW_EXCEPTION(instr->fetchAndSubscribe.exceptionId);
} else {
+ INVALIDATION_CHECK(invalidated, object, instr->fetchAndSubscribe.property.coreIndex);
+
int subIdx = instr->fetchAndSubscribe.subscription;
Subscription *sub = 0;
if (subIdx != -1) {
@@ -2111,6 +2147,8 @@ void QV4Bindings::run(int instrIndex, quint32 &executedBlocks,
if (!object) {
THROW_EXCEPTION(instr->fetch.exceptionId);
} else {
+ INVALIDATION_CHECK(invalidated, object, instr->fetch.index);
+
const Register::Type valueType = (Register::Type)instr->fetch.valueType;
reg.init(valueType);
if (instr->fetch.valueType >= FirstCleanupType)
diff --git a/src/qml/qml/v4/qv4bindings_p.h b/src/qml/qml/v4/qv4bindings_p.h
index e9c6301cef..0c92cc4b45 100644
--- a/src/qml/qml/v4/qv4bindings_p.h
+++ b/src/qml/qml/v4/qv4bindings_p.h
@@ -71,7 +71,7 @@ public:
QV4Bindings(const char *program, QQmlContextData *context);
virtual ~QV4Bindings();
- QQmlAbstractBinding *configBinding(int index, QObject *target,
+ QQmlAbstractBinding *configBinding(int index, int fallbackIndex, QObject *target,
QObject *scope, int property,
int line, int column);
@@ -80,8 +80,8 @@ public:
#endif
struct Binding : public QQmlAbstractBinding, public QQmlDelayedError {
- Binding() : QQmlAbstractBinding(V4), enabled(false), updating(0), property(0),
- scope(0), target(0), executedBlocks(0), parent(0) {}
+ Binding() : QQmlAbstractBinding(V4), index(-1), fallbackIndex(-1), enabled(false),
+ updating(0), property(0), scope(0), target(0), executedBlocks(0), parent(0) {}
// Inherited from QQmlAbstractBinding
static void destroy(QQmlAbstractBinding *);
@@ -96,9 +96,11 @@ public:
int targetProperty;
};
- int index:30;
+ int index:15;
+ int fallbackIndex:15;
bool enabled:1;
bool updating:1;
+
// Encoding of property is coreIndex | (propType << 16) | (valueTypeIndex << 24)
// propType and valueTypeIndex are only set if the property is a value type property
int property;
@@ -134,7 +136,8 @@ private:
void init();
void run(int instr, quint32 &executedBlocks, QQmlContextData *context,
QQmlDelayedError *error, QObject *scope, QObject *output,
- QQmlPropertyPrivate::WriteFlags storeFlags
+ QQmlPropertyPrivate::WriteFlags storeFlags,
+ bool *invalidated
#ifdef QML_THREADED_INTERPRETER
, void ***decode_instr = 0
#endif
diff --git a/src/qml/qml/v4/qv4compiler.cpp b/src/qml/qml/v4/qv4compiler.cpp
index bac1f2c131..8f87583a94 100644
--- a/src/qml/qml/v4/qv4compiler.cpp
+++ b/src/qml/qml/v4/qv4compiler.cpp
@@ -66,7 +66,7 @@ using namespace QQmlJS;
QV4CompilerPrivate::QV4CompilerPrivate()
: subscriptionOffset(0)
, _function(0) , _block(0) , _discarded(false), registerCount(0)
- , bindingLine(0), bindingColumn(0)
+ , bindingLine(0), bindingColumn(0), invalidatable(false)
{
}
@@ -1258,6 +1258,7 @@ void QV4CompilerPrivate::resetInstanceState()
patches.clear();
pool.clear();
currentReg = 0;
+ invalidatable = false;
}
/*!
@@ -1304,7 +1305,7 @@ bool QV4CompilerPrivate::compile(QQmlJS::AST::Node *node)
IR::Function thisFunction(&pool), *function = &thisFunction;
QV4IRBuilder irBuilder(expression, engine);
- if (!irBuilder(function, node))
+ if (!irBuilder(function, node, &invalidatable))
return false;
bool discarded = false;
@@ -1445,7 +1446,7 @@ bool QV4Compiler::isValid() const
/*
-1 on failure, otherwise the binding index to use.
*/
-int QV4Compiler::compile(const Expression &expression, QQmlEnginePrivate *engine)
+int QV4Compiler::compile(const Expression &expression, QQmlEnginePrivate *engine, bool *invalidatable)
{
if (!expression.expression.asAST()) return false;
@@ -1456,6 +1457,7 @@ int QV4Compiler::compile(const Expression &expression, QQmlEnginePrivate *engine
d->engine = engine;
if (d->compile(expression.expression.asAST())) {
+ *invalidatable = d->isInvalidatable();
return d->commitCompile();
} else {
return -1;
diff --git a/src/qml/qml/v4/qv4compiler_p.h b/src/qml/qml/v4/qv4compiler_p.h
index cf0d51914b..ec246cacba 100644
--- a/src/qml/qml/v4/qv4compiler_p.h
+++ b/src/qml/qml/v4/qv4compiler_p.h
@@ -89,7 +89,7 @@ public:
};
// -1 on failure, otherwise the binding index to use
- int compile(const Expression &, QQmlEnginePrivate *);
+ int compile(const Expression &, QQmlEnginePrivate *, bool *);
// Returns the compiled program
QByteArray program() const;
diff --git a/src/qml/qml/v4/qv4compiler_p_p.h b/src/qml/qml/v4/qv4compiler_p_p.h
index 0c06ade87f..12beaa0fbb 100644
--- a/src/qml/qml/v4/qv4compiler_p_p.h
+++ b/src/qml/qml/v4/qv4compiler_p_p.h
@@ -127,6 +127,8 @@ public:
bool compile(QQmlJS::AST::Node *);
+ bool isInvalidatable() const { return invalidatable; }
+
int registerLiteralString(quint8 reg, const QStringRef &);
QByteArray data;
@@ -235,6 +237,7 @@ private:
quint32 currentBlockMask;
int bindingLine;
int bindingColumn;
+ bool invalidatable;
};
diff --git a/src/qml/qml/v4/qv4irbuilder.cpp b/src/qml/qml/v4/qv4irbuilder.cpp
index ddc2264cf7..79090b4269 100644
--- a/src/qml/qml/v4/qv4irbuilder.cpp
+++ b/src/qml/qml/v4/qv4irbuilder.cpp
@@ -91,14 +91,15 @@ static IR::Type irTypeFromVariantType(int t, QQmlEnginePrivate *engine)
}
}
-QV4IRBuilder::QV4IRBuilder(const QV4Compiler::Expression *expr,
- QQmlEnginePrivate *engine)
-: m_expression(expr), m_engine(engine), _function(0), _block(0), _discard(false)
+QV4IRBuilder::QV4IRBuilder(const QV4Compiler::Expression *expr,
+ QQmlEnginePrivate *engine)
+: m_expression(expr), m_engine(engine), _function(0), _block(0), _discard(false),
+ _invalidatable(false)
{
}
bool QV4IRBuilder::operator()(QQmlJS::IR::Function *function,
- QQmlJS::AST::Node *ast)
+ QQmlJS::AST::Node *ast, bool *invalidatable)
{
bool discarded = false;
@@ -142,6 +143,7 @@ bool QV4IRBuilder::operator()(QQmlJS::IR::Function *function,
qSwap(_function, function);
qSwap(_discard, discarded);
+ *invalidatable = _invalidatable;
return !discarded;
}
@@ -615,12 +617,8 @@ bool QV4IRBuilder::visit(AST::FieldMemberExpression *ast)
if (!data || data->isFunction())
return false; // Don't support methods (or non-existing properties ;)
- if(!data->isFinal()) {
- if (qmlVerboseCompiler())
- qWarning() << "*** non-final attached property:"
- << (*baseName->id + QLatin1Char('.') + ast->name.toString());
- return false; // We don't know enough about this property
- }
+ if (!data->isFinal())
+ _invalidatable = true;
IR::Type irType = irTypeFromVariantType(data->propType, m_engine);
_expr.code = _block->SYMBOL(baseName, irType, name, attachedMeta, data, line, column);
@@ -654,12 +652,8 @@ bool QV4IRBuilder::visit(AST::FieldMemberExpression *ast)
if (!data || data->isFunction())
return false; // Don't support methods (or non-existing properties ;)
- if (!data->isFinal()) {
- if (qmlVerboseCompiler())
- qWarning() << "*** non-final attached property:"
- << (*baseName->id + QLatin1Char('.') + ast->name.toString());
- return false; // We don't know enough about this property
- }
+ if (!data->isFinal())
+ _invalidatable = true;
IR::Type irType = irTypeFromVariantType(data->propType, m_engine);
_expr.code = _block->SYMBOL(baseName, irType, name, baseName->meta, data, line, column);
@@ -690,20 +684,15 @@ bool QV4IRBuilder::visit(AST::FieldMemberExpression *ast)
break;
case IR::Name::Property:
- if (baseName->type == IR::ObjectType && !baseName->meta.isNull() &&
- baseName->property->isFinal()) {
+ if (baseName->type == IR::ObjectType && !baseName->meta.isNull()) {
QQmlMetaObject meta = m_engine->metaObjectForType(baseName->property->propType);
QQmlPropertyCache *cache = meta.propertyCache(m_engine);
if (!cache)
return false;
if (QQmlPropertyData *data = cache->property(name)) {
- if (!data->isFinal()) {
- if (qmlVerboseCompiler())
- qWarning() << "*** non-final property access:"
- << (*baseName->id + QLatin1Char('.') + ast->name.toString());
- return false; // We don't know enough about this property
- }
+ if (!baseName->property->isFinal() || !data->isFinal())
+ _invalidatable = true;
IR::Type irType = irTypeFromVariantType(data->propType, m_engine);
_expr.code = _block->SYMBOL(baseName, irType, name,
diff --git a/src/qml/qml/v4/qv4irbuilder_p.h b/src/qml/qml/v4/qv4irbuilder_p.h
index e73ec22750..e4f75d575c 100644
--- a/src/qml/qml/v4/qv4irbuilder_p.h
+++ b/src/qml/qml/v4/qv4irbuilder_p.h
@@ -55,7 +55,7 @@ class QV4IRBuilder : public QQmlJS::AST::Visitor
public:
QV4IRBuilder(const QV4Compiler::Expression *, QQmlEnginePrivate *);
- bool operator()(QQmlJS::IR::Function *, QQmlJS::AST::Node *);
+ bool operator()(QQmlJS::IR::Function *, QQmlJS::AST::Node *, bool *invalidatable);
protected:
struct ExprResult {
@@ -229,6 +229,7 @@ private:
QQmlJS::IR::Function *_function;
QQmlJS::IR::BasicBlock *_block;
bool _discard;
+ bool _invalidatable;
ExprResult _expr;
};
diff --git a/src/qml/qml/v8/qv8bindings.cpp b/src/qml/qml/v8/qv8bindings.cpp
index 00134c5a51..5a6abdbe22 100644
--- a/src/qml/qml/v8/qv8bindings.cpp
+++ b/src/qml/qml/v8/qv8bindings.cpp
@@ -296,7 +296,8 @@ QV8Bindings::configBinding(QObject *target, QObject *scope,
rv->setNotifyOnValueChanged(true);
rv->parent = this;
- addref(); // This is decremented in Binding::destroy()
+ if (!i->isFallback)
+ addref(); // This is decremented in Binding::destroy()
return rv;
}
diff --git a/src/qml/qml/v8/qv8bindings_p.h b/src/qml/qml/v8/qv8bindings_p.h
index fc6617b516..c7c2a3c960 100644
--- a/src/qml/qml/v8/qv8bindings_p.h
+++ b/src/qml/qml/v8/qv8bindings_p.h
@@ -129,6 +129,8 @@ public:
inline void addref();
inline void release();
+ QQmlAbstractBinding *binding(int index) const { return bindings + index; }
+
private:
Q_DISABLE_COPY(QV8Bindings)