aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSimon Hausmann <simon.hausmann@digia.com>2013-10-28 15:18:31 +0100
committerThe Qt Project <gerrit-noreply@qt-project.org>2013-10-31 18:54:59 +0100
commitb0afac3daf1cbb9daacbeac0183ef6254de6cc95 (patch)
tree1eb69941be2d3c47e5d711705cd5f910eefafdca
parentc7a3089c146d6063f3b3201149e42c720c8ca5b3 (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.h8
-rw-r--r--src/qml/compiler/qv4isel_masm.cpp6
-rw-r--r--src/qml/compiler/qv4isel_masm_p.h1
-rw-r--r--src/qml/compiler/qv4isel_moth.cpp9
-rw-r--r--src/qml/compiler/qv4isel_moth_p.h1
-rw-r--r--src/qml/compiler/qv4isel_p.cpp9
-rw-r--r--src/qml/compiler/qv4isel_p.h1
-rw-r--r--src/qml/compiler/qv4regalloc.cpp7
-rw-r--r--src/qml/jsruntime/qv4qobjectwrapper.cpp96
-rw-r--r--src/qml/jsruntime/qv4qobjectwrapper_p.h2
-rw-r--r--src/qml/jsruntime/qv4runtime.cpp11
-rw-r--r--src/qml/jsruntime/qv4runtime_p.h1
-rw-r--r--src/qml/jsruntime/qv4vme_moth.cpp5
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)