1 /****************************************************************************
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
7 ** This file is part of the QtDeclarative module of the Qt Toolkit.
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** No Commercial Usage
11 ** This file contains pre-release code and may not be distributed.
12 ** You may use this file in accordance with the terms and conditions
13 ** contained in the Technology Preview License Agreement accompanying
16 ** GNU Lesser General Public License Usage
17 ** Alternatively, this file may be used under the terms of the GNU Lesser
18 ** General Public License version 2.1 as published by the Free Software
19 ** Foundation and appearing in the file LICENSE.LGPL included in the
20 ** packaging of this file. Please review the following information to
21 ** ensure the GNU Lesser General Public License version 2.1 requirements
22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 ** In addition, as a special exception, Nokia gives you certain additional
25 ** rights. These rights are described in the Nokia Qt LGPL Exception
26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28 ** If you have questions regarding the use of this file, please contact
29 ** Nokia at qt-info@nokia.com.
40 ****************************************************************************/
42 // #define COMPILEDBINDINGS_DEBUG
43 // #define REGISTER_CLEANUP_DEBUG
45 #include "private/qdeclarativecompiledbindings_p.h"
47 #include <QtDeclarative/qdeclarativeinfo.h>
48 #include <private/qdeclarativecontext_p.h>
49 #include <private/qdeclarativejsast_p.h>
50 #include <private/qdeclarativejsengine_p.h>
51 #include <private/qdeclarativeexpression_p.h>
52 #include <QtCore/qcoreapplication.h>
53 #include <QtCore/qdebug.h>
54 #include <QtCore/qnumeric.h>
55 #include <private/qdeclarativeanchors_p_p.h>
56 #include <private/qdeclarativeglobal_p.h>
57 #include <private/qdeclarativefastproperties_p.h>
58 #include <private/qdeclarativedebugtrace_p.h>
62 DEFINE_BOOL_CONFIG_OPTION(qmlExperimental, QML_EXPERIMENTAL);
63 DEFINE_BOOL_CONFIG_OPTION(qmlDisableOptimizer, QML_DISABLE_OPTIMIZER);
64 DEFINE_BOOL_CONFIG_OPTION(qmlDisableFastProperties, QML_DISABLE_FAST_PROPERTIES);
65 DEFINE_BOOL_CONFIG_OPTION(bindingsDump, QML_BINDINGS_DUMP);
67 Q_GLOBAL_STATIC(QDeclarativeFastProperties, fastProperties);
69 #if defined(Q_CC_GNU) && (!defined(Q_CC_INTEL) || __INTEL_COMPILER >= 1200)
70 # define QML_THREADED_INTERPRETER
73 #define FOR_EACH_QML_INSTR(F) \
75 F(BindingId) /* id */ \
76 F(Subscribe) /* subscribe */ \
77 F(SubscribeId) /* subscribe */ \
78 F(FetchAndSubscribe) /* fetchAndSubscribe */ \
79 F(LoadId) /* load */ \
80 F(LoadScope) /* load */ \
81 F(LoadRoot) /* load */ \
82 F(LoadAttached) /* attached */ \
83 F(ConvertIntToReal) /* unaryop */ \
84 F(ConvertRealToInt) /* unaryop */ \
85 F(Real) /* real_value */ \
86 F(Int) /* int_value */ \
87 F(Bool) /* bool_value */ \
88 F(String) /* string_value */ \
89 F(AddReal) /* binaryop */ \
90 F(AddInt) /* binaryop */ \
91 F(AddString) /* binaryop */ \
92 F(MinusReal) /* binaryop */ \
93 F(MinusInt) /* binaryop */ \
94 F(CompareReal) /* binaryop */ \
95 F(CompareString) /* binaryop */ \
96 F(NotCompareReal) /* binaryop */ \
97 F(NotCompareString) /* binaryop */ \
98 F(GreaterThanReal) /* binaryop */ \
99 F(MaxReal) /* binaryop */ \
100 F(MinReal) /* binaryop */ \
101 F(NewString) /* construct */ \
102 F(NewUrl) /* construct */ \
103 F(CleanupUrl) /* cleanup */ \
104 F(CleanupString) /* cleanup */ \
106 F(Fetch) /* fetch */ \
107 F(Store) /* store */ \
110 /* Speculative property resolution */ \
111 F(InitString) /* initstring */ \
112 F(FindGeneric) /* find */ \
113 F(FindGenericTerminal) /* find */ \
114 F(FindProperty) /* find */ \
115 F(FindPropertyTerminal) /* find */ \
116 F(CleanupGeneric) /* cleanup */ \
117 F(ConvertGenericToReal) /* unaryop */ \
118 F(ConvertGenericToBool) /* unaryop */ \
119 F(ConvertGenericToString) /* unaryop */ \
120 F(ConvertGenericToUrl) /* unaryop */
122 #define QML_INSTR_ENUM(I) I,
123 #define QML_INSTR_ADDR(I) &&op_##I,
125 #ifdef QML_THREADED_INTERPRETER
126 # define QML_BEGIN_INSTR(I) op_##I:
127 # define QML_END_INSTR(I) ++instr; goto *instr->common.code;
128 # define QML_INSTR_HEADER void *code;
130 # define QML_BEGIN_INSTR(I) case Instr::I:
131 # define QML_END_INSTR(I) break;
132 # define QML_INSTR_HEADER
136 using namespace QDeclarativeJS;
139 // Supported types: int, qreal, QString (needs constr/destr), QObject*, bool
141 void setUndefined() { type = 0; }
142 void setUnknownButDefined() { type = -1; }
143 void setNaN() { setqreal(qSNaN()); }
144 bool isUndefined() const { return type == 0; }
146 void setQObject(QObject *o) { *((QObject **)data) = o; type = QMetaType::QObjectStar; }
147 QObject *getQObject() const { return *((QObject **)data); }
149 void setqreal(qreal v) { *((qreal *)data) = v; type = QMetaType::QReal; }
150 qreal getqreal() const { return *((qreal *)data); }
152 void setint(int v) { *((int *)data) = v; type = QMetaType::Int; }
153 int getint() const { return *((int *)data); }
155 void setbool(bool v) { *((bool *)data) = v; type = QMetaType::Bool; }
156 bool getbool() const { return *((bool *)data); }
158 QVariant *getvariantptr() { return (QVariant *)typeDataPtr(); }
159 QString *getstringptr() { return (QString *)typeDataPtr(); }
160 QUrl *geturlptr() { return (QUrl *)typeDataPtr(); }
161 const QVariant *getvariantptr() const { return (QVariant *)typeDataPtr(); }
162 const QString *getstringptr() const { return (QString *)typeDataPtr(); }
163 const QUrl *geturlptr() const { return (QUrl *)typeDataPtr(); }
165 void *typeDataPtr() { return (void *)&data; }
166 void *typeMemory() { return (void *)data; }
167 const void *typeDataPtr() const { return (void *)&data; }
168 const void *typeMemory() const { return (void *)data; }
170 int gettype() const { return type; }
171 void settype(int t) { type = t; }
173 int type; // Optional type
174 void *data[2]; // Object stored here
176 #ifdef REGISTER_CLEANUP_DEBUG
182 int allowedTypes[] = { QMetaType::QObjectStar, QMetaType::QReal, QMetaType::Int, QMetaType::Bool, 0 };
183 bool found = (type == 0);
184 int *ctype = allowedTypes;
185 while (!found && *ctype) {
186 found = (*ctype == type);
190 qWarning("Register leaked of type %d", type);
196 class QDeclarativeCompiledBindingsPrivate : public QObjectPrivate
198 Q_DECLARE_PUBLIC(QDeclarativeCompiledBindings)
201 QDeclarativeCompiledBindingsPrivate();
202 virtual ~QDeclarativeCompiledBindingsPrivate();
204 struct Binding : public QDeclarativeAbstractBinding, public QDeclarativeDelayedError {
205 Binding() : enabled(false), updating(0), property(0),
206 scope(0), target(0), parent(0) {}
208 // Inherited from QDeclarativeAbstractBinding
209 virtual void setEnabled(bool, QDeclarativePropertyPrivate::WriteFlags flags);
210 virtual void update(QDeclarativePropertyPrivate::WriteFlags flags);
211 virtual void destroy();
220 QDeclarativeCompiledBindingsPrivate *parent;
223 typedef QDeclarativeNotifierEndpoint Subscription;
224 Subscription *subscriptions;
225 QScriptDeclarativeClass::PersistentIdentifier *identifiers;
227 void run(Binding *, QDeclarativePropertyPrivate::WriteFlags flags);
229 const char *programData;
231 quint32 *m_signalTable;
233 static int methodCount;
236 void run(int instr, QDeclarativeContextData *context,
237 QDeclarativeDelayedError *error, QObject *scope, QObject *output, QDeclarativePropertyPrivate::WriteFlags storeFlags);
240 inline void unsubscribe(int subIndex);
241 inline void subscribeId(QDeclarativeContextData *p, int idIndex, int subIndex);
242 inline void subscribe(QObject *o, int notifyIndex, int subIndex);
244 QDeclarativePropertyCache::Data *findproperty(QObject *obj,
245 const QScriptDeclarativeClass::Identifier &name,
246 QDeclarativeEnginePrivate *enginePriv,
247 QDeclarativePropertyCache::Data &local);
248 bool findproperty(QObject *obj,
250 QDeclarativeEnginePrivate *enginePriv,
252 const QScriptDeclarativeClass::Identifier &name,
254 void findgeneric(Register *output, // value output
255 int subIdx, // Subscription index in config
256 QDeclarativeContextData *context, // Context to search in
257 const QScriptDeclarativeClass::Identifier &name,
261 QDeclarativeCompiledBindingsPrivate::QDeclarativeCompiledBindingsPrivate()
262 : subscriptions(0), identifiers(0)
266 QDeclarativeCompiledBindingsPrivate::~QDeclarativeCompiledBindingsPrivate()
268 delete [] subscriptions; subscriptions = 0;
269 delete [] identifiers; identifiers = 0;
272 int QDeclarativeCompiledBindingsPrivate::methodCount = -1;
274 QDeclarativeCompiledBindings::QDeclarativeCompiledBindings(const char *program, QDeclarativeContextData *context)
275 : QObject(*(new QDeclarativeCompiledBindingsPrivate))
277 Q_D(QDeclarativeCompiledBindings);
279 if (d->methodCount == -1)
280 d->methodCount = QDeclarativeCompiledBindings::staticMetaObject.methodCount();
282 d->programData = program;
286 QDeclarativeAbstractExpression::setContext(context);
289 QDeclarativeCompiledBindings::~QDeclarativeCompiledBindings()
291 Q_D(QDeclarativeCompiledBindings);
293 delete [] d->m_bindings;
296 QDeclarativeAbstractBinding *QDeclarativeCompiledBindings::configBinding(int index, QObject *target,
297 QObject *scope, int property)
299 Q_D(QDeclarativeCompiledBindings);
301 QDeclarativeCompiledBindingsPrivate::Binding *rv = d->m_bindings + index;
304 rv->property = property;
309 addref(); // This is decremented in Binding::destroy()
314 void QDeclarativeCompiledBindingsPrivate::Binding::setEnabled(bool e, QDeclarativePropertyPrivate::WriteFlags flags)
319 if (e) update(flags);
323 void QDeclarativeCompiledBindingsPrivate::Binding::update(QDeclarativePropertyPrivate::WriteFlags flags)
325 QDeclarativeDebugTrace::startRange(QDeclarativeDebugTrace::Binding);
326 parent->run(this, flags);
327 QDeclarativeDebugTrace::endRange(QDeclarativeDebugTrace::Binding);
330 void QDeclarativeCompiledBindingsPrivate::Binding::destroy()
335 parent->q_func()->release();
338 int QDeclarativeCompiledBindings::qt_metacall(QMetaObject::Call c, int id, void **)
340 Q_D(QDeclarativeCompiledBindings);
342 if (c == QMetaObject::InvokeMetaMethod && id >= d->methodCount) {
343 id -= d->methodCount;
345 quint32 *reeval = d->m_signalTable + d->m_signalTable[id];
346 quint32 count = *reeval;
348 for (quint32 ii = 0; ii < count; ++ii) {
349 d->run(d->m_bindings + reeval[ii], QDeclarativePropertyPrivate::DontRemoveBinding);
355 void QDeclarativeCompiledBindingsPrivate::run(Binding *binding, QDeclarativePropertyPrivate::WriteFlags flags)
357 Q_Q(QDeclarativeCompiledBindings);
359 if (!binding->enabled)
362 QDeclarativeContextData *context = q->QDeclarativeAbstractExpression::context();
363 if (!context || !context->isValid())
366 if (binding->updating) {
368 if (binding->property & 0xFFFF0000) {
369 QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(context->engine);
371 QDeclarativeValueType *vt = ep->valueTypes[(binding->property >> 16) & 0xFF];
374 name = QLatin1String(binding->target->metaObject()->property(binding->property & 0xFFFF).name());
375 name.append(QLatin1String("."));
376 name.append(QLatin1String(vt->metaObject()->property(binding->property >> 24).name()));
378 name = QLatin1String(binding->target->metaObject()->property(binding->property).name());
380 qmlInfo(binding->target) << QCoreApplication::translate("QDeclarativeCompiledBindings", "Binding loop detected for property \"%1\"").arg(name);
384 binding->updating = true;
385 if (binding->property & 0xFFFF0000) {
386 QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(context->engine);
388 QDeclarativeValueType *vt = ep->valueTypes[(binding->property >> 16) & 0xFF];
390 vt->read(binding->target, binding->property & 0xFFFF);
392 QObject *target = vt;
393 run(binding->index, context, binding, binding->scope, target, flags);
395 vt->write(binding->target, binding->property & 0xFFFF, flags);
397 run(binding->index, context, binding, binding->scope, binding->target, flags);
399 binding->updating = false;
403 // This structure is exactly 8-bytes in size
406 FOR_EACH_QML_INSTR(QML_INSTR_ENUM)
426 quint16 subscriptions;
465 quint16 subscription;
546 quint16 subscribeIndex;
567 quint32 signalTableOffset;
568 quint32 exceptionDataOffset;
569 quint16 subscriptions;
571 quint16 instructionCount;
574 const char *data() const { return ((const char *)this) + sizeof(Program); }
575 const Instr *instructions() const { return (const Instr *)(data() + dataLength); }
579 struct QDeclarativeBindingCompilerPrivate
582 Result() : unknownType(false), metaObject(0), type(-1), reg(-1) {}
583 bool operator==(const Result &o) const {
584 return unknownType == o.unknownType &&
585 metaObject == o.metaObject &&
589 bool operator!=(const Result &o) const {
590 return !(*this == o);
593 const QMetaObject *metaObject;
597 QSet<QString> subscriptionSet;
600 QDeclarativeBindingCompilerPrivate() : registers(0) {}
602 void resetInstanceState();
605 QDeclarativeParser::Object *context;
606 QDeclarativeParser::Object *component;
607 QDeclarativeParser::Property *destination;
608 QHash<QString, QDeclarativeParser::Object *> ids;
609 QDeclarativeImports imports;
610 QDeclarativeEnginePrivate *engine;
612 QString contextName() const { return QLatin1String("$$$SCOPE_") + QString::number((quintptr)context, 16); }
614 bool compile(QDeclarativeJS::AST::Node *);
616 bool parseExpression(QDeclarativeJS::AST::Node *, Result &);
618 bool tryName(QDeclarativeJS::AST::Node *);
619 bool parseName(QDeclarativeJS::AST::Node *, Result &);
621 bool tryArith(QDeclarativeJS::AST::Node *);
622 bool parseArith(QDeclarativeJS::AST::Node *, Result &);
623 bool numberArith(Result &, const Result &, const Result &, QSOperator::Op op);
624 bool stringArith(Result &, const Result &, const Result &, QSOperator::Op op);
626 bool tryLogic(QDeclarativeJS::AST::Node *);
627 bool parseLogic(QDeclarativeJS::AST::Node *, Result &);
629 bool tryConditional(QDeclarativeJS::AST::Node *);
630 bool parseConditional(QDeclarativeJS::AST::Node *, Result &);
632 bool tryConstant(QDeclarativeJS::AST::Node *);
633 bool parseConstant(QDeclarativeJS::AST::Node *, Result &);
635 bool tryMethod(QDeclarativeJS::AST::Node *);
636 bool parseMethod(QDeclarativeJS::AST::Node *, Result &);
638 bool buildName(QStringList &, QDeclarativeJS::AST::Node *, QList<QDeclarativeJS::AST::ExpressionNode *> *nodes = 0);
639 bool fetch(Result &type, const QMetaObject *, int reg, int idx, const QStringList &, QDeclarativeJS::AST::ExpressionNode *);
642 QHash<int, QPair<int, int> > registerCleanups;
643 int acquireReg(int cleanup = Instr::Noop, int cleanupType = 0);
644 void registerCleanup(int reg, int cleanup, int cleanupType = 0);
645 void releaseReg(int);
647 int registerLiteralString(const QString &);
648 int registerString(const QString &);
649 QHash<QString, QPair<int, int> > registeredStrings;
652 bool subscription(const QStringList &, Result *);
653 int subscriptionIndex(const QStringList &);
654 bool subscriptionNeutral(const QSet<QString> &base, const QSet<QString> &lhs, const QSet<QString> &rhs);
656 quint8 exceptionId(QDeclarativeJS::AST::ExpressionNode *);
657 QVector<quint64> exceptions;
659 QSet<int> usedSubscriptionIds;
660 QSet<QString> subscriptionSet;
661 QHash<QString, int> subscriptionIds;
662 QVector<Instr> bytecode;
664 // Committed binding data
667 QList<QSet<int> > dependencies;
669 QVector<Instr> bytecode;
671 QHash<QString, int> subscriptionIds;
672 QVector<quint64> exceptions;
674 QHash<QString, QPair<int, int> > registeredStrings;
676 int count() const { return offsets.count(); }
679 QByteArray buildSignalTable() const;
680 QByteArray buildExceptionData() const;
683 void QDeclarativeCompiledBindingsPrivate::unsubscribe(int subIndex)
685 QDeclarativeCompiledBindingsPrivate::Subscription *sub = (subscriptions + subIndex);
689 void QDeclarativeCompiledBindingsPrivate::subscribeId(QDeclarativeContextData *p, int idIndex, int subIndex)
691 Q_Q(QDeclarativeCompiledBindings);
693 unsubscribe(subIndex);
695 if (p->idValues[idIndex]) {
696 QDeclarativeCompiledBindingsPrivate::Subscription *sub = (subscriptions + subIndex);
698 sub->targetMethod = methodCount + subIndex;
699 sub->connect(&p->idValues[idIndex].bindings);
703 void QDeclarativeCompiledBindingsPrivate::subscribe(QObject *o, int notifyIndex, int subIndex)
705 Q_Q(QDeclarativeCompiledBindings);
707 QDeclarativeCompiledBindingsPrivate::Subscription *sub = (subscriptions + subIndex);
709 sub->targetMethod = methodCount + subIndex;
711 sub->connect(o, notifyIndex);
716 // Conversion functions - these MUST match the QtScript expression path
717 inline static qreal toReal(Register *reg, int type, bool *ok = 0)
721 if (type == QMetaType::QReal) {
722 return reg->getqreal();
723 } else if (type == qMetaTypeId<QVariant>()) {
724 return reg->getvariantptr()->toReal();
731 inline static QString toString(Register *reg, int type, bool *ok = 0)
735 if (type == QMetaType::QReal) {
736 return QString::number(reg->getqreal());
737 } else if (type == QMetaType::Int) {
738 return QString::number(reg->getint());
739 } else if (type == qMetaTypeId<QVariant>()) {
740 return reg->getvariantptr()->toString();
741 } else if (type == QMetaType::QString) {
742 return *reg->getstringptr();
749 inline static bool toBool(Register *reg, int type, bool *ok = 0)
753 if (type == QMetaType::Bool) {
754 return reg->getbool();
755 } else if (type == qMetaTypeId<QVariant>()) {
756 return reg->getvariantptr()->toBool();
763 inline static QUrl toUrl(Register *reg, int type, QDeclarativeContextData *context, bool *ok = 0)
768 if (type == qMetaTypeId<QVariant>()) {
769 QVariant *var = reg->getvariantptr();
770 int vt = var->type();
771 if (vt == QVariant::Url) {
773 } else if (vt == QVariant::ByteArray) {
774 base = QUrl(QString::fromUtf8(var->toByteArray()));
775 } else if (vt == QVariant::String) {
776 base = QUrl(var->toString());
781 } else if (type == QMetaType::QString) {
782 base = QUrl(*reg->getstringptr());
788 if (!base.isEmpty() && base.isRelative())
789 return context->url.resolved(base);
794 static QObject *variantToQObject(const QVariant &value, bool *ok)
798 if (value.userType() == QMetaType::QObjectStar) {
799 return qvariant_cast<QObject*>(value);
806 bool QDeclarativeCompiledBindingsPrivate::findproperty(QObject *obj, Register *output,
807 QDeclarativeEnginePrivate *enginePriv,
808 int subIdx, const QScriptDeclarativeClass::Identifier &name,
812 output->setUndefined();
816 QDeclarativePropertyCache::Data local;
817 QDeclarativePropertyCache::Data *property =
818 QDeclarativePropertyCache::property(QDeclarativeEnginePrivate::get(enginePriv), obj, name, local);
822 subscribe(obj, property->notifyIndex, subIdx);
824 if (property->flags & QDeclarativePropertyCache::Data::IsQObjectDerived) {
825 void *args[] = { output->typeDataPtr(), 0 };
826 QMetaObject::metacall(obj, QMetaObject::ReadProperty, property->coreIndex, args);
827 output->settype(QMetaType::QObjectStar);
828 } else if (property->propType == qMetaTypeId<QVariant>()) {
830 void *args[] = { &v, 0 };
831 QMetaObject::metacall(obj, QMetaObject::ReadProperty, property->coreIndex, args);
834 new (output->typeDataPtr()) QVariant(v);
835 output->settype(qMetaTypeId<QVariant>());
838 output->setQObject(variantToQObject(v, &ok));
840 output->setUndefined();
842 output->settype(QMetaType::QObjectStar);
847 output->setUndefined();
848 } else if (property->propType == QMetaType::QReal) {
849 void *args[] = { output->typeDataPtr(), 0 };
850 QMetaObject::metacall(obj, QMetaObject::ReadProperty, property->coreIndex, args);
851 output->settype(QMetaType::QReal);
852 } else if (property->propType == QMetaType::Int) {
853 void *args[] = { output->typeDataPtr(), 0 };
854 QMetaObject::metacall(obj, QMetaObject::ReadProperty, property->coreIndex, args);
855 output->settype(QMetaType::Int);
856 } else if (property->propType == QMetaType::Bool) {
857 void *args[] = { output->typeDataPtr(), 0 };
858 QMetaObject::metacall(obj, QMetaObject::ReadProperty, property->coreIndex, args);
859 output->settype(QMetaType::Bool);
860 } else if (property->propType == QMetaType::QString) {
861 new (output->typeDataPtr()) QString();
862 void *args[] = { output->typeDataPtr(), 0 };
863 QMetaObject::metacall(obj, QMetaObject::ReadProperty, property->coreIndex, args);
864 output->settype(QMetaType::QString);
866 new (output->typeDataPtr())
867 QVariant(obj->metaObject()->property(property->coreIndex).read(obj));
868 output->settype(qMetaTypeId<QVariant>());
874 output->setUndefined();
879 void QDeclarativeCompiledBindingsPrivate::findgeneric(Register *output,
881 QDeclarativeContextData *context,
882 const QScriptDeclarativeClass::Identifier &name,
885 QDeclarativeEnginePrivate *enginePriv = QDeclarativeEnginePrivate::get(context->engine);
889 int contextPropertyIndex = context->propertyNames?context->propertyNames->value(name):-1;
892 if (contextPropertyIndex != -1) {
894 if (contextPropertyIndex < context->idValueCount) {
895 output->setQObject(context->idValues[contextPropertyIndex]);
896 output->settype(QMetaType::QObjectStar);
899 subscribeId(context, contextPropertyIndex, subIdx);
902 QDeclarativeContextPrivate *cp = context->asQDeclarativeContextPrivate();
903 const QVariant &value = cp->propertyValues.at(contextPropertyIndex);
906 new (output->typeDataPtr()) QVariant(value);
907 output->settype(qMetaTypeId<QVariant>());
910 output->setQObject(variantToQObject(value, &ok));
911 if (!ok) { output->setUndefined(); }
912 else { output->settype(QMetaType::QObjectStar); }
917 subscribe(context->asQDeclarativeContext(), contextPropertyIndex + cp->notifyIndex, subIdx);
925 if (QObject *root = context->contextObject) {
927 if (findproperty(root, output, enginePriv, subIdx, name, isTerminal))
932 context = context->parent;
935 output->setUndefined();
938 void QDeclarativeCompiledBindingsPrivate::init()
940 Program *program = (Program *)programData;
941 if (program->subscriptions)
942 subscriptions = new QDeclarativeCompiledBindingsPrivate::Subscription[program->subscriptions];
943 if (program->identifiers)
944 identifiers = new QScriptDeclarativeClass::PersistentIdentifier[program->identifiers];
946 m_signalTable = (quint32 *)(program->data() + program->signalTableOffset);
947 m_bindings = new QDeclarativeCompiledBindingsPrivate::Binding[program->bindings];
950 static void throwException(int id, QDeclarativeDelayedError *error,
951 Program *program, QDeclarativeContextData *context,
952 const QString &description = QString())
954 error->error.setUrl(context->url);
955 if (description.isEmpty())
956 error->error.setDescription(QLatin1String("TypeError: Result of expression is not an object"));
958 error->error.setDescription(description);
960 quint64 e = *((quint64 *)(program->data() + program->exceptionDataOffset) + id);
961 error->error.setLine((e >> 32) & 0xFFFFFFFF);
962 error->error.setColumn(e & 0xFFFFFFFF);
964 error->error.setLine(-1);
965 error->error.setColumn(-1);
967 if (!context->engine || !error->addError(QDeclarativeEnginePrivate::get(context->engine)))
968 QDeclarativeEnginePrivate::warning(context->engine, error->error);
971 static void dumpInstruction(const Instr *instr)
973 switch (instr->common.type) {
975 qWarning().nospace() << "\t" << "Noop";
977 case Instr::BindingId:
978 qWarning().nospace() << instr->id.line << ":" << instr->id.column << ":";
980 case Instr::Subscribe:
981 qWarning().nospace() << "\t" << "Subscribe" << "\t\t" << instr->subscribe.offset << "\t" << instr->subscribe.reg << "\t" << instr->subscribe.index;
983 case Instr::SubscribeId:
984 qWarning().nospace() << "\t" << "SubscribeId" << "\t\t" << instr->subscribe.offset << "\t" << instr->subscribe.reg << "\t" << instr->subscribe.index;
986 case Instr::FetchAndSubscribe:
987 qWarning().nospace() << "\t" << "FetchAndSubscribe" << "\t" << instr->fetchAndSubscribe.output << "\t" << instr->fetchAndSubscribe.objectReg << "\t" << instr->fetchAndSubscribe.subscription;
990 qWarning().nospace() << "\t" << "LoadId" << "\t\t\t" << instr->load.index << "\t" << instr->load.reg;
992 case Instr::LoadScope:
993 qWarning().nospace() << "\t" << "LoadScope" << "\t\t" << instr->load.index << "\t" << instr->load.reg;
995 case Instr::LoadRoot:
996 qWarning().nospace() << "\t" << "LoadRoot" << "\t\t" << instr->load.index << "\t" << instr->load.reg;
998 case Instr::LoadAttached:
999 qWarning().nospace() << "\t" << "LoadAttached" << "\t\t" << instr->attached.output << "\t" << instr->attached.reg << "\t" << instr->attached.id;
1001 case Instr::ConvertIntToReal:
1002 qWarning().nospace() << "\t" << "ConvertIntToReal" << "\t" << instr->unaryop.output << "\t" << instr->unaryop.src;
1004 case Instr::ConvertRealToInt:
1005 qWarning().nospace() << "\t" << "ConvertRealToInt" << "\t" << instr->unaryop.output << "\t" << instr->unaryop.src;
1008 qWarning().nospace() << "\t" << "Real" << "\t\t\t" << instr->real_value.reg << "\t" << instr->real_value.value;
1011 qWarning().nospace() << "\t" << "Int" << "\t\t\t" << instr->int_value.reg << "\t" << instr->int_value.value;
1014 qWarning().nospace() << "\t" << "Bool" << "\t\t\t" << instr->bool_value.reg << "\t" << instr->bool_value.value;
1017 qWarning().nospace() << "\t" << "String" << "\t\t\t" << instr->string_value.reg << "\t" << instr->string_value.offset << "\t" << instr->string_value.length;
1019 case Instr::AddReal:
1020 qWarning().nospace() << "\t" << "AddReal" << "\t\t\t" << instr->binaryop.output << "\t" << instr->binaryop.src1 << "\t" << instr->binaryop.src2;
1023 qWarning().nospace() << "\t" << "AddInt" << "\t\t\t" << instr->binaryop.output << "\t" << instr->binaryop.src1 << "\t" << instr->binaryop.src2;
1025 case Instr::AddString:
1026 qWarning().nospace() << "\t" << "AddString" << "\t\t" << instr->binaryop.output << "\t" << instr->binaryop.src1 << "\t" << instr->binaryop.src2;
1028 case Instr::MinusReal:
1029 qWarning().nospace() << "\t" << "MinusReal" << "\t\t" << instr->binaryop.output << "\t" << instr->binaryop.src1 << "\t" << instr->binaryop.src2;
1031 case Instr::MinusInt:
1032 qWarning().nospace() << "\t" << "MinusInt" << "\t\t" << instr->binaryop.output << "\t" << instr->binaryop.src1 << "\t" << instr->binaryop.src2;
1034 case Instr::CompareReal:
1035 qWarning().nospace() << "\t" << "CompareReal" << "\t\t" << instr->binaryop.output << "\t" << instr->binaryop.src1 << "\t" << instr->binaryop.src2;
1037 case Instr::CompareString:
1038 qWarning().nospace() << "\t" << "CompareString" << "\t\t" << instr->binaryop.output << "\t" << instr->binaryop.src1 << "\t" << instr->binaryop.src2;
1040 case Instr::NotCompareReal:
1041 qWarning().nospace() << "\t" << "NotCompareReal" << "\t\t" << instr->binaryop.output << "\t" << instr->binaryop.src1 << "\t" << instr->binaryop.src2;
1043 case Instr::NotCompareString:
1044 qWarning().nospace() << "\t" << "NotCompareString" << "\t\t" << instr->binaryop.output << "\t" << instr->binaryop.src1 << "\t" << instr->binaryop.src2;
1046 case Instr::GreaterThanReal:
1047 qWarning().nospace() << "\t" << "GreaterThanReal" << "\t\t" << instr->binaryop.output << "\t" << instr->binaryop.src1 << "\t" << instr->binaryop.src2;
1049 case Instr::MaxReal:
1050 qWarning().nospace() << "\t" << "MaxReal" << "\t\t\t" << instr->binaryop.output << "\t" << instr->binaryop.src1 << "\t" << instr->binaryop.src2;
1052 case Instr::MinReal:
1053 qWarning().nospace() << "\t" << "MinReal" << "\t\t\t" << instr->binaryop.output << "\t" << instr->binaryop.src1 << "\t" << instr->binaryop.src2;
1055 case Instr::NewString:
1056 qWarning().nospace() << "\t" << "NewString" << "\t\t" << instr->construct.reg;
1059 qWarning().nospace() << "\t" << "NewUrl" << "\t\t\t" << instr->construct.reg;
1061 case Instr::CleanupString:
1062 qWarning().nospace() << "\t" << "CleanupString" << "\t\t" << instr->cleanup.reg;
1064 case Instr::CleanupUrl:
1065 qWarning().nospace() << "\t" << "CleanupUrl" << "\t\t" << instr->cleanup.reg;
1068 qWarning().nospace() << "\t" << "Fetch" << "\t\t\t" << instr->fetch.output << "\t" << instr->fetch.index << "\t" << instr->fetch.objectReg;
1071 qWarning().nospace() << "\t" << "Store" << "\t\t\t" << instr->store.output << "\t" << instr->store.index << "\t" << instr->store.reg;
1074 qWarning().nospace() << "\t" << "Copy" << "\t\t\t" << instr->copy.reg << "\t" << instr->copy.src;
1077 qWarning().nospace() << "\t" << "Skip" << "\t\t\t" << instr->skip.reg << "\t" << instr->skip.count;
1080 qWarning().nospace() << "\t" << "Done";
1082 case Instr::InitString:
1083 qWarning().nospace() << "\t" << "InitString" << "\t\t" << instr->initstring.offset << "\t" << instr->initstring.dataIdx;
1085 case Instr::FindGeneric:
1086 qWarning().nospace() << "\t" << "FindGeneric" << "\t\t" << instr->find.reg << "\t" << instr->find.name;
1088 case Instr::FindGenericTerminal:
1089 qWarning().nospace() << "\t" << "FindGenericTerminal" << "\t" << instr->find.reg << "\t" << instr->find.name;
1091 case Instr::FindProperty:
1092 qWarning().nospace() << "\t" << "FindProperty" << "\t\t" << instr->find.reg << "\t" << instr->find.src << "\t" << instr->find.name;
1094 case Instr::FindPropertyTerminal:
1095 qWarning().nospace() << "\t" << "FindPropertyTerminal" << "\t" << instr->find.reg << "\t" << instr->find.src << "\t" << instr->find.name;
1097 case Instr::CleanupGeneric:
1098 qWarning().nospace() << "\t" << "CleanupGeneric" << "\t\t" << instr->cleanup.reg;
1100 case Instr::ConvertGenericToReal:
1101 qWarning().nospace() << "\t" << "ConvertGenericToReal" << "\t" << instr->unaryop.output << "\t" << instr->unaryop.src;
1103 case Instr::ConvertGenericToBool:
1104 qWarning().nospace() << "\t" << "ConvertGenericToBool" << "\t" << instr->unaryop.output << "\t" << instr->unaryop.src;
1106 case Instr::ConvertGenericToString:
1107 qWarning().nospace() << "\t" << "ConvertGenericToString" << "\t" << instr->unaryop.output << "\t" << instr->unaryop.src;
1109 case Instr::ConvertGenericToUrl:
1110 qWarning().nospace() << "\t" << "ConvertGenericToUrl" << "\t" << instr->unaryop.output << "\t" << instr->unaryop.src;
1113 qWarning().nospace() << "\t" << "Unknown";
1118 void QDeclarativeCompiledBindingsPrivate::run(int instrIndex,
1119 QDeclarativeContextData *context, QDeclarativeDelayedError *error,
1120 QObject *scope, QObject *output, QDeclarativePropertyPrivate::WriteFlags storeFlags)
1122 Q_Q(QDeclarativeCompiledBindings);
1124 error->removeError();
1126 Register registers[32];
1128 QDeclarativeEnginePrivate *engine = QDeclarativeEnginePrivate::get(context->engine);
1129 Program *program = (Program *)programData;
1130 const Instr *instr = program->instructions();
1131 instr += instrIndex;
1132 const char *data = program->data();
1134 #ifdef QML_THREADED_INTERPRETER
1135 static void *decode_instr[] = {
1136 FOR_EACH_QML_INSTR(QML_INSTR_ADDR)
1139 if (!program->compiled) {
1140 program->compiled = true;
1141 const Instr *inop = program->instructions();
1142 for (int i = 0; i < program->instructionCount; ++i) {
1143 Instr *op = (Instr *) inop++;
1144 op->common.code = decode_instr[op->common.type];
1148 goto *instr->common.code;
1152 #ifdef COMPILEDBINDINGS_DEBUG
1153 qWarning().nospace() << "Begin binding run";
1157 switch (instr->common.type) {
1159 #ifdef COMPILEDBINDINGS_DEBUG
1160 dumpInstruction(instr);
1165 QML_BEGIN_INSTR(Noop)
1168 QML_BEGIN_INSTR(BindingId)
1169 QML_END_INSTR(BindingId)
1171 QML_BEGIN_INSTR(SubscribeId)
1172 subscribeId(context, instr->subscribe.index, instr->subscribe.offset);
1173 QML_END_INSTR(SubscribeId)
1175 QML_BEGIN_INSTR(Subscribe)
1178 const Register &object = registers[instr->subscribe.reg];
1179 if (!object.isUndefined()) o = object.getQObject();
1180 subscribe(o, instr->subscribe.index, instr->subscribe.offset);
1182 QML_END_INSTR(Subscribe)
1184 QML_BEGIN_INSTR(FetchAndSubscribe)
1186 const Register &input = registers[instr->fetchAndSubscribe.objectReg];
1187 Register &output = registers[instr->fetchAndSubscribe.output];
1189 if (input.isUndefined()) {
1190 throwException(instr->fetchAndSubscribe.exceptionId, error, program, context);
1194 QObject *object = input.getQObject();
1196 output.setUndefined();
1198 int subIdx = instr->fetchAndSubscribe.subscription;
1199 QDeclarativeCompiledBindingsPrivate::Subscription *sub = 0;
1201 sub = (subscriptions + subIdx);
1203 sub->targetMethod = methodCount + subIdx;
1205 fastProperties()->accessor(instr->fetchAndSubscribe.function)(object, output.typeDataPtr(), sub);
1208 QML_END_INSTR(FetchAndSubscribe)
1210 QML_BEGIN_INSTR(LoadId)
1211 registers[instr->load.reg].setQObject(context->idValues[instr->load.index].data());
1212 QML_END_INSTR(LoadId)
1214 QML_BEGIN_INSTR(LoadScope)
1215 registers[instr->load.reg].setQObject(scope);
1216 QML_END_INSTR(LoadScope)
1218 QML_BEGIN_INSTR(LoadRoot)
1219 registers[instr->load.reg].setQObject(context->contextObject);
1220 QML_END_INSTR(LoadRoot)
1222 QML_BEGIN_INSTR(LoadAttached)
1224 const Register &input = registers[instr->attached.reg];
1225 Register &output = registers[instr->attached.output];
1226 if (input.isUndefined()) {
1227 throwException(instr->attached.exceptionId, error, program, context);
1231 QObject *object = registers[instr->attached.reg].getQObject();
1233 output.setUndefined();
1236 qmlAttachedPropertiesObjectById(instr->attached.id,
1237 registers[instr->attached.reg].getQObject(),
1240 output.setQObject(attached);
1243 QML_END_INSTR(LoadAttached)
1245 QML_BEGIN_INSTR(ConvertIntToReal)
1247 const Register &input = registers[instr->unaryop.src];
1248 Register &output = registers[instr->unaryop.output];
1249 if (input.isUndefined()) output.setUndefined();
1250 else output.setqreal(qreal(input.getint()));
1252 QML_END_INSTR(ConvertIntToReal)
1254 QML_BEGIN_INSTR(ConvertRealToInt)
1256 const Register &input = registers[instr->unaryop.src];
1257 Register &output = registers[instr->unaryop.output];
1258 if (input.isUndefined()) output.setUndefined();
1259 else output.setint(qRound(input.getqreal()));
1261 QML_END_INSTR(ConvertRealToInt)
1263 QML_BEGIN_INSTR(Real)
1264 registers[instr->real_value.reg].setqreal(instr->real_value.value);
1267 QML_BEGIN_INSTR(Int)
1268 registers[instr->int_value.reg].setint(instr->int_value.value);
1271 QML_BEGIN_INSTR(Bool)
1272 registers[instr->bool_value.reg].setbool(instr->bool_value.value);
1275 QML_BEGIN_INSTR(String)
1277 Register &output = registers[instr->string_value.reg];
1278 new (output.getstringptr())
1279 QString((QChar *)(data + instr->string_value.offset), instr->string_value.length);
1280 output.settype(QMetaType::QString);
1282 QML_END_INSTR(String)
1284 QML_BEGIN_INSTR(AddReal)
1286 const Register &lhs = registers[instr->binaryop.src1];
1287 const Register &rhs = registers[instr->binaryop.src2];
1288 Register &output = registers[instr->binaryop.output];
1289 if (lhs.isUndefined() || rhs.isUndefined()) output.setNaN();
1290 else output.setqreal(lhs.getqreal() + rhs.getqreal());
1292 QML_END_INSTR(AddReal)
1294 QML_BEGIN_INSTR(AddInt)
1296 const Register &lhs = registers[instr->binaryop.src1];
1297 const Register &rhs = registers[instr->binaryop.src2];
1298 Register &output = registers[instr->binaryop.output];
1299 if (lhs.isUndefined() || rhs.isUndefined()) output.setNaN();
1300 else output.setint(lhs.getint() + rhs.getint());
1302 QML_END_INSTR(AddInt)
1304 QML_BEGIN_INSTR(AddString)
1306 const Register &lhs = registers[instr->binaryop.src1];
1307 const Register &rhs = registers[instr->binaryop.src2];
1308 Register &output = registers[instr->binaryop.output];
1309 if (lhs.isUndefined() && rhs.isUndefined()) { output.setNaN(); }
1311 if (lhs.isUndefined())
1312 new (output.getstringptr())
1313 QString(QLatin1String("undefined") + *registers[instr->binaryop.src2].getstringptr());
1314 else if (rhs.isUndefined())
1315 new (output.getstringptr())
1316 QString(*registers[instr->binaryop.src1].getstringptr() + QLatin1String("undefined"));
1318 new (output.getstringptr())
1319 QString(*registers[instr->binaryop.src1].getstringptr() +
1320 *registers[instr->binaryop.src2].getstringptr());
1321 output.settype(QMetaType::QString);
1324 QML_END_INSTR(AddString)
1326 QML_BEGIN_INSTR(MinusReal)
1328 const Register &lhs = registers[instr->binaryop.src1];
1329 const Register &rhs = registers[instr->binaryop.src2];
1330 Register &output = registers[instr->binaryop.output];
1331 if (lhs.isUndefined() || rhs.isUndefined()) output.setNaN();
1332 else output.setqreal(lhs.getqreal() - rhs.getqreal());
1334 QML_END_INSTR(MinusReal)
1336 QML_BEGIN_INSTR(MinusInt)
1338 const Register &lhs = registers[instr->binaryop.src1];
1339 const Register &rhs = registers[instr->binaryop.src2];
1340 Register &output = registers[instr->binaryop.output];
1341 if (lhs.isUndefined() || rhs.isUndefined()) output.setNaN();
1342 else output.setint(lhs.getint() - rhs.getint());
1344 QML_END_INSTR(MinusInt)
1346 QML_BEGIN_INSTR(CompareReal)
1348 const Register &lhs = registers[instr->binaryop.src1];
1349 const Register &rhs = registers[instr->binaryop.src2];
1350 Register &output = registers[instr->binaryop.output];
1351 if (lhs.isUndefined() || rhs.isUndefined()) output.setbool(lhs.isUndefined() == rhs.isUndefined());
1352 else output.setbool(lhs.getqreal() == rhs.getqreal());
1354 QML_END_INSTR(CompareReal)
1356 QML_BEGIN_INSTR(CompareString)
1358 const Register &lhs = registers[instr->binaryop.src1];
1359 const Register &rhs = registers[instr->binaryop.src2];
1360 Register &output = registers[instr->binaryop.output];
1361 if (lhs.isUndefined() || rhs.isUndefined()) output.setbool(lhs.isUndefined() == rhs.isUndefined());
1362 else output.setbool(*lhs.getstringptr() == *rhs.getstringptr());
1364 QML_END_INSTR(CompareString)
1366 QML_BEGIN_INSTR(NotCompareReal)
1368 const Register &lhs = registers[instr->binaryop.src1];
1369 const Register &rhs = registers[instr->binaryop.src2];
1370 Register &output = registers[instr->binaryop.output];
1371 if (lhs.isUndefined() || rhs.isUndefined()) output.setbool(lhs.isUndefined() != rhs.isUndefined());
1372 else output.setbool(lhs.getqreal() != rhs.getqreal());
1374 QML_END_INSTR(NotCompareReal)
1376 QML_BEGIN_INSTR(NotCompareString)
1378 const Register &lhs = registers[instr->binaryop.src1];
1379 const Register &rhs = registers[instr->binaryop.src2];
1380 Register &output = registers[instr->binaryop.output];
1381 if (lhs.isUndefined() || rhs.isUndefined()) output.setbool(lhs.isUndefined() != rhs.isUndefined());
1382 else output.setbool(*lhs.getstringptr() != *rhs.getstringptr());
1384 QML_END_INSTR(NotCompareString)
1386 QML_BEGIN_INSTR(GreaterThanReal)
1388 const Register &lhs = registers[instr->binaryop.src1];
1389 const Register &rhs = registers[instr->binaryop.src2];
1390 Register &output = registers[instr->binaryop.output];
1391 if (lhs.isUndefined() || rhs.isUndefined()) output.setbool(false);
1392 else output.setbool(lhs.getqreal() > rhs.getqreal());
1394 QML_END_INSTR(GreaterThanReal)
1396 QML_BEGIN_INSTR(MaxReal)
1398 const Register &lhs = registers[instr->binaryop.src1];
1399 const Register &rhs = registers[instr->binaryop.src2];
1400 Register &output = registers[instr->binaryop.output];
1401 if (lhs.isUndefined() || rhs.isUndefined()) output.setNaN();
1402 else output.setqreal(qMax(lhs.getqreal(), rhs.getqreal()));
1404 QML_END_INSTR(MaxReal)
1406 QML_BEGIN_INSTR(MinReal)
1408 const Register &lhs = registers[instr->binaryop.src1];
1409 const Register &rhs = registers[instr->binaryop.src2];
1410 Register &output = registers[instr->binaryop.output];
1411 if (lhs.isUndefined() || rhs.isUndefined()) output.setNaN();
1412 else output.setqreal(qMin(lhs.getqreal(), rhs.getqreal()));
1414 QML_END_INSTR(MinReal)
1416 QML_BEGIN_INSTR(NewString)
1418 Register &output = registers[instr->construct.reg];
1419 new (output.getstringptr()) QString;
1420 output.settype(QMetaType::QString);
1422 QML_END_INSTR(NewString)
1424 QML_BEGIN_INSTR(NewUrl)
1426 Register &output = registers[instr->construct.reg];
1427 new (output.geturlptr()) QUrl;
1428 output.settype(QMetaType::QUrl);
1430 QML_END_INSTR(NewUrl)
1432 QML_BEGIN_INSTR(CleanupString)
1433 registers[instr->cleanup.reg].getstringptr()->~QString();
1434 #ifdef REGISTER_CLEANUP_DEBUG
1435 registers[instr->cleanup.reg].setUndefined();
1437 QML_END_INSTR(CleanupString)
1439 QML_BEGIN_INSTR(CleanupUrl)
1440 registers[instr->cleanup.reg].geturlptr()->~QUrl();
1441 #ifdef REGISTER_CLEANUP_DEBUG
1442 registers[instr->cleanup.reg].setUndefined();
1444 QML_END_INSTR(CleanupUrl)
1446 QML_BEGIN_INSTR(Fetch)
1448 const Register &input = registers[instr->fetch.objectReg];
1449 Register &output = registers[instr->fetch.output];
1451 if (input.isUndefined()) {
1452 throwException(instr->fetch.exceptionId, error, program, context);
1456 QObject *object = input.getQObject();
1458 output.setUndefined();
1460 void *argv[] = { output.typeDataPtr(), 0 };
1461 QMetaObject::metacall(object, QMetaObject::ReadProperty, instr->fetch.index, argv);
1464 QML_END_INSTR(Fetch)
1466 QML_BEGIN_INSTR(Store)
1468 Register &data = registers[instr->store.reg];
1469 if (data.isUndefined()) {
1470 throwException(instr->store.exceptionId, error, program, context,
1471 QLatin1String("Unable to assign undefined value"));
1476 void *argv[] = { data.typeDataPtr(), 0, &status, &storeFlags };
1477 QMetaObject::metacall(output, QMetaObject::WriteProperty,
1478 instr->store.index, argv);
1480 QML_END_INSTR(Store)
1482 QML_BEGIN_INSTR(Copy)
1483 registers[instr->copy.reg] = registers[instr->copy.src];
1486 QML_BEGIN_INSTR(Skip)
1487 if (instr->skip.reg == -1 || !registers[instr->skip.reg].getbool())
1488 instr += instr->skip.count;
1491 QML_BEGIN_INSTR(Done)
1495 QML_BEGIN_INSTR(InitString)
1496 if (!identifiers[instr->initstring.offset].identifier) {
1497 quint32 len = *(quint32 *)(data + instr->initstring.dataIdx);
1498 QChar *strdata = (QChar *)(data + instr->initstring.dataIdx + sizeof(quint32));
1500 QString str = QString::fromRawData(strdata, len);
1502 identifiers[instr->initstring.offset] = engine->objectClass->createPersistentIdentifier(str);
1504 QML_END_INSTR(InitString)
1506 QML_BEGIN_INSTR(FindGenericTerminal)
1507 // We start the search in the parent context, as we know that the
1508 // name is not present in the current context or it would have been
1509 // found during the static compile
1510 findgeneric(registers + instr->find.reg, instr->find.subscribeIndex,
1512 identifiers[instr->find.name].identifier,
1513 instr->common.type == Instr::FindGenericTerminal);
1514 QML_END_INSTR(FindGenericTerminal)
1516 QML_BEGIN_INSTR(FindGeneric)
1517 // We start the search in the parent context, as we know that the
1518 // name is not present in the current context or it would have been
1519 // found during the static compile
1520 findgeneric(registers + instr->find.reg, instr->find.subscribeIndex,
1522 identifiers[instr->find.name].identifier,
1523 instr->common.type == Instr::FindGenericTerminal);
1524 QML_END_INSTR(FindGeneric)
1526 QML_BEGIN_INSTR(FindPropertyTerminal)
1528 const Register &object = registers[instr->find.src];
1529 if (object.isUndefined()) {
1530 throwException(instr->find.exceptionId, error, program, context);
1534 findproperty(object.getQObject(), registers + instr->find.reg,
1535 QDeclarativeEnginePrivate::get(context->engine),
1536 instr->find.subscribeIndex, identifiers[instr->find.name].identifier,
1537 instr->common.type == Instr::FindPropertyTerminal);
1539 QML_END_INSTR(FindPropertyTerminal)
1541 QML_BEGIN_INSTR(FindProperty)
1543 const Register &object = registers[instr->find.src];
1544 if (object.isUndefined()) {
1545 throwException(instr->find.exceptionId, error, program, context);
1549 findproperty(object.getQObject(), registers + instr->find.reg,
1550 QDeclarativeEnginePrivate::get(context->engine),
1551 instr->find.subscribeIndex, identifiers[instr->find.name].identifier,
1552 instr->common.type == Instr::FindPropertyTerminal);
1554 QML_END_INSTR(FindProperty)
1556 QML_BEGIN_INSTR(CleanupGeneric)
1558 int type = registers[instr->cleanup.reg].gettype();
1559 if (type == qMetaTypeId<QVariant>()) {
1560 registers[instr->cleanup.reg].getvariantptr()->~QVariant();
1561 #ifdef REGISTER_CLEANUP_DEBUG
1562 registers[instr->cleanup.reg].setUndefined();
1564 } else if (type == QMetaType::QString) {
1565 registers[instr->cleanup.reg].getstringptr()->~QString();
1566 #ifdef REGISTER_CLEANUP_DEBUG
1567 registers[instr->cleanup.reg].setUndefined();
1569 } else if (type == QMetaType::QUrl) {
1570 registers[instr->cleanup.reg].geturlptr()->~QUrl();
1571 #ifdef REGISTER_CLEANUP_DEBUG
1572 registers[instr->cleanup.reg].setUndefined();
1576 QML_END_INSTR(CleanupGeneric)
1578 QML_BEGIN_INSTR(ConvertGenericToReal)
1580 Register &output = registers[instr->unaryop.output];
1581 Register &input = registers[instr->unaryop.src];
1583 output.setqreal(toReal(&input, input.gettype(), &ok));
1584 if (!ok) output.setUndefined();
1586 QML_END_INSTR(ConvertGenericToReal)
1588 QML_BEGIN_INSTR(ConvertGenericToBool)
1590 Register &output = registers[instr->unaryop.output];
1591 Register &input = registers[instr->unaryop.src];
1593 output.setbool(toBool(&input, input.gettype(), &ok));
1594 if (!ok) output.setUndefined();
1596 QML_END_INSTR(ConvertGenericToBool)
1598 QML_BEGIN_INSTR(ConvertGenericToString)
1600 Register &output = registers[instr->unaryop.output];
1601 Register &input = registers[instr->unaryop.src];
1603 QString str = toString(&input, input.gettype(), &ok);
1604 if (ok) { new (output.getstringptr()) QString(str); output.settype(QMetaType::QString); }
1605 else { output.setUndefined(); }
1607 QML_END_INSTR(ConvertGenericToString)
1609 QML_BEGIN_INSTR(ConvertGenericToUrl)
1611 Register &output = registers[instr->unaryop.output];
1612 Register &input = registers[instr->unaryop.src];
1614 QUrl url = toUrl(&input, input.gettype(), context, &ok);
1615 if (ok) { new (output.geturlptr()) QUrl(url); output.settype(QMetaType::QUrl); }
1616 else { output.setUndefined(); }
1618 QML_END_INSTR(ConvertGenericToUrl)
1620 #ifdef QML_THREADED_INTERPRETER
1633 void QDeclarativeBindingCompiler::dump(const QByteArray &programData)
1635 const Program *program = (const Program *)programData.constData();
1637 qWarning() << "Program.bindings:" << program->bindings;
1638 qWarning() << "Program.dataLength:" << program->dataLength;
1639 qWarning() << "Program.subscriptions:" << program->subscriptions;
1640 qWarning() << "Program.indentifiers:" << program->identifiers;
1642 int count = program->instructionCount;
1643 const Instr *instr = program->instructions();
1647 dumpInstruction(instr);
1653 Clear the state associated with attempting to compile a specific binding.
1654 This does not clear the global "committed binding" states.
1656 void QDeclarativeBindingCompilerPrivate::resetInstanceState()
1659 registerCleanups.clear();
1660 data = committed.data;
1661 exceptions = committed.exceptions;
1662 usedSubscriptionIds.clear();
1663 subscriptionSet.clear();
1664 subscriptionIds = committed.subscriptionIds;
1665 registeredStrings = committed.registeredStrings;
1670 Mark the last compile as successful, and add it to the "committed data"
1673 Returns the index for the committed binding.
1675 int QDeclarativeBindingCompilerPrivate::commitCompile()
1677 int rv = committed.count();
1678 committed.offsets << committed.bytecode.count();
1679 committed.dependencies << usedSubscriptionIds;
1680 committed.bytecode << bytecode;
1681 committed.data = data;
1682 committed.exceptions = exceptions;
1683 committed.subscriptionIds = subscriptionIds;
1684 committed.registeredStrings = registeredStrings;
1688 bool QDeclarativeBindingCompilerPrivate::compile(QDeclarativeJS::AST::Node *node)
1690 resetInstanceState();
1692 if (destination->type == -1)
1695 if (bindingsDump()) {
1696 QDeclarativeJS::AST::ExpressionNode *n = node->expressionCast();
1699 id.common.type = Instr::BindingId;
1700 id.id.column = n->firstSourceLocation().startColumn;
1701 id.id.line = n->firstSourceLocation().startLine;
1708 if (!parseExpression(node, type))
1711 if (subscriptionSet.count() > 0xFFFF ||
1712 registeredStrings.count() > 0xFFFF)
1715 if (type.unknownType) {
1716 if (!qmlExperimental())
1719 if (destination->type != QMetaType::QReal &&
1720 destination->type != QVariant::String &&
1721 destination->type != QMetaType::Bool &&
1722 destination->type != QVariant::Url)
1725 int convertReg = acquireReg();
1726 if (convertReg == -1)
1729 if (destination->type == QMetaType::QReal) {
1731 convert.common.type = Instr::ConvertGenericToReal;
1732 convert.unaryop.output = convertReg;
1733 convert.unaryop.src = type.reg;
1734 bytecode << convert;
1735 } else if (destination->type == QVariant::String) {
1737 convert.common.type = Instr::ConvertGenericToString;
1738 convert.unaryop.output = convertReg;
1739 convert.unaryop.src = type.reg;
1740 bytecode << convert;
1741 } else if (destination->type == QMetaType::Bool) {
1743 convert.common.type = Instr::ConvertGenericToBool;
1744 convert.unaryop.output = convertReg;
1745 convert.unaryop.src = type.reg;
1746 bytecode << convert;
1747 } else if (destination->type == QVariant::Url) {
1749 convert.common.type = Instr::ConvertGenericToUrl;
1750 convert.unaryop.output = convertReg;
1751 convert.unaryop.src = type.reg;
1752 bytecode << convert;
1756 cleanup.common.type = Instr::CleanupGeneric;
1757 cleanup.cleanup.reg = type.reg;
1758 bytecode << cleanup;
1761 instr.common.type = Instr::Store;
1762 instr.store.output = 0;
1763 instr.store.index = destination->index;
1764 instr.store.reg = convertReg;
1765 instr.store.exceptionId = exceptionId(node->expressionCast());
1768 if (destination->type == QVariant::String) {
1770 cleanup.common.type = Instr::CleanupString;
1771 cleanup.cleanup.reg = convertReg;
1772 bytecode << cleanup;
1773 } else if (destination->type == QVariant::Url) {
1775 cleanup.common.type = Instr::CleanupUrl;
1776 cleanup.cleanup.reg = convertReg;
1777 bytecode << cleanup;
1780 releaseReg(convertReg);
1783 done.common.type = Instr::Done;
1787 // Can we store the final value?
1788 if (type.type == QVariant::Int &&
1789 destination->type == QMetaType::QReal) {
1791 instr.common.type = Instr::ConvertIntToReal;
1792 instr.unaryop.output = type.reg;
1793 instr.unaryop.src = type.reg;
1795 type.type = QMetaType::QReal;
1796 } else if (type.type == QMetaType::QReal &&
1797 destination->type == QVariant::Int) {
1799 instr.common.type = Instr::ConvertRealToInt;
1800 instr.unaryop.output = type.reg;
1801 instr.unaryop.src = type.reg;
1803 type.type = QVariant::Int;
1804 } else if (type.type == destination->type) {
1806 const QMetaObject *from = type.metaObject;
1807 const QMetaObject *to = engine->rawMetaObjectForType(destination->type);
1809 if (QDeclarativePropertyPrivate::canConvert(from, to))
1810 type.type = destination->type;
1813 if (type.type == destination->type) {
1815 instr.common.type = Instr::Store;
1816 instr.store.output = 0;
1817 instr.store.index = destination->index;
1818 instr.store.reg = type.reg;
1819 instr.store.exceptionId = exceptionId(node->expressionCast());
1822 releaseReg(type.reg);
1825 done.common.type = Instr::Done;
1835 bool QDeclarativeBindingCompilerPrivate::parseExpression(QDeclarativeJS::AST::Node *node, Result &type)
1837 while (node->kind == AST::Node::Kind_NestedExpression)
1838 node = static_cast<AST::NestedExpression *>(node)->expression;
1840 if (tryArith(node)) {
1841 if (!parseArith(node, type)) return false;
1842 } else if (tryLogic(node)) {
1843 if (!parseLogic(node, type)) return false;
1844 } else if (tryConditional(node)) {
1845 if (!parseConditional(node, type)) return false;
1846 } else if (tryName(node)) {
1847 if (!parseName(node, type)) return false;
1848 } else if (tryConstant(node)) {
1849 if (!parseConstant(node, type)) return false;
1850 } else if (tryMethod(node)) {
1851 if (!parseMethod(node, type)) return false;
1858 bool QDeclarativeBindingCompilerPrivate::tryName(QDeclarativeJS::AST::Node *node)
1860 return node->kind == AST::Node::Kind_IdentifierExpression ||
1861 node->kind == AST::Node::Kind_FieldMemberExpression;
1864 bool QDeclarativeBindingCompilerPrivate::parseName(AST::Node *node, Result &type)
1866 QStringList nameParts;
1867 QList<AST::ExpressionNode *> nameNodes;
1868 if (!buildName(nameParts, node, &nameNodes))
1871 int reg = acquireReg();
1876 QDeclarativeParser::Object *absType = 0;
1878 QStringList subscribeName;
1880 bool wasAttachedObject = false;
1882 for (int ii = 0; ii < nameParts.count(); ++ii) {
1883 const QString &name = nameParts.at(ii);
1885 // We don't handle signal properties or attached properties
1886 if (name.length() > 2 && name.startsWith(QLatin1String("on")) &&
1887 name.at(2).isUpper())
1890 QDeclarativeType *attachType = 0;
1891 if (name.at(0).isUpper()) {
1892 // Could be an attached property
1893 if (ii == nameParts.count() - 1)
1895 if (nameParts.at(ii + 1).at(0).isUpper())
1898 QDeclarativeImportedNamespace *ns = 0;
1899 if (!imports.resolveType(name.toUtf8(), &attachType, 0, 0, 0, &ns))
1901 if (ns || !attachType || !attachType->attachedPropertiesType())
1904 wasAttachedObject = true;
1911 instr.common.type = Instr::LoadScope;
1912 instr.load.index = 0;
1913 instr.load.reg = reg;
1917 attach.common.type = Instr::LoadAttached;
1918 attach.attached.output = reg;
1919 attach.attached.reg = reg;
1920 attach.attached.id = attachType->attachedPropertiesId();
1921 attach.attached.exceptionId = exceptionId(nameNodes.at(ii));
1924 subscribeName << contextName();
1925 subscribeName << QLatin1String("$$$ATTACH_") + name;
1928 type.metaObject = attachType->attachedPropertiesType();
1931 } else if (ids.contains(name)) {
1932 QDeclarativeParser::Object *idObject = ids.value(name);
1934 type.metaObject = absType->metaObject();
1936 // We check if the id object is the root or
1937 // scope object to avoid a subscription
1938 if (idObject == component) {
1940 instr.common.type = Instr::LoadRoot;
1941 instr.load.index = 0;
1942 instr.load.reg = reg;
1944 } else if (idObject == context) {
1946 instr.common.type = Instr::LoadScope;
1947 instr.load.index = 0;
1948 instr.load.reg = reg;
1952 instr.common.type = Instr::LoadId;
1953 instr.load.index = idObject->idIndex;
1954 instr.load.reg = reg;
1957 subscribeName << QLatin1String("$$$ID_") + name;
1959 if (subscription(subscribeName, &type)) {
1961 sub.common.type = Instr::SubscribeId;
1962 sub.subscribe.offset = subscriptionIndex(subscribeName);
1963 sub.subscribe.reg = reg;
1964 sub.subscribe.index = instr.load.index;
1971 QByteArray utf8Name = name.toUtf8();
1972 const char *cname = utf8Name.constData();
1974 int d0Idx = (context == component)?-1:context->metaObject()->indexOfProperty(cname);
1977 d1Idx = component->metaObject()->indexOfProperty(cname);
1981 instr.common.type = Instr::LoadScope;
1982 instr.load.index = 0;
1983 instr.load.reg = reg;
1986 subscribeName << contextName();
1987 subscribeName << name;
1989 if (!fetch(type, context->metaObject(), reg, d0Idx, subscribeName, nameNodes.at(ii)))
1991 } else if(d1Idx != -1) {
1993 instr.common.type = Instr::LoadRoot;
1994 instr.load.index = 0;
1995 instr.load.reg = reg;
1998 subscribeName << QLatin1String("$$$ROOT");
1999 subscribeName << name;
2001 if (!fetch(type, component->metaObject(), reg, d1Idx, subscribeName, nameNodes.at(ii)))
2003 } else if (qmlExperimental()) {
2005 if (nameParts.count() == 1)
2006 find.common.type = Instr::FindGenericTerminal;
2008 find.common.type = Instr::FindGeneric;
2010 find.find.reg = reg;
2012 find.find.name = registerString(name);
2013 find.find.exceptionId = exceptionId(nameNodes.at(ii));
2015 subscribeName << QString(QLatin1String("$$$Generic_") + name);
2016 if (subscription(subscribeName, &type))
2017 find.find.subscribeIndex = subscriptionIndex(subscribeName);
2019 find.find.subscribeIndex = -1;
2022 type.unknownType = true;
2025 if (!type.unknownType && type.type == -1)
2026 return false; // Couldn't fetch that type
2033 attach.common.type = Instr::LoadAttached;
2034 attach.attached.output = reg;
2035 attach.attached.reg = reg;
2036 attach.attached.id = attachType->attachedPropertiesId();
2040 type.metaObject = attachType->attachedPropertiesType();
2042 subscribeName << QLatin1String("$$$ATTACH_") + name;
2046 const QMetaObject *mo = 0;
2048 mo = absType->metaObject();
2049 else if (type.metaObject)
2050 mo = type.metaObject;
2052 QByteArray utf8Name = name.toUtf8();
2053 const char *cname = utf8Name.constData();
2054 int idx = mo?mo->indexOfProperty(cname):-1;
2055 if (absType && idx == -1)
2058 subscribeName << name;
2060 if (absType || (wasAttachedObject && idx != -1) || (mo && mo->property(idx).isFinal())) {
2062 if (!fetch(type, mo, reg, idx, subscribeName, nameNodes.at(ii)))
2067 if (ii == nameParts.count() -1 )
2068 prop.common.type = Instr::FindPropertyTerminal;
2070 prop.common.type = Instr::FindProperty;
2072 prop.find.reg = reg;
2073 prop.find.src = reg;
2074 prop.find.name = registerString(name);
2075 prop.find.exceptionId = exceptionId(nameNodes.at(ii));
2077 if (subscription(subscribeName, &type))
2078 prop.find.subscribeIndex = subscriptionIndex(subscribeName);
2080 prop.find.subscribeIndex = -1;
2082 type.unknownType = true;
2083 type.metaObject = 0;
2090 wasAttachedObject = false;
2096 bool QDeclarativeBindingCompilerPrivate::tryArith(QDeclarativeJS::AST::Node *node)
2098 if (node->kind != AST::Node::Kind_BinaryExpression)
2101 AST::BinaryExpression *expression = static_cast<AST::BinaryExpression *>(node);
2102 if (expression->op == QSOperator::Add ||
2103 expression->op == QSOperator::Sub)
2109 bool QDeclarativeBindingCompilerPrivate::parseArith(QDeclarativeJS::AST::Node *node, Result &type)
2111 AST::BinaryExpression *expression = static_cast<AST::BinaryExpression *>(node);
2113 type.reg = acquireReg();
2120 if (!parseExpression(expression->left, lhs)) return false;
2121 if (!parseExpression(expression->right, rhs)) return false;
2123 if ((lhs.type == QVariant::Int || lhs.type == QMetaType::QReal) &&
2124 (rhs.type == QVariant::Int || rhs.type == QMetaType::QReal))
2125 return numberArith(type, lhs, rhs, (QSOperator::Op)expression->op);
2126 else if(expression->op == QSOperator::Sub)
2127 return numberArith(type, lhs, rhs, (QSOperator::Op)expression->op);
2128 else if ((lhs.type == QMetaType::QString || lhs.unknownType) &&
2129 (rhs.type == QMetaType::QString || rhs.unknownType) &&
2130 (lhs.type == QMetaType::QString || rhs.type == QMetaType::QString))
2131 return stringArith(type, lhs, rhs, (QSOperator::Op)expression->op);
2136 bool QDeclarativeBindingCompilerPrivate::numberArith(Result &type, const Result &lhs, const Result &rhs, QSOperator::Op op)
2138 bool nativeReal = rhs.type == QMetaType::QReal ||
2139 lhs.type == QMetaType::QReal ||
2143 if (nativeReal && lhs.type == QMetaType::Int) {
2145 convert.common.type = Instr::ConvertIntToReal;
2146 convert.unaryop.output = lhs.reg;
2147 convert.unaryop.src = lhs.reg;
2148 bytecode << convert;
2151 if (nativeReal && rhs.type == QMetaType::Int) {
2153 convert.common.type = Instr::ConvertIntToReal;
2154 convert.unaryop.output = rhs.reg;
2155 convert.unaryop.src = rhs.reg;
2156 bytecode << convert;
2162 if (lhs.unknownType) {
2163 if (!qmlExperimental())
2166 lhsTmp = acquireReg();
2171 conv.common.type = Instr::ConvertGenericToReal;
2172 conv.unaryop.output = lhsTmp;
2173 conv.unaryop.src = lhs.reg;
2177 if (rhs.unknownType) {
2178 if (!qmlExperimental())
2181 rhsTmp = acquireReg();
2186 conv.common.type = Instr::ConvertGenericToReal;
2187 conv.unaryop.output = rhsTmp;
2188 conv.unaryop.src = rhs.reg;
2193 if (op == QSOperator::Add) {
2194 arith.common.type = nativeReal?Instr::AddReal:Instr::AddInt;
2195 } else if (op == QSOperator::Sub) {
2196 arith.common.type = nativeReal?Instr::MinusReal:Instr::MinusInt;
2198 qFatal("Unsupported arithmetic operator");
2201 arith.binaryop.output = type.reg;
2202 arith.binaryop.src1 = (lhsTmp == -1)?lhs.reg:lhsTmp;
2203 arith.binaryop.src2 = (rhsTmp == -1)?rhs.reg:rhsTmp;
2206 type.metaObject = 0;
2207 type.type = nativeReal?QMetaType::QReal:QMetaType::Int;
2208 type.subscriptionSet.unite(lhs.subscriptionSet);
2209 type.subscriptionSet.unite(rhs.subscriptionSet);
2211 if (lhsTmp != -1) releaseReg(lhsTmp);
2212 if (rhsTmp != -1) releaseReg(rhsTmp);
2213 releaseReg(lhs.reg);
2214 releaseReg(rhs.reg);
2219 bool QDeclarativeBindingCompilerPrivate::stringArith(Result &type, const Result &lhs, const Result &rhs, QSOperator::Op op)
2221 if (op != QSOperator::Add)
2227 if (lhs.unknownType) {
2228 if (!qmlExperimental())
2231 lhsTmp = acquireReg(Instr::CleanupString);
2236 convert.common.type = Instr::ConvertGenericToString;
2237 convert.unaryop.output = lhsTmp;
2238 convert.unaryop.src = lhs.reg;
2239 bytecode << convert;
2242 if (rhs.unknownType) {
2243 if (!qmlExperimental())
2246 rhsTmp = acquireReg(Instr::CleanupString);
2251 convert.common.type = Instr::ConvertGenericToString;
2252 convert.unaryop.output = rhsTmp;
2253 convert.unaryop.src = rhs.reg;
2254 bytecode << convert;
2257 type.reg = acquireReg(Instr::CleanupString);
2261 type.type = QMetaType::QString;
2264 add.common.type = Instr::AddString;
2265 add.binaryop.output = type.reg;
2266 add.binaryop.src1 = (lhsTmp == -1)?lhs.reg:lhsTmp;
2267 add.binaryop.src2 = (rhsTmp == -1)?rhs.reg:rhsTmp;
2270 if (lhsTmp != -1) releaseReg(lhsTmp);
2271 if (rhsTmp != -1) releaseReg(rhsTmp);
2272 releaseReg(lhs.reg);
2273 releaseReg(rhs.reg);
2278 bool QDeclarativeBindingCompilerPrivate::tryLogic(QDeclarativeJS::AST::Node *node)
2280 if (node->kind != AST::Node::Kind_BinaryExpression)
2283 AST::BinaryExpression *expression = static_cast<AST::BinaryExpression *>(node);
2284 if (expression->op == QSOperator::Gt ||
2285 expression->op == QSOperator::Equal ||
2286 expression->op == QSOperator::NotEqual)
2292 bool QDeclarativeBindingCompilerPrivate::parseLogic(QDeclarativeJS::AST::Node *node, Result &type)
2294 AST::BinaryExpression *expression = static_cast<AST::BinaryExpression *>(node);
2299 if (!parseExpression(expression->left, lhs)) return false;
2300 if (!parseExpression(expression->right, rhs)) return false;
2302 type.reg = acquireReg();
2306 type.metaObject = 0;
2307 type.type = QVariant::Bool;
2309 if (lhs.type == QMetaType::QReal && rhs.type == QMetaType::QReal) {
2312 if (expression->op == QSOperator::Gt)
2313 op.common.type = Instr::GreaterThanReal;
2314 else if (expression->op == QSOperator::Equal)
2315 op.common.type = Instr::CompareReal;
2316 else if (expression->op == QSOperator::NotEqual)
2317 op.common.type = Instr::NotCompareReal;
2320 op.binaryop.output = type.reg;
2321 op.binaryop.src1 = lhs.reg;
2322 op.binaryop.src2 = rhs.reg;
2326 } else if (lhs.type == QMetaType::QString && rhs.type == QMetaType::QString) {
2329 if (expression->op == QSOperator::Equal)
2330 op.common.type = Instr::CompareString;
2331 else if (expression->op == QSOperator::NotEqual)
2332 op.common.type = Instr::NotCompareString;
2335 op.binaryop.output = type.reg;
2336 op.binaryop.src1 = lhs.reg;
2337 op.binaryop.src2 = rhs.reg;
2344 releaseReg(lhs.reg);
2345 releaseReg(rhs.reg);
2350 bool QDeclarativeBindingCompilerPrivate::tryConditional(QDeclarativeJS::AST::Node *node)
2352 return (node->kind == AST::Node::Kind_ConditionalExpression);
2355 bool QDeclarativeBindingCompilerPrivate::parseConditional(QDeclarativeJS::AST::Node *node, Result &type)
2357 AST::ConditionalExpression *expression = static_cast<AST::ConditionalExpression *>(node);
2359 AST::Node *test = expression->expression;
2360 if (test->kind == AST::Node::Kind_NestedExpression)
2361 test = static_cast<AST::NestedExpression*>(test)->expression;
2364 if (!parseExpression(test, etype)) return false;
2366 if (etype.type != QVariant::Bool)
2370 skip.common.type = Instr::Skip;
2371 skip.skip.reg = etype.reg;
2372 skip.skip.count = 0;
2373 int skipIdx = bytecode.count();
2376 // Release to allow reuse of reg
2377 releaseReg(etype.reg);
2379 QSet<QString> preSubSet = subscriptionSet;
2381 // int preConditionalSubscriptions = subscriptionSet.count();
2384 if (!parseExpression(expression->ok, ok)) return false;
2385 if (ok.unknownType) return false;
2387 int skipIdx2 = bytecode.count();
2391 // Release to allow reuse of reg
2393 bytecode[skipIdx].skip.count = bytecode.count() - skipIdx - 1;
2395 subscriptionSet = preSubSet;
2398 if (!parseExpression(expression->ko, ko)) return false;
2399 if (ko.unknownType) return false;
2401 // Release to allow reuse of reg
2403 bytecode[skipIdx2].skip.count = bytecode.count() - skipIdx2 - 1;
2406 return false; // Must be same type and in same register
2408 subscriptionSet = preSubSet;
2410 if (!subscriptionNeutral(subscriptionSet, ok.subscriptionSet, ko.subscriptionSet))
2411 return false; // Conditionals cannot introduce new subscriptions
2418 bool QDeclarativeBindingCompilerPrivate::tryConstant(QDeclarativeJS::AST::Node *node)
2420 return node->kind == AST::Node::Kind_TrueLiteral ||
2421 node->kind == AST::Node::Kind_FalseLiteral ||
2422 node->kind == AST::Node::Kind_NumericLiteral ||
2423 node->kind == AST::Node::Kind_StringLiteral;
2426 bool QDeclarativeBindingCompilerPrivate::parseConstant(QDeclarativeJS::AST::Node *node, Result &type)
2428 type.metaObject = 0;
2430 type.reg = acquireReg();
2434 if (node->kind == AST::Node::Kind_TrueLiteral) {
2435 type.type = QVariant::Bool;
2437 instr.common.type = Instr::Bool;
2438 instr.bool_value.reg = type.reg;
2439 instr.bool_value.value = true;
2442 } else if (node->kind == AST::Node::Kind_FalseLiteral) {
2443 type.type = QVariant::Bool;
2445 instr.common.type = Instr::Bool;
2446 instr.bool_value.reg = type.reg;
2447 instr.bool_value.value = false;
2450 } else if (node->kind == AST::Node::Kind_NumericLiteral) {
2451 qreal value = qreal(static_cast<AST::NumericLiteral *>(node)->value);
2453 if (qreal(float(value)) != value)
2456 type.type = QMetaType::QReal;
2458 instr.common.type = Instr::Real;
2459 instr.real_value.reg = type.reg;
2460 instr.real_value.value = float(value);
2463 } else if (node->kind == AST::Node::Kind_StringLiteral) {
2464 QString str = static_cast<AST::StringLiteral *>(node)->value->asString();
2465 type.type = QMetaType::QString;
2466 type.reg = registerLiteralString(str);
2473 bool QDeclarativeBindingCompilerPrivate::tryMethod(QDeclarativeJS::AST::Node *node)
2475 return node->kind == AST::Node::Kind_CallExpression;
2478 bool QDeclarativeBindingCompilerPrivate::parseMethod(QDeclarativeJS::AST::Node *node, Result &result)
2480 AST::CallExpression *expr = static_cast<AST::CallExpression *>(node);
2483 if (!buildName(name, expr->base))
2486 if (name.count() != 2 || name.at(0) != QLatin1String("Math"))
2489 QString method = name.at(1);
2491 AST::ArgumentList *args = expr->arguments;
2492 if (!args) return false;
2493 AST::ExpressionNode *arg0 = args->expression;
2495 if (!args) return false;
2496 AST::ExpressionNode *arg1 = args->expression;
2497 if (args->next != 0) return false;
2498 if (!arg0 || !arg1) return false;
2501 if (!parseExpression(arg0, r0)) return false;
2503 if (!parseExpression(arg1, r1)) return false;
2505 if (r0.type != QMetaType::QReal || r1.type != QMetaType::QReal)
2509 if (method == QLatin1String("max")) {
2510 op.common.type = Instr::MaxReal;
2511 } else if (method == QLatin1String("min")) {
2512 op.common.type = Instr::MinReal;
2516 // We release early to reuse registers
2520 op.binaryop.output = acquireReg();
2521 if (op.binaryop.output == -1)
2524 op.binaryop.src1 = r0.reg;
2525 op.binaryop.src2 = r1.reg;
2528 result.type = QMetaType::QReal;
2529 result.reg = op.binaryop.output;
2534 bool QDeclarativeBindingCompilerPrivate::buildName(QStringList &name,
2535 QDeclarativeJS::AST::Node *node,
2536 QList<QDeclarativeJS::AST::ExpressionNode *> *nodes)
2538 if (node->kind == AST::Node::Kind_IdentifierExpression) {
2539 name << static_cast<AST::IdentifierExpression*>(node)->name->asString();
2540 if (nodes) *nodes << static_cast<AST::IdentifierExpression*>(node);
2541 } else if (node->kind == AST::Node::Kind_FieldMemberExpression) {
2542 AST::FieldMemberExpression *expr =
2543 static_cast<AST::FieldMemberExpression *>(node);
2545 if (!buildName(name, expr->base, nodes))
2548 name << expr->name->asString();
2549 if (nodes) *nodes << expr;
2557 bool QDeclarativeBindingCompilerPrivate::fetch(Result &rv, const QMetaObject *mo, int reg,
2558 int idx, const QStringList &subName,
2559 QDeclarativeJS::AST::ExpressionNode *node)
2561 QMetaProperty prop = mo->property(idx);
2565 //XXX binding optimizer doesn't handle properties with a revision
2566 if (prop.revision() > 0)
2569 int fastFetchIndex = fastProperties()->accessorIndexForProperty(mo, idx);
2573 if (!qmlDisableFastProperties() && fastFetchIndex != -1) {
2574 fetch.common.type = Instr::FetchAndSubscribe;
2575 fetch.fetchAndSubscribe.objectReg = reg;
2576 fetch.fetchAndSubscribe.output = reg;
2577 fetch.fetchAndSubscribe.function = fastFetchIndex;
2578 fetch.fetchAndSubscribe.subscription = subscriptionIndex(subName);
2579 fetch.fetchAndSubscribe.exceptionId = exceptionId(node);
2581 if (subscription(subName, &rv) && prop.hasNotifySignal() && prop.notifySignalIndex() != -1) {
2583 sub.common.type = Instr::Subscribe;
2584 sub.subscribe.offset = subscriptionIndex(subName);
2585 sub.subscribe.reg = reg;
2586 sub.subscribe.index = prop.notifySignalIndex();
2590 fetch.common.type = Instr::Fetch;
2591 fetch.fetch.objectReg = reg;
2592 fetch.fetch.index = idx;
2593 fetch.fetch.output = reg;
2594 fetch.fetch.exceptionId = exceptionId(node);
2597 rv.type = prop.userType();
2598 rv.metaObject = engine->metaObjectForType(rv.type);
2601 if (rv.type == QMetaType::QString) {
2602 int tmp = acquireReg();
2606 copy.common.type = Instr::Copy;
2607 copy.copy.reg = tmp;
2608 copy.copy.src = reg;
2611 fetch.fetch.objectReg = tmp;
2614 setup.common.type = Instr::NewString;
2615 setup.construct.reg = reg;
2617 registerCleanup(reg, Instr::CleanupString);
2622 if (!rv.metaObject &&
2623 rv.type != QMetaType::QReal &&
2624 rv.type != QMetaType::Int &&
2625 rv.type != QMetaType::Bool &&
2626 rv.type != qMetaTypeId<QDeclarativeAnchorLine>() &&
2627 rv.type != QMetaType::QString) {
2630 return false; // Unsupported type (string not supported yet);
2636 void QDeclarativeBindingCompilerPrivate::registerCleanup(int reg, int cleanup, int cleanupType)
2638 registerCleanups.insert(reg, qMakePair(cleanup, cleanupType));
2641 int QDeclarativeBindingCompilerPrivate::acquireReg(int cleanup, int cleanupType)
2643 for (int ii = 0; ii < 32; ++ii) {
2644 if (!(registers & (1 << ii))) {
2645 registers |= (1 << ii);
2647 if (cleanup != Instr::Noop)
2648 registerCleanup(ii, cleanup, cleanupType);
2656 void QDeclarativeBindingCompilerPrivate::releaseReg(int reg)
2658 Q_ASSERT(reg >= 0 && reg <= 31);
2660 if (registerCleanups.contains(reg)) {
2661 QPair<int, int> c = registerCleanups[reg];
2662 registerCleanups.remove(reg);
2664 cleanup.common.type = (quint8)c.first;
2665 cleanup.cleanup.reg = reg;
2666 bytecode << cleanup;
2669 quint32 mask = 1 << reg;
2674 int QDeclarativeBindingCompilerPrivate::registerLiteralString(const QString &str)
2676 QByteArray strdata((const char *)str.constData(), str.length() * sizeof(QChar));
2677 int offset = data.count();
2680 int reg = acquireReg(Instr::CleanupString);
2685 string.common.type = Instr::String;
2686 string.string_value.reg = reg;
2687 string.string_value.offset = offset;
2688 string.string_value.length = str.length();
2694 // Returns an identifier offset
2695 int QDeclarativeBindingCompilerPrivate::registerString(const QString &string)
2697 Q_ASSERT(!string.isEmpty());
2699 QHash<QString, QPair<int, int> >::ConstIterator iter = registeredStrings.find(string);
2701 if (iter == registeredStrings.end()) {
2702 quint32 len = string.length();
2703 QByteArray lendata((const char *)&len, sizeof(quint32));
2704 QByteArray strdata((const char *)string.constData(), string.length() * sizeof(QChar));
2705 strdata.prepend(lendata);
2706 int rv = data.count();
2709 iter = registeredStrings.insert(string, qMakePair(registeredStrings.count(), rv));
2713 reg.common.type = Instr::InitString;
2714 reg.initstring.offset = iter->first;
2715 reg.initstring.dataIdx = iter->second;
2717 return reg.initstring.offset;
2720 bool QDeclarativeBindingCompilerPrivate::subscription(const QStringList &sub, Result *result)
2722 QString str = sub.join(QLatin1String("."));
2723 result->subscriptionSet.insert(str);
2725 if (subscriptionSet.contains(str)) {
2728 subscriptionSet.insert(str);
2733 int QDeclarativeBindingCompilerPrivate::subscriptionIndex(const QStringList &sub)
2735 QString str = sub.join(QLatin1String("."));
2736 QHash<QString, int>::ConstIterator iter = subscriptionIds.find(str);
2737 if (iter == subscriptionIds.end())
2738 iter = subscriptionIds.insert(str, subscriptionIds.count());
2739 usedSubscriptionIds.insert(*iter);
2744 Returns true if lhs contains no subscriptions that aren't also in base or rhs AND
2745 rhs contains no subscriptions that aren't also in base or lhs.
2747 bool QDeclarativeBindingCompilerPrivate::subscriptionNeutral(const QSet<QString> &base,
2748 const QSet<QString> &lhs,
2749 const QSet<QString> &rhs)
2751 QSet<QString> difflhs = lhs;
2752 difflhs.subtract(rhs);
2753 QSet<QString> diffrhs = rhs;
2754 diffrhs.subtract(lhs);
2756 difflhs.unite(diffrhs);
2757 difflhs.subtract(base);
2759 return difflhs.isEmpty();
2762 quint8 QDeclarativeBindingCompilerPrivate::exceptionId(QDeclarativeJS::AST::ExpressionNode *n)
2765 if (n && exceptions.count() < 0xFF) {
2766 rv = (quint8)exceptions.count();
2767 QDeclarativeJS::AST::SourceLocation l = n->firstSourceLocation();
2768 quint64 e = l.startLine;
2771 exceptions.append(e);
2776 QDeclarativeBindingCompiler::QDeclarativeBindingCompiler()
2777 : d(new QDeclarativeBindingCompilerPrivate)
2781 QDeclarativeBindingCompiler::~QDeclarativeBindingCompiler()
2787 Returns true if any bindings were compiled.
2789 bool QDeclarativeBindingCompiler::isValid() const
2791 return !d->committed.bytecode.isEmpty();
2795 -1 on failure, otherwise the binding index to use.
2797 int QDeclarativeBindingCompiler::compile(const Expression &expression, QDeclarativeEnginePrivate *engine)
2799 if (!expression.expression.asAST()) return false;
2801 if (!qmlExperimental() && expression.property->isValueTypeSubProperty)
2804 if (qmlDisableOptimizer())
2807 d->context = expression.context;
2808 d->component = expression.component;
2809 d->destination = expression.property;
2810 d->ids = expression.ids;
2811 d->imports = expression.imports;
2814 if (d->compile(expression.expression.asAST())) {
2815 return d->commitCompile();
2822 QByteArray QDeclarativeBindingCompilerPrivate::buildSignalTable() const
2824 QHash<int, QList<int> > table;
2826 for (int ii = 0; ii < committed.count(); ++ii) {
2827 const QSet<int> &deps = committed.dependencies.at(ii);
2828 for (QSet<int>::ConstIterator iter = deps.begin(); iter != deps.end(); ++iter)
2829 table[*iter].append(ii);
2832 QVector<quint32> header;
2833 QVector<quint32> data;
2834 for (int ii = 0; ii < committed.subscriptionIds.count(); ++ii) {
2835 header.append(committed.subscriptionIds.count() + data.count());
2836 const QList<int> &bindings = table[ii];
2837 data.append(bindings.count());
2838 for (int jj = 0; jj < bindings.count(); ++jj)
2839 data.append(bindings.at(jj));
2843 return QByteArray((const char *)header.constData(), header.count() * sizeof(quint32));
2846 QByteArray QDeclarativeBindingCompilerPrivate::buildExceptionData() const
2849 rv.resize(committed.exceptions.count() * sizeof(quint64));
2850 ::memcpy(rv.data(), committed.exceptions.constData(), rv.size());
2855 Returns the compiled program.
2857 QByteArray QDeclarativeBindingCompiler::program() const
2859 QByteArray programData;
2863 prog.bindings = d->committed.count();
2865 QVector<Instr> bytecode;
2867 skip.common.type = Instr::Skip;
2869 for (int ii = 0; ii < d->committed.count(); ++ii) {
2870 skip.skip.count = d->committed.count() - ii - 1;
2871 skip.skip.count+= d->committed.offsets.at(ii);
2874 bytecode << d->committed.bytecode;
2876 QByteArray data = d->committed.data;
2877 while (data.count() % 4) data.append('\0');
2878 prog.signalTableOffset = data.count();
2879 data += d->buildSignalTable();
2880 while (data.count() % 4) data.append('\0');
2881 prog.exceptionDataOffset = data.count();
2882 data += d->buildExceptionData();
2884 prog.dataLength = 4 * ((data.size() + 3) / 4);
2885 prog.subscriptions = d->committed.subscriptionIds.count();
2886 prog.identifiers = d->committed.registeredStrings.count();
2887 prog.instructionCount = bytecode.count();
2888 prog.compiled = false;
2889 int size = sizeof(Program) + bytecode.count() * sizeof(Instr);
2890 size += prog.dataLength;
2892 programData.resize(size);
2893 memcpy(programData.data(), &prog, sizeof(Program));
2894 if (prog.dataLength)
2895 memcpy((char *)((Program *)programData.data())->data(), data.constData(),
2897 memcpy((char *)((Program *)programData.data())->instructions(), bytecode.constData(),
2898 bytecode.count() * sizeof(Instr));