summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/declarative/qml/qmlbasicscript_p.h2
-rw-r--r--src/declarative/qml/qmlbindingvme.cpp177
-rw-r--r--src/declarative/qml/qmlbindingvme_p.h2
-rw-r--r--src/declarative/qml/qmlcompiler.cpp4
-rw-r--r--src/declarative/qml/qmlengine_p.h2
5 files changed, 161 insertions, 26 deletions
diff --git a/src/declarative/qml/qmlbasicscript_p.h b/src/declarative/qml/qmlbasicscript_p.h
index 830d2bd..3af09c2 100644
--- a/src/declarative/qml/qmlbasicscript_p.h
+++ b/src/declarative/qml/qmlbasicscript_p.h
@@ -54,6 +54,7 @@
//
#include "qmlparser_p.h"
+#include "qmlengine_p.h"
#include <QtCore/QList>
#include <QtCore/QByteArray>
@@ -88,6 +89,7 @@ public:
QmlParser::Property *property;
QmlParser::Variant expression;
QHash<QString, QmlParser::Object *> ids;
+ QmlEnginePrivate::Imports imports;
};
bool compile(const Expression &);
diff --git a/src/declarative/qml/qmlbindingvme.cpp b/src/declarative/qml/qmlbindingvme.cpp
index 26dd303..3cadb62 100644
--- a/src/declarative/qml/qmlbindingvme.cpp
+++ b/src/declarative/qml/qmlbindingvme.cpp
@@ -83,6 +83,7 @@ struct Instr {
LoadId, // load
LoadScope, // load
LoadRoot, // load
+ LoadAttached, // attached
ConvertIntToReal, // unaryop
ConvertRealToInt, // unaryop
@@ -117,6 +118,7 @@ struct Instr {
FindPropertyTerminal, // find
CleanupGeneric, // cleanup
ConvertGenericToReal, // genericunaryop
+ ConvertGenericToBool, // genericunaryop
ConvertGenericToString, // genericunaryop
} type;
@@ -137,8 +139,13 @@ struct Instr {
} load;
struct {
int output;
+ int reg;
int index;
+ } attached;
+ struct {
+ int output;
int reg;
+ int index;
} store;
struct {
int output;
@@ -221,6 +228,8 @@ struct QmlBindingCompiler
const QMetaObject *metaObject;
int type;
int reg;
+
+ QSet<QString> subscriptionSet;
};
QmlBindingCompiler() : registers(0), strings(0) {}
@@ -230,6 +239,8 @@ struct QmlBindingCompiler
QmlParser::Object *component;
QmlParser::Property *destination;
QHash<QString, QmlParser::Object *> ids;
+ QmlEnginePrivate::Imports imports;
+ QmlEnginePrivate *engine;
bool compile(QmlJS::AST::Node *);
@@ -262,11 +273,14 @@ struct QmlBindingCompiler
QByteArray data;
QSet<QString> subscriptionSet;
- bool subscription(const QStringList &);
+ QHash<QString, int> subscriptionIds;
+ bool subscription(const QStringList &, Result *);
+ int subscriptionIndex(const QStringList &);
+ bool subscriptionNeutral(const QSet<QString> &base, const QSet<QString> &lhs, const QSet<QString> &rhs);
QVector<Instr> bytecode;
};
-QByteArray QmlBindingVME::compile(const QmlBasicScript::Expression &expression)
+QByteArray QmlBindingVME::compile(const QmlBasicScript::Expression &expression, QmlEnginePrivate *engine)
{
if (!expression.expression.asAST()) return false;
@@ -275,6 +289,8 @@ QByteArray QmlBindingVME::compile(const QmlBasicScript::Expression &expression)
bsc.component = expression.component;
bsc.destination = expression.property;
bsc.ids = expression.ids;
+ bsc.imports = expression.imports;
+ bsc.engine = engine;
bool ok = bsc.compile(expression.expression.asAST());
@@ -475,7 +491,7 @@ static bool findgeneric(Register *output, // val
}
-// Conversion functions
+// Conversion functions - these MUST match the QtScript expression path
inline static qreal toReal(Register *reg, int type, bool *ok = 0)
{
if (ok) *ok = true;
@@ -595,6 +611,15 @@ void QmlBindingVME::run(const char *programData, Config *config,
registers[instr->load.reg].setQObject(context->defaultObjects.at(0));
break;
+ case Instr::LoadAttached:
+ {
+ QObject *o = qmlAttachedPropertiesObjectById(instr->attached.index,
+ registers[instr->attached.reg].getQObject(),
+ true);
+ registers[instr->attached.output].setQObject(o);
+ }
+ break;
+
case Instr::ConvertIntToReal:
registers[instr->unaryop.output].setqreal(qreal(registers[instr->unaryop.src].getint()));
break;
@@ -730,6 +755,13 @@ void QmlBindingVME::run(const char *programData, Config *config,
}
break;
+ case Instr::ConvertGenericToBool:
+ {
+ int type = registers[instr->genericunaryop.srcType].getint();
+ registers[instr->genericunaryop.output].setbool(toBool(registers + instr->genericunaryop.src, type));
+ }
+ break;
+
case Instr::ConvertGenericToString:
{
int type = registers[instr->genericunaryop.srcType].getint();
@@ -775,6 +807,9 @@ void QmlBindingVME::dump(const QByteArray &programData)
case Instr::LoadRoot:
qWarning().nospace() << "LoadRoot" << "\t\t" << instr->load.index << "\t" << instr->load.reg;
break;
+ case Instr::LoadAttached:
+ qWarning().nospace() << "LoadAttached" << "\t\t" << instr->attached.output << "\t" << instr->attached.reg << "\t" << instr->attached.index;
+ break;
case Instr::ConvertIntToReal:
qWarning().nospace() << "ConvertIntToReal" << "\t" << instr->unaryop.output << "\t" << instr->unaryop.src;
break;
@@ -836,7 +871,7 @@ void QmlBindingVME::dump(const QByteArray &programData)
qWarning().nospace() << "FindProperty" << "\t\t" << instr->find.reg << "\t" << instr->find.src << "\t" << instr->find.typeReg << "\t" << instr->find.name;
break;
case Instr::FindPropertyTerminal:
- qWarning().nospace() << "FindPropertyTerminal" << "\t\t" << instr->find.reg << "\t" << instr->find.src << "\t" << instr->find.typeReg << "\t" << instr->find.name;
+ qWarning().nospace() << "FindPropertyTerminal" << "\t" << instr->find.reg << "\t" << instr->find.src << "\t" << instr->find.typeReg << "\t" << instr->find.name;
break;
case Instr::CleanupGeneric:
qWarning().nospace() << "CleanupGeneric" << "\t\t" << instr->cleanup.reg << "\t" << instr->cleanup.typeReg;
@@ -844,6 +879,9 @@ void QmlBindingVME::dump(const QByteArray &programData)
case Instr::ConvertGenericToReal:
qWarning().nospace() << "ConvertGenericToReal" << "\t" << instr->genericunaryop.output << "\t" << instr->genericunaryop.src << "\t" << instr->genericunaryop.srcType;
break;
+ case Instr::ConvertGenericToBool:
+ qWarning().nospace() << "ConvertGenericToBool" << "\t" << instr->genericunaryop.output << "\t" << instr->genericunaryop.src << "\t" << instr->genericunaryop.srcType;
+ break;
case Instr::ConvertGenericToString:
qWarning().nospace() << "ConvertGenericToString" << "\t" << instr->genericunaryop.output << "\t" << instr->genericunaryop.src << "\t" << instr->genericunaryop.srcType;
break;
@@ -881,14 +919,15 @@ bool QmlBindingCompiler::compile(QmlJS::AST::Node *node)
Instr init;
init.type = Instr::Init;
- init.init.subscriptions = subscriptionSet.count();
+ init.init.subscriptions = subscriptionIds.count();
init.init.identifiers = strings;
bytecode.prepend(init);
}
if (type.unknownType) {
if (destination->type != QMetaType::QReal &&
- destination->type != QVariant::String)
+ destination->type != QVariant::String &&
+ destination->type != QMetaType::Bool)
return false;
int convertReg = acquireReg();
@@ -907,6 +946,13 @@ bool QmlBindingCompiler::compile(QmlJS::AST::Node *node)
convert.genericunaryop.src = type.reg;
convert.genericunaryop.srcType = 2; // XXX
bytecode << convert;
+ } else if (destination->type == QMetaType::Bool) {
+ Instr convert;
+ convert.type = Instr::ConvertGenericToBool;
+ convert.genericunaryop.output = convertReg;
+ convert.genericunaryop.src = type.reg;
+ convert.genericunaryop.srcType = 2; // XXX
+ bytecode << convert;
}
Instr cleanup;
@@ -1025,6 +1071,8 @@ bool QmlBindingCompiler::parseName(AST::Node *node, Result &type)
QStringList subscribeName;
+ bool wasAttachedObject = false;
+
for (int ii = 0; ii < nameParts.count(); ++ii) {
const QString &name = nameParts.at(ii);
@@ -1032,13 +1080,47 @@ bool QmlBindingCompiler::parseName(AST::Node *node, Result &type)
if (name.length() > 2 && name.startsWith(QLatin1String("on")) &&
name.at(2).isUpper())
return false;
- if (name.at(0).isUpper())
- return false;
+ QmlType *attachType = 0;
+ if (name.at(0).isUpper()) {
+ // Could be an attached property
+ if (ii == nameParts.count() - 1)
+ return false;
+ if (nameParts.at(ii + 1).at(0).isUpper())
+ return false;
+
+ QmlEnginePrivate::ImportedNamespace *ns = 0;
+ if (!engine->resolveType(imports, name.toUtf8(), &attachType, 0, 0, 0, &ns))
+ return false;
+ if (ns || !attachType || !attachType->attachedPropertiesType())
+ return false;
+
+ wasAttachedObject = true;
+ }
if (ii == 0) {
- if (ids.contains(name)) {
+ if (attachType) {
+ Instr instr;
+ instr.type = Instr::LoadScope;
+ instr.load.index = 0;
+ instr.load.reg = reg;
+ bytecode << instr;
+
+ Instr attach;
+ attach.type = Instr::LoadAttached;
+ attach.attached.output = reg;
+ attach.attached.reg = reg;
+ attach.attached.index = attachType->index();
+ bytecode << attach;
+
+ absType = 0;
+ type.metaObject = attachType->attachedPropertiesType();
+
+ subscribeName << QLatin1String("$$$ATTACH_") + name;
+
+ continue;
+ } else if (ids.contains(name)) {
QmlParser::Object *idObject = ids.value(name);
absType = idObject;
type.metaObject = absType->metaObject();
@@ -1066,10 +1148,10 @@ bool QmlBindingCompiler::parseName(AST::Node *node, Result &type)
subscribeName << QLatin1String("$$$ID_") + name;
- if (subscription(subscribeName)) {
+ if (subscription(subscribeName, &type)) {
Instr sub;
sub.type = Instr::SubscribeId;
- sub.subscribe.offset = subscriptionSet.count() - 1;
+ sub.subscribe.offset = subscriptionIndex(subscribeName);
sub.subscribe.reg = reg;
sub.subscribe.index = instr.load.index;
bytecode << sub;
@@ -1121,8 +1203,8 @@ bool QmlBindingCompiler::parseName(AST::Node *node, Result &type)
find.find.name = registerString(name);
subscribeName << QString(QLatin1String("$$$Generic_") + name);
- if (subscription(subscribeName))
- find.find.subscribeIndex = subscriptionSet.count() - 1;
+ if (subscription(subscribeName, &type))
+ find.find.subscribeIndex = subscriptionIndex(subscribeName);
else
find.find.subscribeIndex = -1;
@@ -1136,6 +1218,21 @@ bool QmlBindingCompiler::parseName(AST::Node *node, Result &type)
} else {
+ if (attachType) {
+ Instr attach;
+ attach.type = Instr::LoadAttached;
+ attach.attached.output = reg;
+ attach.attached.reg = reg;
+ attach.attached.index = attachType->index();
+ bytecode << attach;
+
+ absType = 0;
+ type.metaObject = attachType->attachedPropertiesType();
+
+ subscribeName << QLatin1String("$$$ATTACH_") + name;
+ continue;
+ }
+
const QMetaObject *mo = 0;
if (absType)
mo = absType->metaObject();
@@ -1150,7 +1247,7 @@ bool QmlBindingCompiler::parseName(AST::Node *node, Result &type)
subscribeName << name;
- if (absType || (mo && mo->property(idx).isFinal())) {
+ if (absType || (wasAttachedObject && idx != -1) || (mo && mo->property(idx).isFinal())) {
absType = 0;
type = fetch(mo, reg, idx, subscribeName);
if (type.type == -1)
@@ -1167,8 +1264,8 @@ bool QmlBindingCompiler::parseName(AST::Node *node, Result &type)
prop.find.src = reg;
prop.find.typeReg = 2; // XXX
prop.find.name = registerString(name);
- if (subscription(subscribeName))
- prop.find.subscribeIndex = subscriptionSet.count() - 1;
+ if (subscription(subscribeName, &type))
+ prop.find.subscribeIndex = subscriptionIndex(subscribeName);
else
prop.find.subscribeIndex = -1;
@@ -1179,6 +1276,8 @@ bool QmlBindingCompiler::parseName(AST::Node *node, Result &type)
bytecode << prop;
}
}
+
+ wasAttachedObject = false;
}
return true;
@@ -1335,7 +1434,9 @@ bool QmlBindingCompiler::parseConditional(QmlJS::AST::Node *node, Result &type)
// Release to allow reuse of reg
releaseReg(etype.reg);
- int preConditionalSubscriptions = subscriptionSet.count();
+ QSet<QString> preSubSet = subscriptionSet;
+
+ // int preConditionalSubscriptions = subscriptionSet.count();
Result ok;
if (!parseExpression(expression->ok, ok)) return false;
@@ -1349,6 +1450,8 @@ bool QmlBindingCompiler::parseConditional(QmlJS::AST::Node *node, Result &type)
releaseReg(ok.reg);
bytecode[skipIdx].skip.count = bytecode.count() - skipIdx - 1;
+ subscriptionSet = preSubSet;
+
Result ko;
if (!parseExpression(expression->ko, ko)) return false;
if (ko.unknownType) return false;
@@ -1360,7 +1463,9 @@ bool QmlBindingCompiler::parseConditional(QmlJS::AST::Node *node, Result &type)
if (ok != ko)
return false; // Must be same type and in same register
- if (preConditionalSubscriptions != subscriptionSet.count())
+ subscriptionSet = preSubSet;
+
+ if (!subscriptionNeutral(subscriptionSet, ok.subscriptionSet, ko.subscriptionSet))
return false; // Conditionals cannot introduce new subscriptions
type = ok;
@@ -1434,10 +1539,11 @@ QmlBindingCompiler::Result
QmlBindingCompiler::fetch(const QMetaObject *mo, int reg, int idx, const QStringList &subName)
{
QMetaProperty prop = mo->property(idx);
- if (subscription(subName) && prop.hasNotifySignal() && prop.notifySignalIndex() != -1) {
+ Result rv;
+ if (subscription(subName, &rv) && prop.hasNotifySignal() && prop.notifySignalIndex() != -1) {
Instr sub;
sub.type = Instr::Subscribe;
- sub.subscribe.offset = subscriptionSet.count() - 1;
+ sub.subscribe.offset = subscriptionIndex(subName);
sub.subscribe.reg = reg;
sub.subscribe.index = prop.notifySignalIndex();
bytecode << sub;
@@ -1450,7 +1556,6 @@ QmlBindingCompiler::fetch(const QMetaObject *mo, int reg, int idx, const QString
instr.fetch.output = reg;
bytecode << instr;
- Result rv;
rv.type = prop.userType();
rv.metaObject = QmlMetaType::metaObjectForType(rv.type);
rv.reg = reg;
@@ -1503,9 +1608,10 @@ int QmlBindingCompiler::registerString(const QString &string)
return strings - 1;
}
-bool QmlBindingCompiler::subscription(const QStringList &sub)
+bool QmlBindingCompiler::subscription(const QStringList &sub, Result *result)
{
QString str = sub.join(QLatin1String("."));
+ result->subscriptionSet.insert(str);
if (subscriptionSet.contains(str)) {
return false;
@@ -1515,5 +1621,32 @@ bool QmlBindingCompiler::subscription(const QStringList &sub)
}
}
+int QmlBindingCompiler::subscriptionIndex(const QStringList &sub)
+{
+ QString str = sub.join(QLatin1String("."));
+ QHash<QString, int>::ConstIterator iter = subscriptionIds.find(str);
+ if (iter == subscriptionIds.end())
+ iter = subscriptionIds.insert(str, subscriptionIds.count());
+ return *iter;
+}
+
+/*
+ Returns true if lhs contains no subscriptions that aren't also in base or rhs AND
+ rhs contains no subscriptions that aren't also in base or lhs.
+*/
+bool QmlBindingCompiler::subscriptionNeutral(const QSet<QString> &base,
+ const QSet<QString> &lhs,
+ const QSet<QString> &rhs)
+{
+ QSet<QString> difflhs = lhs;
+ difflhs.subtract(rhs);
+ QSet<QString> diffrhs = rhs;
+ diffrhs.subtract(lhs);
+
+ difflhs.unite(diffrhs);
+ difflhs.subtract(base);
+
+ return difflhs.isEmpty();
+}
QT_END_NAMESPACE
diff --git a/src/declarative/qml/qmlbindingvme_p.h b/src/declarative/qml/qmlbindingvme_p.h
index 9a0239d..a01c308 100644
--- a/src/declarative/qml/qmlbindingvme_p.h
+++ b/src/declarative/qml/qmlbindingvme_p.h
@@ -80,7 +80,7 @@ public:
QScriptDeclarativeClass::PersistentIdentifier *identifiers;
};
- static QByteArray compile(const QmlBasicScript::Expression &);
+ static QByteArray compile(const QmlBasicScript::Expression &, QmlEnginePrivate *);
static void run(const char *program,
Config *config, QmlContextPrivate *context,
QObject **scopes, QObject **outputs);
diff --git a/src/declarative/qml/qmlcompiler.cpp b/src/declarative/qml/qmlcompiler.cpp
index fa7da95..34608d6 100644
--- a/src/declarative/qml/qmlcompiler.cpp
+++ b/src/declarative/qml/qmlcompiler.cpp
@@ -2536,12 +2536,13 @@ bool QmlCompiler::completeComponentBuild()
expr.context = binding.bindingContext.object;
expr.property = binding.property;
expr.expression = binding.expression;
+ expr.imports = unit->imports;
bs.compile(expr);
if (qmlExperimental() && (!bs.isValid() || (!bs.isSingleIdFetch() && !bs.isSingleContextProperty()))) {
- QByteArray qmvdata = QmlBindingVME::compile(expr);
+ QByteArray qmvdata = QmlBindingVME::compile(expr, QmlEnginePrivate::get(engine));
if (!qmvdata.isEmpty()) {
qWarning() << expr.expression.asScript();
QmlBindingVME::dump(qmvdata);
@@ -2566,6 +2567,7 @@ bool QmlCompiler::completeComponentBuild()
// Pre-rewrite the expression
QString expression = binding.expression.asScript();
+ qWarning() << "Unoptimized" << expression;
// ### Optimize
QmlRewrite::SharedBindingTester sharableTest;
diff --git a/src/declarative/qml/qmlengine_p.h b/src/declarative/qml/qmlengine_p.h
index 1d83d0f..c3db6cf 100644
--- a/src/declarative/qml/qmlengine_p.h
+++ b/src/declarative/qml/qmlengine_p.h
@@ -59,7 +59,6 @@
#include "qmlcompositetypemanager_p.h"
#include "qpodvector_p.h"
#include "qml.h"
-#include "qmlbasicscript_p.h"
#include "qmlvaluetype_p.h"
#include "qmlcontext.h"
#include "qmlexpression.h"
@@ -86,7 +85,6 @@ class QmlContext;
class QmlEngine;
class QmlContextPrivate;
class QmlExpression;
-class QmlBasicScriptNodeCache;
class QmlContextScriptClass;
class QmlObjectScriptClass;
class QmlTypeNameScriptClass;