summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorAaron Kennedy <aaron.kennedy@nokia.com>2009-12-16 05:31:19 (GMT)
committerAaron Kennedy <aaron.kennedy@nokia.com>2009-12-16 05:31:19 (GMT)
commit0bd5787e4d4c89fd860ff70bcdb0ddb9e4a4f8db (patch)
tree16f14c8316464650177ea6a0a38bb7a2dba0b0c2 /src
parentdbd48151f6260743056edd9b906fc28acd02b390 (diff)
downloadQt-0bd5787e4d4c89fd860ff70bcdb0ddb9e4a4f8db.zip
Qt-0bd5787e4d4c89fd860ff70bcdb0ddb9e4a4f8db.tar.gz
Qt-0bd5787e4d4c89fd860ff70bcdb0ddb9e4a4f8db.tar.bz2
Binding optimizer extensions
Diffstat (limited to 'src')
-rw-r--r--src/declarative/qml/qmlbinding.cpp5
-rw-r--r--src/declarative/qml/qmlbinding.h2
-rw-r--r--src/declarative/qml/qmlbindingoptimizations.cpp112
-rw-r--r--src/declarative/qml/qmlbindingoptimizations_p.h54
-rw-r--r--src/declarative/qml/qmlbindingvme.cpp324
-rw-r--r--src/declarative/qml/qmlbindingvme_p.h25
-rw-r--r--src/declarative/qml/qmlcompiler.cpp29
-rw-r--r--src/declarative/qml/qmlcompiler_p.h4
-rw-r--r--src/declarative/qml/qmlengine.cpp2
-rw-r--r--src/declarative/qml/qmlinstruction_p.h1
-rw-r--r--src/declarative/qml/qmlvme.cpp22
11 files changed, 408 insertions, 172 deletions
diff --git a/src/declarative/qml/qmlbinding.cpp b/src/declarative/qml/qmlbinding.cpp
index 56d5807..d1a8fe8 100644
--- a/src/declarative/qml/qmlbinding.cpp
+++ b/src/declarative/qml/qmlbinding.cpp
@@ -276,6 +276,11 @@ QmlAbstractBinding::~QmlAbstractBinding()
*m_mePtr = 0;
}
+void QmlAbstractBinding::destroy()
+{
+ delete this;
+}
+
void QmlAbstractBinding::addToObject(QObject *object)
{
Q_ASSERT(object);
diff --git a/src/declarative/qml/qmlbinding.h b/src/declarative/qml/qmlbinding.h
index 6f2d4f1..177a0fd 100644
--- a/src/declarative/qml/qmlbinding.h
+++ b/src/declarative/qml/qmlbinding.h
@@ -61,6 +61,8 @@ public:
QmlAbstractBinding();
virtual ~QmlAbstractBinding();
+ virtual void destroy();
+
virtual QString expression() const;
void setEnabled(bool e) { setEnabled(e, QmlMetaProperty::DontRemoveBinding); }
diff --git a/src/declarative/qml/qmlbindingoptimizations.cpp b/src/declarative/qml/qmlbindingoptimizations.cpp
index 120e07b..d8a2de0 100644
--- a/src/declarative/qml/qmlbindingoptimizations.cpp
+++ b/src/declarative/qml/qmlbindingoptimizations.cpp
@@ -47,32 +47,50 @@
QT_BEGIN_NAMESPACE
-int QmlBinding_Basic::reevalIndex = -1;
+int QmlOptimizedBindings::methodCount = -1;
-QmlBinding_Basic::QmlBinding_Basic(QObject *target, int property,
- const char *data, QmlRefCount *ref,
- QObject *scope, QmlContext *context)
-: m_enabled(false), m_updating(false), m_scope(scope), m_target(target),
- m_property(property), m_data(data)
+QmlOptimizedBindings::QmlOptimizedBindings(const char *program, QmlContext *context)
+: m_program(program)
{
- if (reevalIndex == -1)
- reevalIndex = QmlBinding_Basic::staticMetaObject.indexOfSlot("reeval()");
+ if (methodCount == -1)
+ methodCount = QmlOptimizedBindings::staticMetaObject.methodCount();
m_config.target = this;
- m_config.targetSlot = reevalIndex;
- m_scope2 = m_scope;
+ m_config.targetSlot = metaObject()->methodCount();
+
+ quint32 bindings = 0;
+ QmlBindingVME::init(m_program, &m_config, &m_signalTable, &bindings);
+
+ m_bindings = new Binding[bindings];
QmlAbstractExpression::setContext(context);
}
-QmlBinding_Basic::~QmlBinding_Basic()
+QmlOptimizedBindings::~QmlOptimizedBindings()
{
+ delete [] m_bindings;
}
-void QmlBinding_Basic::setEnabled(bool e, QmlMetaProperty::WriteFlags flags)
+QmlAbstractBinding *QmlOptimizedBindings::configBinding(int index, QObject *target,
+ QObject *scope, int property)
+{
+ Binding *rv = m_bindings + index;
+
+ rv->index = index;
+ rv->property = property;
+ rv->target = target;
+ rv->scope = scope;
+ rv->parent = this;
+
+ addref(); // This is decremented in Binding::destroy()
+
+ return rv;
+}
+
+void QmlOptimizedBindings::Binding::setEnabled(bool e, QmlMetaProperty::WriteFlags flags)
{
if (e) {
- addToObject(m_target);
+ addToObject(target);
update(flags);
} else {
removeFromObject();
@@ -80,56 +98,74 @@ void QmlBinding_Basic::setEnabled(bool e, QmlMetaProperty::WriteFlags flags)
QmlAbstractBinding::setEnabled(e, flags);
- if (m_enabled != e) {
- m_enabled = e;
+ if (enabled != e) {
+ enabled = e;
if (e) update(flags);
}
}
-int QmlBinding_Basic::propertyIndex()
+int QmlOptimizedBindings::Binding::propertyIndex()
{
- return m_property & 0xFFFF;
+ return property & 0xFFFF;
}
-void QmlBinding_Basic::update(QmlMetaProperty::WriteFlags flags)
+void QmlOptimizedBindings::Binding::update(QmlMetaProperty::WriteFlags)
{
- if (!m_enabled)
- return;
+ parent->run(this);
+}
- if (m_updating) {
- qmlInfo(m_target) << tr("Binding loop detected");
- return;
+void QmlOptimizedBindings::Binding::destroy()
+{
+ enabled = false;
+ removeFromObject();
+ parent->release();
+}
+
+int QmlOptimizedBindings::qt_metacall(QMetaObject::Call c, int id, void **)
+{
+ if (c == QMetaObject::InvokeMetaMethod && id >= methodCount) {
+ id -= methodCount;
+
+ quint32 *reeval = m_signalTable + m_signalTable[id];
+ quint32 count = *reeval;
+ ++reeval;
+ for (quint32 ii = 0; ii < count; ++ii) {
+ run(m_bindings + reeval[ii]);
+ }
}
+ return -1;
+}
+
+void QmlOptimizedBindings::run(Binding *binding)
+{
+ if (!binding->enabled)
+ return;
+ if (binding->updating)
+ qWarning("ERROR: Circular binding");
QmlContext *context = QmlAbstractExpression::context();
if (!context)
return;
QmlContextPrivate *cp = QmlContextPrivate::get(context);
- m_updating = true;
-
- if (m_property & 0xFFFF0000) {
+ if (binding->property & 0xFFFF0000) {
QmlEnginePrivate *ep = QmlEnginePrivate::get(cp->engine);
- QmlValueType *vt = ep->valueTypes[(m_property >> 16) & 0xFF];
+ QmlValueType *vt = ep->valueTypes[(binding->property >> 16) & 0xFF];
Q_ASSERT(vt);
- vt->read(m_target, m_property & 0xFFFF);
+ vt->read(binding->target, binding->property & 0xFFFF);
QObject *target = vt;
- QmlBindingVME::run(m_data, &m_config, cp, &m_scope, &target);
+ QmlBindingVME::run(m_program, binding->index, &m_config, cp,
+ &binding->scope, &target);
- vt->write(m_target, m_property & 0xFFFF, flags);
+ vt->write(binding->target, binding->property & 0xFFFF,
+ QmlMetaProperty::DontRemoveBinding);
} else {
- QmlBindingVME::run(m_data, &m_config, cp, &m_scope, &m_target);
+ QmlBindingVME::run(m_program, binding->index, &m_config, cp,
+ &binding->scope, &binding->target);
}
-
- m_updating = false;
-}
-
-void QmlBinding_Basic::reeval()
-{
- update(QmlMetaProperty::DontRemoveBinding);
}
/*
diff --git a/src/declarative/qml/qmlbindingoptimizations_p.h b/src/declarative/qml/qmlbindingoptimizations_p.h
index ee2eb83..6289cc0 100644
--- a/src/declarative/qml/qmlbindingoptimizations_p.h
+++ b/src/declarative/qml/qmlbindingoptimizations_p.h
@@ -62,36 +62,44 @@ QT_BEGIN_HEADER
QT_BEGIN_NAMESPACE
-class QmlBinding_Basic : public QObject,
- public QmlAbstractExpression,
- public QmlAbstractBinding
+class QmlOptimizedBindings : public QObject, public QmlAbstractExpression, public QmlRefCount
{
- Q_OBJECT
public:
- QmlBinding_Basic(QObject *target, int property,
- const char *data, QmlRefCount *ref,
- QObject *scope, QmlContext *context);
- virtual ~QmlBinding_Basic();
+ QmlOptimizedBindings(const char *program, QmlContext *context);
+ virtual ~QmlOptimizedBindings();
+ QmlAbstractBinding *configBinding(int index, QObject *target, QObject *scope, int property);
- // Inherited from QmlAbstractBinding
- virtual void setEnabled(bool, QmlMetaProperty::WriteFlags flags);
- virtual int propertyIndex();
- virtual void update(QmlMetaProperty::WriteFlags flags);
-
-private slots:
- void reeval();
+protected:
+ int qt_metacall(QMetaObject::Call, int, void **);
private:
- bool m_enabled:1;
- bool m_updating:1;
- QObject *m_scope;
- QObject *m_target;
- int m_property;
- const char *m_data;
+ struct Binding : public QmlAbstractBinding {
+ Binding() : enabled(false), updating(0), property(0),
+ scope(0), target(0), parent(0) {}
+
+ // Inherited from QmlAbstractBinding
+ virtual void setEnabled(bool, QmlMetaProperty::WriteFlags flags);
+ virtual int propertyIndex();
+ virtual void update(QmlMetaProperty::WriteFlags flags);
+ virtual void destroy();
+
+ int index:30;
+ bool enabled:1;
+ bool updating:1;
+ int property;
+ QObject *scope;
+ QObject *target;
+
+ QmlOptimizedBindings *parent;
+ };
+ void run(Binding *);
+
QmlBindingVME::Config m_config;
- QGuard<QObject> m_scope2;
+ const char *m_program;
+ Binding *m_bindings;
+ quint32 *m_signalTable;
- static int reevalIndex;
+ static int methodCount;
};
class QmlBinding_Id : public QmlAbstractExpression,
diff --git a/src/declarative/qml/qmlbindingvme.cpp b/src/declarative/qml/qmlbindingvme.cpp
index e5cbdfc..d85d7ba 100644
--- a/src/declarative/qml/qmlbindingvme.cpp
+++ b/src/declarative/qml/qmlbindingvme.cpp
@@ -79,8 +79,6 @@ struct Instr {
enum {
Noop,
- Init, // init
-
Subscribe, // subscribe
SubscribeId, // subscribe
@@ -224,13 +222,18 @@ struct Instr {
};
struct Program {
- int dataLength;
+ quint32 bindings;
+ quint32 dataLength;
+ quint32 signalTableOffset;
+ quint16 subscriptions;
+ quint16 identifiers;
+
const char *data() const { return ((const char *)this) + sizeof(Program); }
const Instr *instructions() const { return (const Instr *)(data() + dataLength); }
};
}
-struct QmlBindingCompiler
+struct QmlBindingCompilerPrivate
{
struct Result {
Result() : unknownType(false), metaObject(0), type(-1), reg(-1) {}
@@ -251,8 +254,12 @@ struct QmlBindingCompiler
QSet<QString> subscriptionSet;
};
- QmlBindingCompiler() : registers(0), strings(0) {}
- void reset();
+ QmlBindingCompilerPrivate() : registers(0), strings(0) {
+ committed.strings = 0;
+ }
+
+ void resetInstanceState();
+ int commitCompile();
QmlParser::Object *context;
QmlParser::Object *component;
@@ -261,6 +268,8 @@ struct QmlBindingCompiler
QmlEnginePrivate::Imports imports;
QmlEnginePrivate *engine;
+ QString contextName() const { return QLatin1String("$$$SCOPE_") + QString::number((intptr_t)context, 16); }
+
bool compile(QmlJS::AST::Node *);
bool parseExpression(QmlJS::AST::Node *, Result &);
@@ -293,60 +302,44 @@ struct QmlBindingCompiler
int strings;
QByteArray data;
- QSet<QString> subscriptionSet;
- 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, QmlEnginePrivate *engine)
-{
- if (!expression.expression.asAST()) return false;
+ QSet<int> usedSubscriptionIds;
+ QSet<QString> subscriptionSet;
+ QHash<QString, int> subscriptionIds;
+ QVector<Instr> bytecode;
- QmlBindingCompiler bsc;
- bsc.context = expression.context;
- bsc.component = expression.component;
- bsc.destination = expression.property;
- bsc.ids = expression.ids;
- bsc.imports = expression.imports;
- bsc.engine = engine;
+ // Committed binding data
+ struct {
+ QList<int> offsets;
+ QList<QSet<int> > dependencies;
- bool ok = bsc.compile(expression.expression.asAST());
+ QVector<Instr> bytecode;
+ QByteArray data;
+ int strings;
+ QHash<QString, int> subscriptionIds;
- if (ok) {
- Program prog;
- prog.dataLength = 4 * ((bsc.data.size() + 3) / 4);
- int size = sizeof(Program) + bsc.bytecode.count() * sizeof(Instr);
- size += prog.dataLength;
+ int count() const { return offsets.count(); }
+ } committed;
- QByteArray data;
- data.resize(size);
- memcpy(data.data(), &prog, sizeof(Program));
- if (prog.dataLength)
- memcpy((char *)((Program *)data.data())->data(), bsc.data.constData(),
- bsc.data.size());
- memcpy((char *)((Program *)data.data())->instructions(), bsc.bytecode.constData(),
- bsc.bytecode.count() * sizeof(Instr));
- return data;
- } else {
- return QByteArray();
- }
-}
+ QByteArray buildSignalTable() const;
+};
-inline void subscribe(QObject *o, int notifyIndex, QmlBindingVME::Config::Subscription *s,
- QmlBindingVME::Config *config)
+inline void subscribe(QObject *o, int notifyIndex,
+ int subIndex, QmlBindingVME::Config *config)
{
+ QmlBindingVME::Config::Subscription *s = config->subscriptions + subIndex;
if (o != s->source || notifyIndex != s->notifyIndex) {
if (s->source)
QMetaObject::disconnect(s->source, s->notifyIndex,
- config->target, config->targetSlot);
+ config->target, config->targetSlot + subIndex);
s->source = o;
s->notifyIndex = notifyIndex;
- if (s->source && s->notifyIndex != -1)
+ if (s->source && s->notifyIndex != -1)
QMetaObject::connect(s->source, s->notifyIndex, config->target,
- config->targetSlot, Qt::DirectConnection);
+ config->targetSlot + subIndex, Qt::DirectConnection);
}
}
@@ -436,7 +429,7 @@ static bool findproperty(QObject *obj,
}
if (subIdx != -1)
- subscribe(obj, property->notifyIndex, config->subscriptions + subIdx, config);
+ subscribe(obj, property->notifyIndex, subIdx, config);
return true;
} else {
@@ -588,8 +581,24 @@ inline static QUrl toUrl(Register *reg, int type, QmlContextPrivate *context, bo
return base;
}
-void QmlBindingVME::run(const char *programData, Config *config,
- QmlContextPrivate *context,
+/*!
+Returns the signal/binding table.
+*/
+void QmlBindingVME::init(const char *programData, Config *config,
+ quint32 **sigTable, quint32 *bindingCount)
+{
+ Program *program = (Program *)programData;
+ if (program->subscriptions)
+ config->subscriptions = new Config::Subscription[program->subscriptions];
+ if (program->identifiers)
+ config->identifiers = new QScriptDeclarativeClass::PersistentIdentifier[program->identifiers];
+
+ *sigTable = (quint32 *)(program->data() + program->signalTableOffset);
+ *bindingCount = program->bindings;
+}
+
+void QmlBindingVME::run(const char *programData, int instrIndex,
+ Config *config, QmlContextPrivate *context,
QObject **scopes, QObject **outputs)
{
Register registers[32];
@@ -598,6 +607,7 @@ void QmlBindingVME::run(const char *programData, Config *config,
QmlEnginePrivate *engine = QmlEnginePrivate::get(context->engine);
Program *program = (Program *)programData;
const Instr *instr = program->instructions();
+ instr += instrIndex;
const char *data = program->data();
while (instr) {
@@ -605,18 +615,11 @@ void QmlBindingVME::run(const char *programData, Config *config,
switch (instr->type) {
case Instr::Noop:
break;
- case Instr::Init:
- if (!config->subscriptions && instr->init.subscriptions)
- config->subscriptions = new Config::Subscription[instr->init.subscriptions];
- if (!config->identifiers && instr->init.identifiers)
- config->identifiers = new QScriptDeclarativeClass::PersistentIdentifier[instr->init.identifiers];
- break;
case Instr::SubscribeId:
case Instr::Subscribe:
{
QObject *o = registers[instr->subscribe.reg].getQObject();
- Config::Subscription *s = config->subscriptions + instr->subscribe.offset;
int notifyIndex = instr->subscribe.index;
if (instr->type == Instr::SubscribeId) {
@@ -624,7 +627,7 @@ void QmlBindingVME::run(const char *programData, Config *config,
notifyIndex += context->notifyIndex;
}
- subscribe(o, instr->subscribe.index, s, config);
+ subscribe(o, instr->subscribe.index, instr->subscribe.offset, config);
}
break;
@@ -852,6 +855,11 @@ void QmlBindingVME::dump(const QByteArray &programData)
{
const Program *program = (const Program *)programData.constData();
+ qWarning() << "Program.bindings:" << program->bindings;
+ qWarning() << "Program.dataLength:" << program->dataLength;
+ qWarning() << "Program.subscriptions:" << program->subscriptions;
+ qWarning() << "Program.indentifiers:" << program->identifiers;
+
int count = (programData.size() - sizeof(Program) - program->dataLength) / sizeof(Instr);
const Instr *instr = program->instructions();
@@ -861,9 +869,6 @@ void QmlBindingVME::dump(const QByteArray &programData)
case Instr::Noop:
qWarning().nospace() << "Noop";
break;
- case Instr::Init:
- qWarning().nospace() << "Init" << "\t\t\t" << instr->init.subscriptions << "\t" << instr->init.identifiers;
- break;
case Instr::Subscribe:
qWarning().nospace() << "Subscribe" << "\t\t" << instr->subscribe.offset << "\t" << instr->subscribe.reg << "\t" << instr->subscribe.index;
break;
@@ -990,18 +995,42 @@ void QmlBindingVME::dump(const QByteArray &programData)
}
}
-void QmlBindingCompiler::reset()
+/*!
+Clear the state associated with attempting to compile a specific binding.
+This does not clear the global "commited binding" states.
+*/
+void QmlBindingCompilerPrivate::resetInstanceState()
{
registers = 0;
- strings = 0;
- data.clear();
+ strings = committed.strings;
+ data = committed.data;
+ subscriptionIds = committed.subscriptionIds;
subscriptionSet.clear();
+ usedSubscriptionIds.clear();
bytecode.clear();
}
-bool QmlBindingCompiler::compile(QmlJS::AST::Node *node)
+/*!
+Mark the last compile as successful, and add it to the "committed data"
+section.
+
+Returns the index for the committed binding.
+*/
+int QmlBindingCompilerPrivate::commitCompile()
{
- reset();
+ int rv = committed.count();
+ committed.offsets << committed.bytecode.count();
+ committed.dependencies << usedSubscriptionIds;
+ committed.bytecode << bytecode;
+ committed.data = data;
+ committed.strings = strings;
+ committed.subscriptionIds = subscriptionIds;
+ return rv;
+}
+
+bool QmlBindingCompilerPrivate::compile(QmlJS::AST::Node *node)
+{
+ resetInstanceState();
Result type;
@@ -1012,12 +1041,6 @@ bool QmlBindingCompiler::compile(QmlJS::AST::Node *node)
if (subscriptionSet.count() > 0xFFFF ||
strings > 0xFFFF)
return false;
-
- Instr init;
- init.type = Instr::Init;
- init.init.subscriptions = subscriptionIds.count();
- init.init.identifiers = strings;
- bytecode.prepend(init);
}
if (type.unknownType) {
@@ -1141,7 +1164,7 @@ bool QmlBindingCompiler::compile(QmlJS::AST::Node *node)
}
}
-bool QmlBindingCompiler::parseExpression(QmlJS::AST::Node *node, Result &type)
+bool QmlBindingCompilerPrivate::parseExpression(QmlJS::AST::Node *node, Result &type)
{
while (node->kind == AST::Node::Kind_NestedExpression)
node = static_cast<AST::NestedExpression *>(node)->expression;
@@ -1162,13 +1185,13 @@ bool QmlBindingCompiler::parseExpression(QmlJS::AST::Node *node, Result &type)
return true;
}
-bool QmlBindingCompiler::tryName(QmlJS::AST::Node *node)
+bool QmlBindingCompilerPrivate::tryName(QmlJS::AST::Node *node)
{
return node->kind == AST::Node::Kind_IdentifierExpression ||
node->kind == AST::Node::Kind_FieldMemberExpression;
}
-bool QmlBindingCompiler::parseName(AST::Node *node, Result &type)
+bool QmlBindingCompilerPrivate::parseName(AST::Node *node, Result &type)
{
QStringList nameParts;
if (!buildName(nameParts, node))
@@ -1226,11 +1249,12 @@ bool QmlBindingCompiler::parseName(AST::Node *node, Result &type)
attach.attached.index = attachType->index();
bytecode << attach;
+ subscribeName << contextName();
+ subscribeName << QLatin1String("$$$ATTACH_") + name;
+
absType = 0;
type.metaObject = attachType->attachedPropertiesType();
- subscribeName << QLatin1String("$$$ATTACH_") + name;
-
continue;
} else if (ids.contains(name)) {
QmlParser::Object *idObject = ids.value(name);
@@ -1287,7 +1311,7 @@ bool QmlBindingCompiler::parseName(AST::Node *node, Result &type)
instr.load.reg = reg;
bytecode << instr;
- subscribeName << QLatin1String("$$$Scope");
+ subscribeName << contextName();
subscribeName << name;
fetch(type, context->metaObject(), reg, d0Idx, subscribeName);
@@ -1298,7 +1322,7 @@ bool QmlBindingCompiler::parseName(AST::Node *node, Result &type)
instr.load.reg = reg;
bytecode << instr;
- subscribeName << QLatin1String("$$$Root");
+ subscribeName << QLatin1String("$$$ROOT");
subscribeName << name;
fetch(type, component->metaObject(), reg, d1Idx, subscribeName);
@@ -1395,7 +1419,7 @@ bool QmlBindingCompiler::parseName(AST::Node *node, Result &type)
return true;
}
-bool QmlBindingCompiler::tryArith(QmlJS::AST::Node *node)
+bool QmlBindingCompilerPrivate::tryArith(QmlJS::AST::Node *node)
{
if (node->kind != AST::Node::Kind_BinaryExpression)
return false;
@@ -1408,7 +1432,7 @@ bool QmlBindingCompiler::tryArith(QmlJS::AST::Node *node)
return false;
}
-bool QmlBindingCompiler::parseArith(QmlJS::AST::Node *node, Result &type)
+bool QmlBindingCompilerPrivate::parseArith(QmlJS::AST::Node *node, Result &type)
{
AST::BinaryExpression *expression = static_cast<AST::BinaryExpression *>(node);
@@ -1473,7 +1497,7 @@ bool QmlBindingCompiler::parseArith(QmlJS::AST::Node *node, Result &type)
return true;
}
-bool QmlBindingCompiler::tryLogic(QmlJS::AST::Node *node)
+bool QmlBindingCompilerPrivate::tryLogic(QmlJS::AST::Node *node)
{
if (node->kind != AST::Node::Kind_BinaryExpression)
return false;
@@ -1487,7 +1511,7 @@ bool QmlBindingCompiler::tryLogic(QmlJS::AST::Node *node)
return false;
}
-bool QmlBindingCompiler::parseLogic(QmlJS::AST::Node *node, Result &type)
+bool QmlBindingCompilerPrivate::parseLogic(QmlJS::AST::Node *node, Result &type)
{
AST::BinaryExpression *expression = static_cast<AST::BinaryExpression *>(node);
@@ -1542,12 +1566,12 @@ bool QmlBindingCompiler::parseLogic(QmlJS::AST::Node *node, Result &type)
return true;
}
-bool QmlBindingCompiler::tryConditional(QmlJS::AST::Node *node)
+bool QmlBindingCompilerPrivate::tryConditional(QmlJS::AST::Node *node)
{
return (node->kind == AST::Node::Kind_ConditionalExpression);
}
-bool QmlBindingCompiler::parseConditional(QmlJS::AST::Node *node, Result &type)
+bool QmlBindingCompilerPrivate::parseConditional(QmlJS::AST::Node *node, Result &type)
{
AST::ConditionalExpression *expression = static_cast<AST::ConditionalExpression *>(node);
@@ -1610,14 +1634,14 @@ bool QmlBindingCompiler::parseConditional(QmlJS::AST::Node *node, Result &type)
return true;
}
-bool QmlBindingCompiler::tryConstant(QmlJS::AST::Node *node)
+bool QmlBindingCompilerPrivate::tryConstant(QmlJS::AST::Node *node)
{
return node->kind == AST::Node::Kind_TrueLiteral ||
node->kind == AST::Node::Kind_FalseLiteral ||
node->kind == AST::Node::Kind_NumericLiteral;
}
-bool QmlBindingCompiler::parseConstant(QmlJS::AST::Node *node, Result &type)
+bool QmlBindingCompilerPrivate::parseConstant(QmlJS::AST::Node *node, Result &type)
{
type.metaObject = 0;
type.type = -1;
@@ -1652,7 +1676,7 @@ bool QmlBindingCompiler::parseConstant(QmlJS::AST::Node *node, Result &type)
}
}
-bool QmlBindingCompiler::buildName(QStringList &name,
+bool QmlBindingCompilerPrivate::buildName(QStringList &name,
QmlJS::AST::Node *node)
{
if (node->kind == AST::Node::Kind_IdentifierExpression) {
@@ -1673,7 +1697,7 @@ bool QmlBindingCompiler::buildName(QStringList &name,
}
-bool QmlBindingCompiler::fetch(Result &rv, const QMetaObject *mo, int reg, int idx, const QStringList &subName)
+bool QmlBindingCompilerPrivate::fetch(Result &rv, const QMetaObject *mo, int reg, int idx, const QStringList &subName)
{
QMetaProperty prop = mo->property(idx);
rv.metaObject = 0;
@@ -1731,12 +1755,12 @@ bool QmlBindingCompiler::fetch(Result &rv, const QMetaObject *mo, int reg, int i
return true;
}
-void QmlBindingCompiler::registerCleanup(int reg, int cleanup, int cleanupType)
+void QmlBindingCompilerPrivate::registerCleanup(int reg, int cleanup, int cleanupType)
{
registerCleanups.insert(reg, qMakePair(cleanup, cleanupType));
}
-int QmlBindingCompiler::acquireReg(int cleanup, int cleanupType)
+int QmlBindingCompilerPrivate::acquireReg(int cleanup, int cleanupType)
{
for (int ii = 0; ii < 32; ++ii) {
if (!(registers & (1 << ii))) {
@@ -1751,7 +1775,7 @@ int QmlBindingCompiler::acquireReg(int cleanup, int cleanupType)
return -1;
}
-void QmlBindingCompiler::releaseReg(int reg)
+void QmlBindingCompilerPrivate::releaseReg(int reg)
{
Q_ASSERT(reg >= 0 && reg <= 31);
@@ -1769,7 +1793,7 @@ void QmlBindingCompiler::releaseReg(int reg)
registers &= ~mask;
}
-int QmlBindingCompiler::registerString(const QString &string)
+int QmlBindingCompilerPrivate::registerString(const QString &string)
{
Q_ASSERT(!string.isEmpty());
@@ -1788,7 +1812,7 @@ int QmlBindingCompiler::registerString(const QString &string)
return strings - 1;
}
-bool QmlBindingCompiler::subscription(const QStringList &sub, Result *result)
+bool QmlBindingCompilerPrivate::subscription(const QStringList &sub, Result *result)
{
QString str = sub.join(QLatin1String("."));
result->subscriptionSet.insert(str);
@@ -1801,12 +1825,13 @@ bool QmlBindingCompiler::subscription(const QStringList &sub, Result *result)
}
}
-int QmlBindingCompiler::subscriptionIndex(const QStringList &sub)
+int QmlBindingCompilerPrivate::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());
+ usedSubscriptionIds.insert(*iter);
return *iter;
}
@@ -1814,7 +1839,7 @@ int QmlBindingCompiler::subscriptionIndex(const QStringList &sub)
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,
+bool QmlBindingCompilerPrivate::subscriptionNeutral(const QSet<QString> &base,
const QSet<QString> &lhs,
const QSet<QString> &rhs)
{
@@ -1828,5 +1853,118 @@ bool QmlBindingCompiler::subscriptionNeutral(const QSet<QString> &base,
return difflhs.isEmpty();
}
+
+
+QmlBindingCompiler::QmlBindingCompiler()
+: d(new QmlBindingCompilerPrivate)
+{
+}
+
+QmlBindingCompiler::~QmlBindingCompiler()
+{
+ delete d; d = 0;
+}
+
+/*
+Returns true if any bindings were compiled.
+*/
+bool QmlBindingCompiler::isValid() const
+{
+ return d->bytecode.count();
+}
+
+/*
+-1 on failure, otherwise the binding index to use.
+*/
+int QmlBindingCompiler::compile(const QmlBasicScript::Expression &expression,
+ QmlEnginePrivate *engine)
+{
+ if (!expression.expression.asAST()) return false;
+
+ d->context = expression.context;
+ d->component = expression.component;
+ d->destination = expression.property;
+ d->ids = expression.ids;
+ d->imports = expression.imports;
+ d->engine = engine;
+
+ if (d->compile(expression.expression.asAST())) {
+ return d->commitCompile();
+ } else {
+ return -1;
+ }
+}
+
+
+QByteArray QmlBindingCompilerPrivate::buildSignalTable() const
+{
+ QHash<int, QList<int> > table;
+
+ for (int ii = 0; ii < committed.count(); ++ii) {
+ const QSet<int> &deps = committed.dependencies.at(ii);
+ for (QSet<int>::ConstIterator iter = deps.begin(); iter != deps.end(); ++iter)
+ table[*iter].append(ii);
+ }
+
+ QVector<quint32> header;
+ QVector<quint32> data;
+ for (int ii = 0; ii < committed.subscriptionIds.count(); ++ii) {
+ header.append(committed.subscriptionIds.count() + data.count());
+ const QList<int> &bindings = table[ii];
+ data.append(bindings.count());
+ for (int jj = 0; jj < bindings.count(); ++jj)
+ data.append(bindings.at(jj));
+ }
+ header << data;
+
+ return QByteArray((const char *)header.constData(), header.count() * sizeof(quint32));
+}
+
+/*
+Returns the compiled program.
+*/
+QByteArray QmlBindingCompiler::program() const
+{
+ QByteArray programData;
+
+ if (isValid()) {
+ Program prog;
+ prog.bindings = d->committed.count();
+
+ QVector<Instr> bytecode;
+ Instr skip;
+ skip.type = Instr::Skip;
+ skip.skip.reg = -1;
+ for (int ii = 0; ii < d->committed.count(); ++ii) {
+ skip.skip.count = d->committed.count() - ii - 1;
+ skip.skip.count+= d->committed.offsets.at(ii);
+ bytecode << skip;
+ }
+ bytecode << d->committed.bytecode;
+
+ QByteArray data = d->committed.data;
+ while (data.count() % 4) data.append('\0');
+ prog.signalTableOffset = data.count();
+ data += d->buildSignalTable();
+
+ prog.dataLength = 4 * ((data.size() + 3) / 4);
+ prog.subscriptions = d->committed.subscriptionIds.count();
+ prog.identifiers = d->committed.strings;
+ int size = sizeof(Program) + bytecode.count() * sizeof(Instr);
+ size += prog.dataLength;
+
+ programData.resize(size);
+ memcpy(programData.data(), &prog, sizeof(Program));
+ if (prog.dataLength)
+ memcpy((char *)((Program *)programData.data())->data(), data.constData(),
+ data.size());
+ memcpy((char *)((Program *)programData.data())->instructions(), bytecode.constData(),
+ bytecode.count() * sizeof(Instr));
+ }
+
+ return programData;
+}
+
+
QT_END_NAMESPACE
diff --git a/src/declarative/qml/qmlbindingvme_p.h b/src/declarative/qml/qmlbindingvme_p.h
index a01c308..de73037 100644
--- a/src/declarative/qml/qmlbindingvme_p.h
+++ b/src/declarative/qml/qmlbindingvme_p.h
@@ -80,13 +80,34 @@ public:
QScriptDeclarativeClass::PersistentIdentifier *identifiers;
};
- static QByteArray compile(const QmlBasicScript::Expression &, QmlEnginePrivate *);
- static void run(const char *program,
+ static void init(const char *program, Config *config,
+ quint32 **sigTable, quint32 *bindingCount);
+ static void run(const char *program, int instr,
Config *config, QmlContextPrivate *context,
QObject **scopes, QObject **outputs);
static void dump(const QByteArray &);
};
+class QmlBindingCompilerPrivate;
+class QmlBindingCompiler
+{
+public:
+ QmlBindingCompiler();
+ ~QmlBindingCompiler();
+
+ // Returns true if bindings were compiled
+ bool isValid() const;
+
+ // -1 on failure, otherwise the binding index to use
+ int compile(const QmlBasicScript::Expression &, QmlEnginePrivate *);
+
+ // Returns the compiled program
+ QByteArray program() const;
+
+private:
+ QmlBindingCompilerPrivate *d;
+};
+
QT_END_NAMESPACE
QT_END_HEADER
diff --git a/src/declarative/qml/qmlcompiler.cpp b/src/declarative/qml/qmlcompiler.cpp
index 53ea18e..f25f8b8 100644
--- a/src/declarative/qml/qmlcompiler.cpp
+++ b/src/declarative/qml/qmlcompiler.cpp
@@ -643,6 +643,10 @@ void QmlCompiler::compileTree(Object *tree)
init.init.bindingsSize = compileState.bindings.count();
init.init.parserStatusSize = compileState.parserStatusCount;
init.init.contextCache = genContextCache();
+ if (compileState.compiledBindingData.isEmpty())
+ init.init.compiledBinding = -1;
+ else
+ init.init.compiledBinding = output->indexForByteArray(compileState.compiledBindingData);
output->bytecode << init;
genObject(tree);
@@ -1010,6 +1014,10 @@ void QmlCompiler::genComponent(QmlParser::Object *obj)
init.init.bindingsSize = compileState.bindings.count();
init.init.parserStatusSize = compileState.parserStatusCount;
init.init.contextCache = genContextCache();
+ if (compileState.compiledBindingData.isEmpty())
+ init.init.compiledBinding = -1;
+ else
+ init.init.compiledBinding = output->indexForByteArray(compileState.compiledBindingData);
init.line = obj->location.start.line;
output->bytecode << init;
@@ -2423,7 +2431,7 @@ void QmlCompiler::genBindingAssignment(QmlParser::Value *binding,
if (ref.dataType == BindingReference::Experimental) {
QmlInstruction store;
store.type = QmlInstruction::StoreCompiledBinding;
- store.assignBinding.value = output->indexForByteArray(ref.compiledData);
+ store.assignBinding.value = ref.compiledIndex;
store.assignBinding.context = ref.bindingContext.stack;
store.assignBinding.owner = ref.bindingContext.owner;
if (valueTypeProperty)
@@ -2529,6 +2537,8 @@ bool QmlCompiler::completeComponentBuild()
expr.component = compileState.root;
expr.ids = compileState.ids;
+ QmlBindingCompiler bindingCompiler;
+
for (QHash<QmlParser::Value*,BindingReference>::Iterator iter = compileState.bindings.begin(); iter != compileState.bindings.end(); ++iter) {
BindingReference &binding = *iter;
@@ -2541,15 +2551,15 @@ bool QmlCompiler::completeComponentBuild()
bs.compile(expr);
if (qmlExperimental() && (!bs.isValid() || (!bs.isSingleIdFetch() && !bs.isSingleContextProperty()))) {
-
- QByteArray qmvdata = QmlBindingVME::compile(expr, QmlEnginePrivate::get(engine));
- if (!qmvdata.isEmpty()) {
- qWarning() << expr.expression.asScript();
- QmlBindingVME::dump(qmvdata);
+ int index = bindingCompiler.compile(expr, QmlEnginePrivate::get(engine));
+ if (index != -1) {
+ qWarning() << "Accepted for optimization:" << qPrintable(expr.expression.asScript());
binding.dataType = BindingReference::Experimental;
- binding.compiledData = qmvdata;
+ binding.compiledIndex = index;
componentStat.optimizedBindings++;
continue;
+ } else {
+ qWarning() << "Rejected for optimization:" << qPrintable(expr.expression.asScript());
}
}
@@ -2599,6 +2609,11 @@ bool QmlCompiler::completeComponentBuild()
sizeof(quint32)));
}
+ if (bindingCompiler.isValid()) {
+ compileState.compiledBindingData = bindingCompiler.program();
+ QmlBindingVME::dump(compileState.compiledBindingData);
+ }
+
saveComponentState();
return true;
diff --git a/src/declarative/qml/qmlcompiler_p.h b/src/declarative/qml/qmlcompiler_p.h
index d734a12..3fcba15 100644
--- a/src/declarative/qml/qmlcompiler_p.h
+++ b/src/declarative/qml/qmlcompiler_p.h
@@ -273,6 +273,8 @@ private:
enum DataType { QtScript, BasicScript, Experimental };
DataType dataType;
+ int compiledIndex;
+
QByteArray compiledData;
BindingContext bindingContext;
};
@@ -287,6 +289,8 @@ private:
int parserStatusCount;
int pushedProperties;
+ QByteArray compiledBindingData;
+
QHash<QmlParser::Value *, BindingReference> bindings;
QList<QmlParser::Object *> aliasingObjects;
QmlParser::Object *root;
diff --git a/src/declarative/qml/qmlengine.cpp b/src/declarative/qml/qmlengine.cpp
index ad68c8f..6b66095 100644
--- a/src/declarative/qml/qmlengine.cpp
+++ b/src/declarative/qml/qmlengine.cpp
@@ -564,7 +564,7 @@ void QmlDeclarativeData::destroyed(QObject * /*object*/)
QmlAbstractBinding *next = binding->m_nextBinding;
binding->m_prevBinding = 0;
binding->m_nextBinding = 0;
- delete binding;
+ binding->destroy();
binding = next;
}
diff --git a/src/declarative/qml/qmlinstruction_p.h b/src/declarative/qml/qmlinstruction_p.h
index d06ac86..6e2b452 100644
--- a/src/declarative/qml/qmlinstruction_p.h
+++ b/src/declarative/qml/qmlinstruction_p.h
@@ -170,6 +170,7 @@ public:
int bindingsSize;
int parserStatusSize;
int contextCache;
+ int compiledBinding;
} init;
struct {
int type;
diff --git a/src/declarative/qml/qmlvme.cpp b/src/declarative/qml/qmlvme.cpp
index e4295a1..ae7bf51 100644
--- a/src/declarative/qml/qmlvme.cpp
+++ b/src/declarative/qml/qmlvme.cpp
@@ -161,6 +161,8 @@ QObject *QmlVME::run(QmlVMEStack<QObject *> &stack, QmlContext *ctxt,
int status = -1; //for dbus
QmlMetaProperty::WriteFlags flags = QmlMetaProperty::BypassInterceptor;
+ QmlOptimizedBindings *optimizedBindings = 0;
+
for (int ii = start; !isError() && ii < (start + count); ++ii) {
const QmlInstruction &instr = comp->bytecode.at(ii);
@@ -171,9 +173,10 @@ QObject *QmlVME::run(QmlVMEStack<QObject *> &stack, QmlContext *ctxt,
bindValues = QmlEnginePrivate::SimpleList<QmlAbstractBinding>(instr.init.bindingsSize);
if (instr.init.parserStatusSize)
parserStatus = QmlEnginePrivate::SimpleList<QmlParserStatus>(instr.init.parserStatusSize);
-
if (instr.init.contextCache != -1)
cp->setIdPropertyData(comp->contextCaches.at(instr.init.contextCache));
+ if (instr.init.compiledBinding != -1)
+ optimizedBindings = new QmlOptimizedBindings(datas.at(instr.init.compiledBinding).constData(), ctxt);
}
break;
@@ -619,13 +622,11 @@ QObject *QmlVME::run(QmlVMEStack<QObject *> &stack, QmlContext *ctxt,
if (stack.count() == 1 && bindingSkipList.testBit(property & 0xFFFF))
break;
- const char *data = datas.at(instr.assignBinding.value).constData();
-
- QmlBinding_Basic *bind =
- new QmlBinding_Basic(target, property, data, comp, scope, ctxt);
- bindValues.append(bind);
- bind->m_mePtr = &bindValues.values[bindValues.count - 1];
- bind->addToObject(target);
+ QmlAbstractBinding *binding =
+ optimizedBindings->configBinding(instr.assignBinding.value, target, scope, property);
+ bindValues.append(binding);
+ binding->m_mePtr = &bindValues.values[bindValues.count - 1];
+ binding->addToObject(target);
}
break;
@@ -894,6 +895,11 @@ QObject *QmlVME::run(QmlVMEStack<QObject *> &stack, QmlContext *ctxt,
}
}
+ if (optimizedBindings) {
+ optimizedBindings->release();
+ optimizedBindings = 0;
+ }
+
if (isError()) {
if (!stack.isEmpty()) {
delete stack.at(0);