aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml/qml/v4
diff options
context:
space:
mode:
Diffstat (limited to 'src/qml/qml/v4')
-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
7 files changed, 78 insertions, 42 deletions
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;
};