diff options
author | Simon Hausmann <simon.hausmann@digia.com> | 2013-10-28 15:18:31 +0100 |
---|---|---|
committer | The Qt Project <gerrit-noreply@qt-project.org> | 2013-10-31 18:54:59 +0100 |
commit | b0afac3daf1cbb9daacbeac0183ef6254de6cc95 (patch) | |
tree | 1eb69941be2d3c47e5d711705cd5f910eefafdca | |
parent | c7a3089c146d6063f3b3201149e42c720c8ca5b3 (diff) |
Implement setting of values to resolved QObject properties
After the resolution of a property, we can set it by index at run-time instead
of via name resolution.
Change-Id: I479599dabe343cf9e6582dcda12291aebfcce418
Reviewed-by: Lars Knoll <lars.knoll@digia.com>
-rw-r--r-- | src/qml/compiler/qv4instr_moth_p.h | 8 | ||||
-rw-r--r-- | src/qml/compiler/qv4isel_masm.cpp | 6 | ||||
-rw-r--r-- | src/qml/compiler/qv4isel_masm_p.h | 1 | ||||
-rw-r--r-- | src/qml/compiler/qv4isel_moth.cpp | 9 | ||||
-rw-r--r-- | src/qml/compiler/qv4isel_moth_p.h | 1 | ||||
-rw-r--r-- | src/qml/compiler/qv4isel_p.cpp | 9 | ||||
-rw-r--r-- | src/qml/compiler/qv4isel_p.h | 1 | ||||
-rw-r--r-- | src/qml/compiler/qv4regalloc.cpp | 7 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4qobjectwrapper.cpp | 96 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4qobjectwrapper_p.h | 2 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4runtime.cpp | 11 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4runtime_p.h | 1 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4vme_moth.cpp | 5 |
13 files changed, 116 insertions, 41 deletions
diff --git a/src/qml/compiler/qv4instr_moth_p.h b/src/qml/compiler/qv4instr_moth_p.h index d1619962f5..99aed0db97 100644 --- a/src/qml/compiler/qv4instr_moth_p.h +++ b/src/qml/compiler/qv4instr_moth_p.h @@ -65,6 +65,7 @@ QT_BEGIN_NAMESPACE F(GetLookup, getLookup) \ F(StoreProperty, storeProperty) \ F(SetLookup, setLookup) \ + F(StoreQObjectProperty, storeQObjectProperty) \ F(LoadQObjectProperty, loadQObjectProperty) \ F(Push, push) \ F(CallValue, callValue) \ @@ -296,6 +297,12 @@ union Instr Param base; Param source; }; + struct instr_storeQObjectProperty { + MOTH_INSTR_HEADER + Param base; + int propertyIndex; + Param source; + }; struct instr_loadElement { MOTH_INSTR_HEADER Param base; @@ -663,6 +670,7 @@ union Instr instr_loadQObjectProperty loadQObjectProperty; instr_storeProperty storeProperty; instr_setLookup setLookup; + instr_storeQObjectProperty storeQObjectProperty; instr_push push; instr_callValue callValue; instr_callProperty callProperty; diff --git a/src/qml/compiler/qv4isel_masm.cpp b/src/qml/compiler/qv4isel_masm.cpp index a012273c12..ecfe7dd0a0 100644 --- a/src/qml/compiler/qv4isel_masm.cpp +++ b/src/qml/compiler/qv4isel_masm.cpp @@ -1061,6 +1061,12 @@ void InstructionSelection::setProperty(V4IR::Expr *source, V4IR::Expr *targetBas } } +void InstructionSelection::setQObjectProperty(V4IR::Expr *source, V4IR::Expr *targetBase, int propertyIndex) +{ + generateFunctionCall(Assembler::Void, __qmljs_set_qobject_property, Assembler::ContextRegister, Assembler::PointerToValue(targetBase), + Assembler::TrustedImm32(propertyIndex), Assembler::PointerToValue(source)); +} + void InstructionSelection::getElement(V4IR::Expr *base, V4IR::Expr *index, V4IR::Temp *target) { #if QT_POINTER_SIZE == 8 diff --git a/src/qml/compiler/qv4isel_masm_p.h b/src/qml/compiler/qv4isel_masm_p.h index 46144f22d1..b5f95f0062 100644 --- a/src/qml/compiler/qv4isel_masm_p.h +++ b/src/qml/compiler/qv4isel_masm_p.h @@ -1480,6 +1480,7 @@ protected: virtual void initClosure(V4IR::Closure *closure, V4IR::Temp *target); virtual void getProperty(V4IR::Expr *base, const QString &name, V4IR::Temp *target); virtual void setProperty(V4IR::Expr *source, V4IR::Expr *targetBase, const QString &targetName); + virtual void setQObjectProperty(V4IR::Expr *source, V4IR::Expr *targetBase, int propertyIndex); virtual void getQObjectProperty(V4IR::Expr *base, int propertyIndex, V4IR::Temp *target); virtual void getElement(V4IR::Expr *base, V4IR::Expr *index, V4IR::Temp *target); virtual void setElement(V4IR::Expr *source, V4IR::Expr *targetBase, V4IR::Expr *targetIndex); diff --git a/src/qml/compiler/qv4isel_moth.cpp b/src/qml/compiler/qv4isel_moth.cpp index ca0977e057..954c4f532e 100644 --- a/src/qml/compiler/qv4isel_moth.cpp +++ b/src/qml/compiler/qv4isel_moth.cpp @@ -569,6 +569,15 @@ void InstructionSelection::setProperty(V4IR::Expr *source, V4IR::Expr *targetBas addInstruction(store); } +void InstructionSelection::setQObjectProperty(V4IR::Expr *source, V4IR::Expr *targetBase, int propertyIndex) +{ + Instruction::StoreQObjectProperty store; + store.base = getParam(targetBase); + store.propertyIndex = propertyIndex; + store.source = getParam(source); + addInstruction(store); +} + void InstructionSelection::getQObjectProperty(V4IR::Expr *base, int propertyIndex, V4IR::Temp *target) { Instruction::LoadQObjectProperty load; diff --git a/src/qml/compiler/qv4isel_moth_p.h b/src/qml/compiler/qv4isel_moth_p.h index 0b44bf35ca..61fc092c57 100644 --- a/src/qml/compiler/qv4isel_moth_p.h +++ b/src/qml/compiler/qv4isel_moth_p.h @@ -125,6 +125,7 @@ protected: virtual void initClosure(V4IR::Closure *closure, V4IR::Temp *target); virtual void getProperty(V4IR::Expr *base, const QString &name, V4IR::Temp *target); virtual void setProperty(V4IR::Expr *source, V4IR::Expr *targetBase, const QString &targetName); + virtual void setQObjectProperty(V4IR::Expr *source, V4IR::Expr *targetBase, int propertyIndex); virtual void getQObjectProperty(V4IR::Expr *base, int propertyIndex, V4IR::Temp *target); virtual void getElement(V4IR::Expr *base, V4IR::Expr *index, V4IR::Temp *target); virtual void setElement(V4IR::Expr *source, V4IR::Expr *targetBase, V4IR::Expr *targetIndex); diff --git a/src/qml/compiler/qv4isel_p.cpp b/src/qml/compiler/qv4isel_p.cpp index 1a56ddabf1..d6f0b4b804 100644 --- a/src/qml/compiler/qv4isel_p.cpp +++ b/src/qml/compiler/qv4isel_p.cpp @@ -183,8 +183,13 @@ void IRDecoder::visitMove(V4IR::Move *s) } else if (V4IR::Member *m = s->target->asMember()) { if (m->base->asTemp() || m->base->asConst()) { if (s->source->asTemp() || s->source->asConst()) { - setProperty(s->source, m->base, *m->name); - return; + if (m->type == V4IR::Member::MemberOfQObject) { + setQObjectProperty(s->source, m->base, m->property->coreIndex); + return; + } else { + setProperty(s->source, m->base, *m->name); + return; + } } } } else if (V4IR::Subscript *ss = s->target->asSubscript()) { diff --git a/src/qml/compiler/qv4isel_p.h b/src/qml/compiler/qv4isel_p.h index 5b9dbafb50..bdb998fc0b 100644 --- a/src/qml/compiler/qv4isel_p.h +++ b/src/qml/compiler/qv4isel_p.h @@ -152,6 +152,7 @@ public: // to implement by subclasses: virtual void getProperty(V4IR::Expr *base, const QString &name, V4IR::Temp *target) = 0; virtual void getQObjectProperty(V4IR::Expr *base, int propertyIndex, V4IR::Temp *targetTemp) = 0; virtual void setProperty(V4IR::Expr *source, V4IR::Expr *targetBase, const QString &targetName) = 0; + virtual void setQObjectProperty(V4IR::Expr *source, V4IR::Expr *targetBase, int propertyIndex) = 0; virtual void getElement(V4IR::Expr *base, V4IR::Expr *index, V4IR::Temp *target) = 0; virtual void setElement(V4IR::Expr *source, V4IR::Expr *targetBase, V4IR::Expr *targetIndex) = 0; virtual void copyValue(V4IR::Temp *sourceTemp, V4IR::Temp *targetTemp) = 0; diff --git a/src/qml/compiler/qv4regalloc.cpp b/src/qml/compiler/qv4regalloc.cpp index 84efdbb920..501f5b7edb 100644 --- a/src/qml/compiler/qv4regalloc.cpp +++ b/src/qml/compiler/qv4regalloc.cpp @@ -400,6 +400,13 @@ protected: // IRDecoder addCall(); } + virtual void setQObjectProperty(V4IR::Expr *source, V4IR::Expr *targetBase, int /*propertyIndex*/) + { + addUses(source->asTemp(), Use::CouldHaveRegister); + addUses(targetBase->asTemp(), Use::CouldHaveRegister); + addCall(); + } + virtual void getQObjectProperty(V4IR::Expr *base, int /*propertyIndex*/, V4IR::Temp *target) { addDef(target); diff --git a/src/qml/jsruntime/qv4qobjectwrapper.cpp b/src/qml/jsruntime/qv4qobjectwrapper.cpp index 22e2019112..091eddcf99 100644 --- a/src/qml/jsruntime/qv4qobjectwrapper.cpp +++ b/src/qml/jsruntime/qv4qobjectwrapper.cpp @@ -393,7 +393,6 @@ ReturnedValue QObjectWrapper::getProperty(ExecutionContext *ctx, QQmlPropertyDat } } - ReturnedValue QObjectWrapper::getQmlProperty(ExecutionContext *ctx, QQmlContextData *qmlContext, QObject *object, String *name, QObjectWrapper::RevisionMode revisionMode, bool *hasProperty) { QV4::Scope scope(ctx); @@ -424,8 +423,6 @@ bool QObjectWrapper::setQmlProperty(ExecutionContext *ctx, QQmlContextData *qmlC if (QQmlData::wasDeleted(object)) return false; - QV4::Scope scope(ctx); - QQmlPropertyData local; QQmlPropertyData *result = 0; { @@ -441,25 +438,33 @@ bool QObjectWrapper::setQmlProperty(ExecutionContext *ctx, QQmlContextData *qmlC return false; } - if (!result->isWritable() && !result->isQList()) { + setProperty(object, ctx, result, value); + return true; +} + +void QObjectWrapper::setProperty(QObject *object, ExecutionContext *ctx, QQmlPropertyData *property, const ValueRef value) +{ + if (!property->isWritable() && !property->isQList()) { QString error = QLatin1String("Cannot assign to read-only property \"") + - name->toQString() + QLatin1Char('\"'); - return ctx->throwTypeError(error); + property->name(object) + QLatin1Char('\"'); + ctx->throwTypeError(error); + return; } QQmlBinding *newBinding = 0; + QV4::Scope scope(ctx); QV4::ScopedFunctionObject f(scope, value); if (f) { if (!f->bindingKeyFlag) { - if (!result->isVarProperty() && result->propType != qMetaTypeId<QJSValue>()) { + if (!property->isVarProperty() && property->propType != qMetaTypeId<QJSValue>()) { // assigning a JS function to a non var or QJSValue property or is not allowed. QString error = QLatin1String("Cannot assign JavaScript function to "); - if (!QMetaType::typeName(result->propType)) + if (!QMetaType::typeName(property->propType)) error += QLatin1String("[unknown property type]"); else - error += QLatin1String(QMetaType::typeName(result->propType)); + error += QLatin1String(QMetaType::typeName(property->propType)); ctx->throwError(error); - return false; + return; } } else { // binding assignment. @@ -469,23 +474,23 @@ bool QObjectWrapper::setQmlProperty(ExecutionContext *ctx, QQmlContextData *qmlC newBinding = new QQmlBinding(value, object, callingQmlContext, frame.source, qmlSourceCoordinate(frame.line), qmlSourceCoordinate(frame.column)); - newBinding->setTarget(object, *result, callingQmlContext); + newBinding->setTarget(object, *property, callingQmlContext); newBinding->setEvaluateFlags(newBinding->evaluateFlags() | QQmlBinding::RequiresThisObject); } } QQmlAbstractBinding *oldBinding = - QQmlPropertyPrivate::setBinding(object, result->coreIndex, -1, newBinding); + QQmlPropertyPrivate::setBinding(object, property->coreIndex, -1, newBinding); if (oldBinding) oldBinding->destroy(); - if (!newBinding && result->isVarProperty()) { + if (!newBinding && property->isVarProperty()) { // allow assignment of "special" values (null, undefined, function) to var properties QQmlVMEMetaObject *vmemo = QQmlVMEMetaObject::get(object); Q_ASSERT(vmemo); - vmemo->setVMEProperty(result->coreIndex, value); - return true; + vmemo->setVMEProperty(property->coreIndex, value); + return; } #define PROPERTY_STORE(cpptype, value) \ @@ -493,57 +498,57 @@ bool QObjectWrapper::setQmlProperty(ExecutionContext *ctx, QQmlContextData *qmlC int status = -1; \ int flags = 0; \ void *argv[] = { &o, 0, &status, &flags }; \ - QMetaObject::metacall(object, QMetaObject::WriteProperty, result->coreIndex, argv); + QMetaObject::metacall(object, QMetaObject::WriteProperty, property->coreIndex, argv); - if (value->isNull() && result->isQObject()) { + if (value->isNull() && property->isQObject()) { PROPERTY_STORE(QObject*, 0); - } else if (value->isUndefined() && result->isResettable()) { + } else if (value->isUndefined() && property->isResettable()) { void *a[] = { 0 }; - QMetaObject::metacall(object, QMetaObject::ResetProperty, result->coreIndex, a); - } else if (value->isUndefined() && result->propType == qMetaTypeId<QVariant>()) { + QMetaObject::metacall(object, QMetaObject::ResetProperty, property->coreIndex, a); + } else if (value->isUndefined() && property->propType == qMetaTypeId<QVariant>()) { PROPERTY_STORE(QVariant, QVariant()); - } else if (value->isUndefined() && result->propType == QMetaType::QJsonValue) { + } else if (value->isUndefined() && property->propType == QMetaType::QJsonValue) { PROPERTY_STORE(QJsonValue, QJsonValue(QJsonValue::Undefined)); - } else if (!newBinding && result->propType == qMetaTypeId<QJSValue>()) { + } else if (!newBinding && property->propType == qMetaTypeId<QJSValue>()) { PROPERTY_STORE(QJSValue, new QJSValuePrivate(ctx->engine, value)); } else if (value->isUndefined()) { QString error = QLatin1String("Cannot assign [undefined] to "); - if (!QMetaType::typeName(result->propType)) + if (!QMetaType::typeName(property->propType)) error += QLatin1String("[unknown property type]"); else - error += QLatin1String(QMetaType::typeName(result->propType)); + error += QLatin1String(QMetaType::typeName(property->propType)); ctx->throwError(error); - return false; + return; } else if (value->asFunctionObject()) { // this is handled by the binding creation above - } else if (result->propType == QMetaType::Int && value->isNumber()) { + } else if (property->propType == QMetaType::Int && value->isNumber()) { PROPERTY_STORE(int, qRound(value->asDouble())); - } else if (result->propType == QMetaType::QReal && value->isNumber()) { + } else if (property->propType == QMetaType::QReal && value->isNumber()) { PROPERTY_STORE(qreal, qreal(value->asDouble())); - } else if (result->propType == QMetaType::Float && value->isNumber()) { + } else if (property->propType == QMetaType::Float && value->isNumber()) { PROPERTY_STORE(float, float(value->asDouble())); - } else if (result->propType == QMetaType::Double && value->isNumber()) { + } else if (property->propType == QMetaType::Double && value->isNumber()) { PROPERTY_STORE(double, double(value->asDouble())); - } else if (result->propType == QMetaType::QString && value->isString()) { + } else if (property->propType == QMetaType::QString && value->isString()) { PROPERTY_STORE(QString, value->toQStringNoThrow()); - } else if (result->isVarProperty()) { + } else if (property->isVarProperty()) { QQmlVMEMetaObject *vmemo = QQmlVMEMetaObject::get(object); Q_ASSERT(vmemo); - vmemo->setVMEProperty(result->coreIndex, value); + vmemo->setVMEProperty(property->coreIndex, value); } else { QVariant v; - if (result->isQList()) + if (property->isQList()) v = ctx->engine->v8Engine->toVariant(value, qMetaTypeId<QList<QObject *> >()); else - v = ctx->engine->v8Engine->toVariant(value, result->propType); + v = ctx->engine->v8Engine->toVariant(value, property->propType); QQmlContextData *callingQmlContext = QV4::QmlContextWrapper::callingContext(ctx->engine); - if (!QQmlPropertyPrivate::write(object, *result, v, callingQmlContext)) { + if (!QQmlPropertyPrivate::write(object, *property, v, callingQmlContext)) { const char *valueType = 0; if (v.userType() == QVariant::Invalid) valueType = "null"; else valueType = QMetaType::typeName(v.userType()); - const char *targetTypeName = QMetaType::typeName(result->propType); + const char *targetTypeName = QMetaType::typeName(property->propType); if (!targetTypeName) targetTypeName = "an unregistered type"; @@ -552,11 +557,9 @@ bool QObjectWrapper::setQmlProperty(ExecutionContext *ctx, QQmlContextData *qmlC QLatin1String(" to ") + QLatin1String(targetTypeName); ctx->throwError(error); - return false; + return; } } - - return true; } ReturnedValue QObjectWrapper::wrap(ExecutionEngine *engine, QObject *object) @@ -626,6 +629,21 @@ ReturnedValue QObjectWrapper::getProperty(ExecutionContext *ctx, int propertyInd return getProperty(ctx, property); } +void QObjectWrapper::setProperty(ExecutionContext *ctx, int propertyIndex, const ValueRef value) +{ + if (QQmlData::wasDeleted(m_object)) + return; + QQmlData *ddata = QQmlData::get(m_object, /*create*/false); + if (!ddata) + return; + + QQmlPropertyCache *cache = ddata->propertyCache; + Q_ASSERT(cache); + QQmlPropertyData *property = cache->property(propertyIndex); + Q_ASSERT(property); // We resolved this property earlier, so it better exist! + return setProperty(m_object, ctx, property, value); +} + ReturnedValue QObjectWrapper::create(ExecutionEngine *engine, QQmlData *ddata, QObject *object) { QQmlEngine *qmlEngine = engine->v8Engine->engine(); diff --git a/src/qml/jsruntime/qv4qobjectwrapper_p.h b/src/qml/jsruntime/qv4qobjectwrapper_p.h index 6f886f0522..4907d926fe 100644 --- a/src/qml/jsruntime/qv4qobjectwrapper_p.h +++ b/src/qml/jsruntime/qv4qobjectwrapper_p.h @@ -95,9 +95,11 @@ struct Q_QML_EXPORT QObjectWrapper : public QV4::Object using Object::get; ReturnedValue getProperty(ExecutionContext *ctx, int propertyIndex); + void setProperty(ExecutionContext *ctx, int propertyIndex, const ValueRef value); private: ReturnedValue getProperty(ExecutionContext *ctx, QQmlPropertyData *property); + static void setProperty(QObject *object, ExecutionContext *ctx, QQmlPropertyData *property, const ValueRef value); static ReturnedValue create(ExecutionEngine *engine, QQmlData *ddata, QObject *object); diff --git a/src/qml/jsruntime/qv4runtime.cpp b/src/qml/jsruntime/qv4runtime.cpp index aa8ab1c172..856dedc9ec 100644 --- a/src/qml/jsruntime/qv4runtime.cpp +++ b/src/qml/jsruntime/qv4runtime.cpp @@ -1207,6 +1207,17 @@ ReturnedValue __qmljs_get_qobject_property(ExecutionContext *ctx, const ValueRef return wrapper->getProperty(ctx, propertyIndex); } +void __qmljs_set_qobject_property(ExecutionContext *ctx, const ValueRef object, int propertyIndex, const ValueRef value) +{ + Scope scope(ctx); + QV4::Scoped<QObjectWrapper> wrapper(scope, object); + if (!wrapper) { + ctx->throwTypeError(QStringLiteral("Cannot write property of null")); + return; + } + wrapper->setProperty(ctx, propertyIndex, value); +} + } // namespace QV4 QT_END_NAMESPACE diff --git a/src/qml/jsruntime/qv4runtime_p.h b/src/qml/jsruntime/qv4runtime_p.h index 464595a380..85d8041a58 100644 --- a/src/qml/jsruntime/qv4runtime_p.h +++ b/src/qml/jsruntime/qv4runtime_p.h @@ -168,6 +168,7 @@ QV4::ReturnedValue __qmljs_get_id_object(ExecutionContext *ctx, int id); QV4::ReturnedValue __qmljs_get_context_object(ExecutionContext *ctx); QV4::ReturnedValue __qmljs_get_scope_object(ExecutionContext *ctx); QV4::ReturnedValue __qmljs_get_qobject_property(ExecutionContext *ctx, const ValueRef object, int propertyIndex); +void __qmljs_set_qobject_property(ExecutionContext *ctx, const ValueRef object, int propertyIndex, const ValueRef value); // For each QV4::ReturnedValue __qmljs_foreach_iterator_object(QV4::ExecutionContext *ctx, const QV4::ValueRef in); diff --git a/src/qml/jsruntime/qv4vme_moth.cpp b/src/qml/jsruntime/qv4vme_moth.cpp index 1797f0b2ee..ecbc78cd26 100644 --- a/src/qml/jsruntime/qv4vme_moth.cpp +++ b/src/qml/jsruntime/qv4vme_moth.cpp @@ -305,6 +305,11 @@ QV4::ReturnedValue VME::run(QV4::ExecutionContext *context, const uchar *code, CHECK_EXCEPTION; MOTH_END_INSTR(SetLookup) + MOTH_BEGIN_INSTR(StoreQObjectProperty) + __qmljs_set_qobject_property(context, VALUEPTR(instr.base), instr.propertyIndex, VALUEPTR(instr.source)); + CHECK_EXCEPTION; + MOTH_END_INSTR(StoreQObjectProperty) + MOTH_BEGIN_INSTR(LoadQObjectProperty) STOREVALUE(instr.result, __qmljs_get_qobject_property(context, VALUEPTR(instr.base), instr.propertyIndex)); MOTH_END_INSTR(LoadQObjectProperty) |