aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml/qml
diff options
context:
space:
mode:
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)