diff options
Diffstat (limited to 'src/qml/qml/v4')
-rw-r--r-- | src/qml/qml/v4/qv4bindings.cpp | 54 | ||||
-rw-r--r-- | src/qml/qml/v4/qv4bindings_p.h | 13 | ||||
-rw-r--r-- | src/qml/qml/v4/qv4compiler.cpp | 8 | ||||
-rw-r--r-- | src/qml/qml/v4/qv4compiler_p.h | 2 | ||||
-rw-r--r-- | src/qml/qml/v4/qv4compiler_p_p.h | 3 | ||||
-rw-r--r-- | src/qml/qml/v4/qv4irbuilder.cpp | 37 | ||||
-rw-r--r-- | src/qml/qml/v4/qv4irbuilder_p.h | 3 |
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; }; |