Initial import from the monolithic Qt.
[profile/ivi/qtdeclarative.git] / src / declarative / qml / qdeclarativecompiledbindings.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
6 **
7 ** This file is part of the QtDeclarative module of the Qt Toolkit.
8 **
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
14 ** this package.
15 **
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.
23 **
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.
27 **
28 ** If you have questions regarding the use of this file, please contact
29 ** Nokia at qt-info@nokia.com.
30 **
31 **
32 **
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 // #define COMPILEDBINDINGS_DEBUG
43 // #define REGISTER_CLEANUP_DEBUG
44
45 #include "private/qdeclarativecompiledbindings_p.h"
46
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>
59
60 QT_BEGIN_NAMESPACE
61
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);
66
67 Q_GLOBAL_STATIC(QDeclarativeFastProperties, fastProperties);
68
69 #if defined(Q_CC_GNU) && (!defined(Q_CC_INTEL) || __INTEL_COMPILER >= 1200)
70 #  define QML_THREADED_INTERPRETER
71 #endif
72
73 #define FOR_EACH_QML_INSTR(F) \
74     F(Noop)                    /* Nop */ \
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 */ \
105     F(Copy)                    /* copy */ \
106     F(Fetch)                   /* fetch */ \
107     F(Store)                   /* store */ \
108     F(Skip)                    /* skip */ \
109     F(Done)                    /* done */ \
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 */
121
122 #define QML_INSTR_ENUM(I) I,
123 #define QML_INSTR_ADDR(I) &&op_##I,
124
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;
129 #else
130 #  define QML_BEGIN_INSTR(I) case Instr::I:
131 #  define QML_END_INSTR(I) break;
132 #  define QML_INSTR_HEADER
133 #endif
134
135
136 using namespace QDeclarativeJS;
137
138 namespace {
139 // Supported types: int, qreal, QString (needs constr/destr), QObject*, bool
140 struct Register {
141     void setUndefined() { type = 0; }
142     void setUnknownButDefined() { type = -1; }
143     void setNaN() { setqreal(qSNaN()); }
144     bool isUndefined() const { return type == 0; }
145
146     void setQObject(QObject *o) { *((QObject **)data) = o; type = QMetaType::QObjectStar; }
147     QObject *getQObject() const { return *((QObject **)data); }
148
149     void setqreal(qreal v) { *((qreal *)data) = v; type = QMetaType::QReal; }
150     qreal getqreal() const { return *((qreal *)data); }
151
152     void setint(int v) { *((int *)data) = v; type = QMetaType::Int; }
153     int getint() const { return *((int *)data); }
154
155     void setbool(bool v) { *((bool *)data) = v; type = QMetaType::Bool; }
156     bool getbool() const { return *((bool *)data); }
157
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(); }
164
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; }
169
170     int gettype() const { return type; }
171     void settype(int t) { type = t; }
172
173     int type;          // Optional type
174     void *data[2];     // Object stored here
175
176 #ifdef REGISTER_CLEANUP_DEBUG
177     Register() {
178         type = 0;
179     }
180
181     ~Register() {
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);
187             ++ctype;
188         }
189         if (!found)
190             qWarning("Register leaked of type %d", type);
191     }
192 #endif
193 };
194 }
195
196 class QDeclarativeCompiledBindingsPrivate : public QObjectPrivate
197 {
198     Q_DECLARE_PUBLIC(QDeclarativeCompiledBindings)
199
200 public:
201     QDeclarativeCompiledBindingsPrivate();
202     virtual ~QDeclarativeCompiledBindingsPrivate();
203
204     struct Binding : public QDeclarativeAbstractBinding, public QDeclarativeDelayedError {
205         Binding() : enabled(false), updating(0), property(0),
206                     scope(0), target(0), parent(0) {}
207
208         // Inherited from QDeclarativeAbstractBinding
209         virtual void setEnabled(bool, QDeclarativePropertyPrivate::WriteFlags flags);
210         virtual void update(QDeclarativePropertyPrivate::WriteFlags flags);
211         virtual void destroy();
212
213         int index:30;
214         bool enabled:1;
215         bool updating:1;
216         int property;
217         QObject *scope;
218         QObject *target;
219
220         QDeclarativeCompiledBindingsPrivate *parent;
221     };
222
223     typedef QDeclarativeNotifierEndpoint Subscription;
224     Subscription *subscriptions;
225     QScriptDeclarativeClass::PersistentIdentifier *identifiers;
226
227     void run(Binding *, QDeclarativePropertyPrivate::WriteFlags flags);
228
229     const char *programData;
230     Binding *m_bindings;
231     quint32 *m_signalTable;
232
233     static int methodCount;
234
235     void init();
236     void run(int instr, QDeclarativeContextData *context, 
237              QDeclarativeDelayedError *error, QObject *scope, QObject *output, QDeclarativePropertyPrivate::WriteFlags storeFlags);
238
239
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);
243
244     QDeclarativePropertyCache::Data *findproperty(QObject *obj, 
245                                                   const QScriptDeclarativeClass::Identifier &name,
246                                                   QDeclarativeEnginePrivate *enginePriv, 
247                                                   QDeclarativePropertyCache::Data &local);
248     bool findproperty(QObject *obj, 
249                       Register *output, 
250                       QDeclarativeEnginePrivate *enginePriv,
251                       int subIdx, 
252                       const QScriptDeclarativeClass::Identifier &name,
253                       bool isTerminal);
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, 
258                      bool isTerminal);
259 };
260
261 QDeclarativeCompiledBindingsPrivate::QDeclarativeCompiledBindingsPrivate()
262 : subscriptions(0), identifiers(0)
263 {
264 }
265
266 QDeclarativeCompiledBindingsPrivate::~QDeclarativeCompiledBindingsPrivate()
267 {
268     delete [] subscriptions; subscriptions = 0;
269     delete [] identifiers; identifiers = 0;
270 }
271
272 int QDeclarativeCompiledBindingsPrivate::methodCount = -1;
273
274 QDeclarativeCompiledBindings::QDeclarativeCompiledBindings(const char *program, QDeclarativeContextData *context)
275 : QObject(*(new QDeclarativeCompiledBindingsPrivate))
276 {
277     Q_D(QDeclarativeCompiledBindings);
278
279     if (d->methodCount == -1)
280         d->methodCount = QDeclarativeCompiledBindings::staticMetaObject.methodCount();
281
282     d->programData = program;
283
284     d->init();
285
286     QDeclarativeAbstractExpression::setContext(context);
287 }
288
289 QDeclarativeCompiledBindings::~QDeclarativeCompiledBindings()
290 {
291     Q_D(QDeclarativeCompiledBindings);
292
293     delete [] d->m_bindings;
294 }
295
296 QDeclarativeAbstractBinding *QDeclarativeCompiledBindings::configBinding(int index, QObject *target, 
297                                                         QObject *scope, int property)
298 {
299     Q_D(QDeclarativeCompiledBindings);
300
301     QDeclarativeCompiledBindingsPrivate::Binding *rv = d->m_bindings + index;
302
303     rv->index = index;
304     rv->property = property;
305     rv->target = target;
306     rv->scope = scope;
307     rv->parent = d;
308
309     addref(); // This is decremented in Binding::destroy()
310
311     return rv;
312 }
313
314 void QDeclarativeCompiledBindingsPrivate::Binding::setEnabled(bool e, QDeclarativePropertyPrivate::WriteFlags flags)
315 {
316     if (enabled != e) {
317         enabled = e;
318
319         if (e) update(flags);
320     }
321 }
322
323 void QDeclarativeCompiledBindingsPrivate::Binding::update(QDeclarativePropertyPrivate::WriteFlags flags)
324 {
325     QDeclarativeDebugTrace::startRange(QDeclarativeDebugTrace::Binding);
326     parent->run(this, flags);
327     QDeclarativeDebugTrace::endRange(QDeclarativeDebugTrace::Binding);
328 }
329
330 void QDeclarativeCompiledBindingsPrivate::Binding::destroy()
331 {
332     enabled = false;
333     removeFromObject();
334     clear();
335     parent->q_func()->release();
336 }
337
338 int QDeclarativeCompiledBindings::qt_metacall(QMetaObject::Call c, int id, void **)
339 {
340     Q_D(QDeclarativeCompiledBindings);
341
342     if (c == QMetaObject::InvokeMetaMethod && id >= d->methodCount) {
343         id -= d->methodCount;
344
345         quint32 *reeval = d->m_signalTable + d->m_signalTable[id];
346         quint32 count = *reeval;
347         ++reeval;
348         for (quint32 ii = 0; ii < count; ++ii) {
349             d->run(d->m_bindings + reeval[ii], QDeclarativePropertyPrivate::DontRemoveBinding);
350         }
351     }
352     return -1;
353 }
354
355 void QDeclarativeCompiledBindingsPrivate::run(Binding *binding, QDeclarativePropertyPrivate::WriteFlags flags)
356 {
357     Q_Q(QDeclarativeCompiledBindings);
358
359     if (!binding->enabled)
360         return;
361
362     QDeclarativeContextData *context = q->QDeclarativeAbstractExpression::context();
363     if (!context || !context->isValid()) 
364         return;
365
366     if (binding->updating) {
367         QString name;
368         if (binding->property & 0xFFFF0000) {
369             QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(context->engine);
370
371             QDeclarativeValueType *vt = ep->valueTypes[(binding->property >> 16) & 0xFF];
372             Q_ASSERT(vt);
373
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()));
377         } else {
378             name = QLatin1String(binding->target->metaObject()->property(binding->property).name());
379         }
380         qmlInfo(binding->target) << QCoreApplication::translate("QDeclarativeCompiledBindings", "Binding loop detected for property \"%1\"").arg(name);
381         return;
382     }
383
384     binding->updating = true;
385     if (binding->property & 0xFFFF0000) {
386         QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(context->engine);
387
388         QDeclarativeValueType *vt = ep->valueTypes[(binding->property >> 16) & 0xFF];
389         Q_ASSERT(vt);
390         vt->read(binding->target, binding->property & 0xFFFF);
391
392         QObject *target = vt;
393         run(binding->index, context, binding, binding->scope, target, flags);
394
395         vt->write(binding->target, binding->property & 0xFFFF, flags);
396     } else {
397         run(binding->index, context, binding, binding->scope, binding->target, flags);
398     }
399     binding->updating = false;
400 }
401
402 namespace {
403 // This structure is exactly 8-bytes in size
404 struct Instr {
405     enum {
406         FOR_EACH_QML_INSTR(QML_INSTR_ENUM)
407     };
408
409     union {
410         struct {
411             QML_INSTR_HEADER
412             quint8 type;
413             quint8 packing[7];
414         } common;
415         struct {
416             QML_INSTR_HEADER
417             quint8 type;
418             quint8 packing;
419             quint16 column;
420             quint32 line;
421         } id;
422         struct {
423             QML_INSTR_HEADER
424             quint8 type;
425             quint8 packing[3];
426             quint16 subscriptions;
427             quint16 identifiers;
428         } init;
429         struct {
430             QML_INSTR_HEADER
431             quint8 type;
432             qint8 reg;
433             quint16 offset;
434             quint32 index;
435         } subscribe;
436         struct {
437             QML_INSTR_HEADER
438             quint8 type;
439             qint8 reg;
440             quint8 packing[2];
441             quint32 index;
442         } load;
443         struct {
444             QML_INSTR_HEADER
445             quint8 type;
446             qint8 output;
447             qint8 reg;
448             quint8 exceptionId;
449             quint32 id;
450         } attached;
451         struct {
452             QML_INSTR_HEADER
453             quint8 type;
454             qint8 output;
455             qint8 reg;
456             quint8 exceptionId;
457             quint32 index;
458         } store;
459         struct {
460             QML_INSTR_HEADER
461             quint8 type;
462             qint8 output;
463             qint8 objectReg;
464             quint8 exceptionId;
465             quint16 subscription;
466             quint16 function;
467         } fetchAndSubscribe;
468         struct {
469             QML_INSTR_HEADER
470             quint8 type;
471             qint8 output;
472             qint8 objectReg;
473             quint8 exceptionId;
474             quint32 index;
475         } fetch;
476         struct {
477             QML_INSTR_HEADER
478             quint8 type;
479             qint8 reg;
480             qint8 src;
481             quint8 packing[5];
482         } copy;
483         struct {
484             QML_INSTR_HEADER
485             quint8 type;
486             qint8 reg;
487             quint8 packing[6];
488         } construct;
489         struct {
490             QML_INSTR_HEADER
491             quint8 type;
492             qint8 reg;
493             quint8 packing[2];
494             float value;
495         } real_value;
496         struct {
497             QML_INSTR_HEADER
498             quint8 type;
499             qint8 reg;
500             quint8 packing[2];
501             int value;
502         } int_value;
503         struct {
504             QML_INSTR_HEADER
505             quint8 type;
506             qint8 reg;
507             bool value;
508             quint8 packing[5];
509         } bool_value;
510         struct {
511             QML_INSTR_HEADER
512             quint8 type;
513             qint8 reg;
514             quint16 length;
515             quint32 offset;
516         } string_value;
517         struct {
518             QML_INSTR_HEADER
519             quint8 type;
520             qint8 output;
521             qint8 src1;
522             qint8 src2;
523             quint8 packing[4];
524         } binaryop;
525         struct {
526             QML_INSTR_HEADER
527             quint8 type;
528             qint8 output;
529             qint8 src;
530             quint8 packing[5];
531         } unaryop;
532         struct {
533             QML_INSTR_HEADER
534             quint8 type;
535             qint8 reg;
536             quint8 packing[2];
537             quint32 count;
538         } skip;
539         struct {
540             QML_INSTR_HEADER
541             quint8 type;
542             qint8 reg;
543             qint8 src;
544             quint8 exceptionId;
545             quint16 name; 
546             quint16 subscribeIndex;
547         } find;
548         struct {
549             QML_INSTR_HEADER
550             quint8 type;
551             qint8 reg;
552             quint8 packing[6];
553         } cleanup;
554         struct {
555             QML_INSTR_HEADER
556             quint8 type;
557             quint8 packing[1];
558             quint16 offset;
559             quint32 dataIdx;
560         } initstring;
561     };
562 };
563
564 struct Program {
565     quint32 bindings;
566     quint32 dataLength;
567     quint32 signalTableOffset;
568     quint32 exceptionDataOffset;
569     quint16 subscriptions;
570     quint16 identifiers;
571     quint16 instructionCount;
572     quint16 compiled;
573
574     const char *data() const { return ((const char *)this) + sizeof(Program); }
575     const Instr *instructions() const { return (const Instr *)(data() + dataLength); }
576 };
577 }
578
579 struct QDeclarativeBindingCompilerPrivate
580 {
581     struct Result {
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 && 
586                    type == o.type &&
587                    reg == o.reg; 
588         }
589         bool operator!=(const Result &o) const { 
590             return !(*this == o);
591         }
592         bool unknownType;
593         const QMetaObject *metaObject;
594         int type;
595         int reg;
596
597         QSet<QString> subscriptionSet;
598     };
599
600     QDeclarativeBindingCompilerPrivate() : registers(0) {}
601
602     void resetInstanceState();
603     int commitCompile();
604
605     QDeclarativeParser::Object *context;
606     QDeclarativeParser::Object *component;
607     QDeclarativeParser::Property *destination;
608     QHash<QString, QDeclarativeParser::Object *> ids;
609     QDeclarativeImports imports;
610     QDeclarativeEnginePrivate *engine;
611
612     QString contextName() const { return QLatin1String("$$$SCOPE_") + QString::number((quintptr)context, 16); }
613
614     bool compile(QDeclarativeJS::AST::Node *);
615
616     bool parseExpression(QDeclarativeJS::AST::Node *, Result &);
617
618     bool tryName(QDeclarativeJS::AST::Node *);
619     bool parseName(QDeclarativeJS::AST::Node *, Result &);
620
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);
625
626     bool tryLogic(QDeclarativeJS::AST::Node *);
627     bool parseLogic(QDeclarativeJS::AST::Node *, Result &);
628
629     bool tryConditional(QDeclarativeJS::AST::Node *);
630     bool parseConditional(QDeclarativeJS::AST::Node *, Result &);
631
632     bool tryConstant(QDeclarativeJS::AST::Node *);
633     bool parseConstant(QDeclarativeJS::AST::Node *, Result &);
634
635     bool tryMethod(QDeclarativeJS::AST::Node *);
636     bool parseMethod(QDeclarativeJS::AST::Node *, Result &);
637
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 *);
640
641     quint32 registers;
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);
646
647     int registerLiteralString(const QString &);
648     int registerString(const QString &);
649     QHash<QString, QPair<int, int> > registeredStrings;
650     QByteArray data;
651
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);
655
656     quint8 exceptionId(QDeclarativeJS::AST::ExpressionNode *);
657     QVector<quint64> exceptions;
658
659     QSet<int> usedSubscriptionIds;
660     QSet<QString> subscriptionSet;
661     QHash<QString, int> subscriptionIds;
662     QVector<Instr> bytecode;
663
664     // Committed binding data
665     struct {
666         QList<int> offsets;
667         QList<QSet<int> > dependencies;
668
669         QVector<Instr> bytecode;
670         QByteArray data;
671         QHash<QString, int> subscriptionIds;
672         QVector<quint64> exceptions;
673
674         QHash<QString, QPair<int, int> > registeredStrings;
675
676         int count() const { return offsets.count(); }
677     } committed;
678
679     QByteArray buildSignalTable() const;
680     QByteArray buildExceptionData() const;
681 };
682
683 void QDeclarativeCompiledBindingsPrivate::unsubscribe(int subIndex)
684 {
685     QDeclarativeCompiledBindingsPrivate::Subscription *sub = (subscriptions + subIndex);
686     sub->disconnect();
687 }
688
689 void QDeclarativeCompiledBindingsPrivate::subscribeId(QDeclarativeContextData *p, int idIndex, int subIndex)
690 {
691     Q_Q(QDeclarativeCompiledBindings);
692
693     unsubscribe(subIndex);
694
695     if (p->idValues[idIndex]) {
696         QDeclarativeCompiledBindingsPrivate::Subscription *sub = (subscriptions + subIndex);
697         sub->target = q;
698         sub->targetMethod = methodCount + subIndex;
699         sub->connect(&p->idValues[idIndex].bindings);
700     }
701 }
702  
703 void QDeclarativeCompiledBindingsPrivate::subscribe(QObject *o, int notifyIndex, int subIndex)
704 {
705     Q_Q(QDeclarativeCompiledBindings);
706
707     QDeclarativeCompiledBindingsPrivate::Subscription *sub = (subscriptions + subIndex);
708     sub->target = q;
709     sub->targetMethod = methodCount + subIndex; 
710     if (o)
711         sub->connect(o, notifyIndex);
712     else
713         sub->disconnect();
714 }
715
716 // Conversion functions - these MUST match the QtScript expression path
717 inline static qreal toReal(Register *reg, int type, bool *ok = 0)
718 {
719     if (ok) *ok = true;
720
721     if (type == QMetaType::QReal) {
722         return reg->getqreal();
723     } else if (type == qMetaTypeId<QVariant>()) {
724         return reg->getvariantptr()->toReal();
725     } else {
726         if (ok) *ok = false;
727         return 0;
728     }
729 }
730
731 inline static QString toString(Register *reg, int type, bool *ok = 0)
732 {
733     if (ok) *ok = true;
734
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();
743     } else {
744         if (ok) *ok = false;
745         return QString();
746     }
747 }
748
749 inline static bool toBool(Register *reg, int type, bool *ok = 0)
750 {
751     if (ok) *ok = true;
752
753     if (type == QMetaType::Bool) {
754         return reg->getbool();
755     } else if (type == qMetaTypeId<QVariant>()) {
756         return reg->getvariantptr()->toBool();
757     } else {
758         if (ok) *ok = false;
759         return false;
760     }
761 }
762
763 inline static QUrl toUrl(Register *reg, int type, QDeclarativeContextData *context, bool *ok = 0)
764 {
765     if (ok) *ok = true;
766
767     QUrl base;
768     if (type == qMetaTypeId<QVariant>()) {
769         QVariant *var = reg->getvariantptr();
770         int vt = var->type();
771         if (vt == QVariant::Url) {
772             base = var->toUrl();
773         } else if (vt == QVariant::ByteArray) {
774             base = QUrl(QString::fromUtf8(var->toByteArray()));
775         } else if (vt == QVariant::String) {
776             base = QUrl(var->toString());
777         } else {
778             if (ok) *ok = false;
779             return QUrl();
780         }
781     } else if (type == QMetaType::QString) {
782         base = QUrl(*reg->getstringptr());
783     } else {
784         if (ok) *ok = false;
785         return QUrl();
786     }
787
788     if (!base.isEmpty() && base.isRelative())
789         return context->url.resolved(base);
790     else
791         return base;
792 }
793
794 static QObject *variantToQObject(const QVariant &value, bool *ok)
795 {
796     if (ok) *ok = true;
797
798     if (value.userType() == QMetaType::QObjectStar) {
799         return qvariant_cast<QObject*>(value);
800     } else {
801         if (ok) *ok = false;
802         return 0;
803     }
804 }
805
806 bool QDeclarativeCompiledBindingsPrivate::findproperty(QObject *obj, Register *output, 
807                                                        QDeclarativeEnginePrivate *enginePriv,
808                                                        int subIdx, const QScriptDeclarativeClass::Identifier &name,
809                                                        bool isTerminal)
810 {
811     if (!obj) {
812         output->setUndefined();
813         return false;
814     }
815
816     QDeclarativePropertyCache::Data local;
817     QDeclarativePropertyCache::Data *property = 
818         QDeclarativePropertyCache::property(QDeclarativeEnginePrivate::get(enginePriv), obj, name, local);
819
820     if (property) {
821         if (subIdx != -1)
822             subscribe(obj, property->notifyIndex, subIdx);
823
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>()) {
829             QVariant v;
830             void *args[] = { &v, 0 };
831             QMetaObject::metacall(obj, QMetaObject::ReadProperty, property->coreIndex, args);
832
833             if (isTerminal) {
834                 new (output->typeDataPtr()) QVariant(v);
835                 output->settype(qMetaTypeId<QVariant>());
836             } else {
837                 bool ok;
838                 output->setQObject(variantToQObject(v, &ok));
839                 if (!ok) 
840                     output->setUndefined();
841                 else
842                     output->settype(QMetaType::QObjectStar);
843             }
844
845         } else {
846             if (!isTerminal) {
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);
865             } else {
866                 new (output->typeDataPtr()) 
867                     QVariant(obj->metaObject()->property(property->coreIndex).read(obj));
868                 output->settype(qMetaTypeId<QVariant>());
869             }
870         }
871
872         return true;
873     } else {
874         output->setUndefined();
875         return false;
876     }
877 }
878
879 void QDeclarativeCompiledBindingsPrivate::findgeneric(Register *output, 
880                                                       int subIdx,      
881                                                       QDeclarativeContextData *context,
882                                                       const QScriptDeclarativeClass::Identifier &name, 
883                                                       bool isTerminal)
884 {
885     QDeclarativeEnginePrivate *enginePriv = QDeclarativeEnginePrivate::get(context->engine);
886
887     while (context) {
888
889         int contextPropertyIndex = context->propertyNames?context->propertyNames->value(name):-1;
890
891
892         if (contextPropertyIndex != -1) {
893
894             if (contextPropertyIndex < context->idValueCount) {
895                 output->setQObject(context->idValues[contextPropertyIndex]);
896                 output->settype(QMetaType::QObjectStar);
897
898                 if (subIdx != -1) 
899                     subscribeId(context, contextPropertyIndex, subIdx);
900
901             } else {
902                 QDeclarativeContextPrivate *cp = context->asQDeclarativeContextPrivate();
903                 const QVariant &value = cp->propertyValues.at(contextPropertyIndex);
904
905                 if (isTerminal) {
906                     new (output->typeDataPtr()) QVariant(value);
907                     output->settype(qMetaTypeId<QVariant>());
908                 } else {
909                     bool ok;
910                     output->setQObject(variantToQObject(value, &ok));
911                     if (!ok) { output->setUndefined(); }
912                     else { output->settype(QMetaType::QObjectStar); }
913                     return;
914                 }
915
916                 if (subIdx != -1) 
917                     subscribe(context->asQDeclarativeContext(), contextPropertyIndex + cp->notifyIndex, subIdx);
918
919
920             }
921
922             return;
923         }
924
925         if (QObject *root = context->contextObject) {
926
927             if (findproperty(root, output, enginePriv, subIdx, name, isTerminal))
928                 return;
929
930         }
931
932         context = context->parent;
933     }
934
935     output->setUndefined();
936 }
937
938 void QDeclarativeCompiledBindingsPrivate::init()
939 {
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];
945
946     m_signalTable = (quint32 *)(program->data() + program->signalTableOffset);
947     m_bindings = new QDeclarativeCompiledBindingsPrivate::Binding[program->bindings];
948 }
949
950 static void throwException(int id, QDeclarativeDelayedError *error, 
951                            Program *program, QDeclarativeContextData *context,
952                            const QString &description = QString())
953 {
954     error->error.setUrl(context->url);
955     if (description.isEmpty())
956         error->error.setDescription(QLatin1String("TypeError: Result of expression is not an object"));
957     else
958         error->error.setDescription(description);
959     if (id != 0xFF) {
960         quint64 e = *((quint64 *)(program->data() + program->exceptionDataOffset) + id); 
961         error->error.setLine((e >> 32) & 0xFFFFFFFF);
962         error->error.setColumn(e & 0xFFFFFFFF); 
963     } else {
964         error->error.setLine(-1);
965         error->error.setColumn(-1);
966     }
967     if (!context->engine || !error->addError(QDeclarativeEnginePrivate::get(context->engine)))
968         QDeclarativeEnginePrivate::warning(context->engine, error->error);
969 }
970
971 static void dumpInstruction(const Instr *instr)
972 {
973     switch (instr->common.type) {
974     case Instr::Noop:
975         qWarning().nospace() << "\t" << "Noop";
976         break;
977     case Instr::BindingId:
978         qWarning().nospace() << instr->id.line << ":" << instr->id.column << ":";
979         break;
980     case Instr::Subscribe:
981         qWarning().nospace() << "\t" << "Subscribe" << "\t\t" << instr->subscribe.offset << "\t" << instr->subscribe.reg << "\t" << instr->subscribe.index;
982         break;
983     case Instr::SubscribeId:
984         qWarning().nospace() << "\t" << "SubscribeId" << "\t\t" << instr->subscribe.offset << "\t" << instr->subscribe.reg << "\t" << instr->subscribe.index;
985         break;
986     case Instr::FetchAndSubscribe:
987         qWarning().nospace() << "\t" << "FetchAndSubscribe" << "\t" << instr->fetchAndSubscribe.output << "\t" << instr->fetchAndSubscribe.objectReg << "\t" << instr->fetchAndSubscribe.subscription;
988         break;
989     case Instr::LoadId:
990         qWarning().nospace() << "\t" << "LoadId" << "\t\t\t" << instr->load.index << "\t" << instr->load.reg;
991         break;
992     case Instr::LoadScope:
993         qWarning().nospace() << "\t" << "LoadScope" << "\t\t" << instr->load.index << "\t" << instr->load.reg;
994         break;
995     case Instr::LoadRoot:
996         qWarning().nospace() << "\t" << "LoadRoot" << "\t\t" << instr->load.index << "\t" << instr->load.reg;
997         break;
998     case Instr::LoadAttached:
999         qWarning().nospace() << "\t" << "LoadAttached" << "\t\t" << instr->attached.output << "\t" << instr->attached.reg << "\t" << instr->attached.id;
1000         break;
1001     case Instr::ConvertIntToReal:
1002         qWarning().nospace() << "\t" << "ConvertIntToReal" << "\t" << instr->unaryop.output << "\t" << instr->unaryop.src;
1003         break;
1004     case Instr::ConvertRealToInt:
1005         qWarning().nospace() << "\t" << "ConvertRealToInt" << "\t" << instr->unaryop.output << "\t" << instr->unaryop.src;
1006         break;
1007     case Instr::Real:
1008         qWarning().nospace() << "\t" << "Real" << "\t\t\t" << instr->real_value.reg << "\t" << instr->real_value.value;
1009         break;
1010     case Instr::Int:
1011         qWarning().nospace() << "\t" << "Int" << "\t\t\t" << instr->int_value.reg << "\t" << instr->int_value.value;
1012         break;
1013     case Instr::Bool:
1014         qWarning().nospace() << "\t" << "Bool" << "\t\t\t" << instr->bool_value.reg << "\t" << instr->bool_value.value;
1015         break;
1016     case Instr::String:
1017         qWarning().nospace() << "\t" << "String" << "\t\t\t" << instr->string_value.reg << "\t" << instr->string_value.offset << "\t" << instr->string_value.length;
1018         break;
1019     case Instr::AddReal:
1020         qWarning().nospace() << "\t" << "AddReal" << "\t\t\t" << instr->binaryop.output << "\t" << instr->binaryop.src1 << "\t" << instr->binaryop.src2;
1021         break;
1022     case Instr::AddInt:
1023         qWarning().nospace() << "\t" << "AddInt" << "\t\t\t" << instr->binaryop.output << "\t" << instr->binaryop.src1 << "\t" << instr->binaryop.src2;
1024         break;
1025     case Instr::AddString:
1026         qWarning().nospace() << "\t" << "AddString" << "\t\t" << instr->binaryop.output << "\t" << instr->binaryop.src1 << "\t" << instr->binaryop.src2;
1027         break;
1028     case Instr::MinusReal:
1029         qWarning().nospace() << "\t" << "MinusReal" << "\t\t" << instr->binaryop.output << "\t" << instr->binaryop.src1 << "\t" << instr->binaryop.src2;
1030         break;
1031     case Instr::MinusInt:
1032         qWarning().nospace() << "\t" << "MinusInt" << "\t\t" << instr->binaryop.output << "\t" << instr->binaryop.src1 << "\t" << instr->binaryop.src2;
1033         break;
1034     case Instr::CompareReal:
1035         qWarning().nospace() << "\t" << "CompareReal" << "\t\t" << instr->binaryop.output << "\t" << instr->binaryop.src1 << "\t" << instr->binaryop.src2;
1036         break;
1037     case Instr::CompareString:
1038         qWarning().nospace() << "\t" << "CompareString" << "\t\t" << instr->binaryop.output << "\t" << instr->binaryop.src1 << "\t" << instr->binaryop.src2;
1039         break;
1040     case Instr::NotCompareReal:
1041         qWarning().nospace() << "\t" << "NotCompareReal" << "\t\t" << instr->binaryop.output << "\t" << instr->binaryop.src1 << "\t" << instr->binaryop.src2;
1042         break;
1043     case Instr::NotCompareString:
1044         qWarning().nospace() << "\t" << "NotCompareString" << "\t\t" << instr->binaryop.output << "\t" << instr->binaryop.src1 << "\t" << instr->binaryop.src2;
1045         break;
1046     case Instr::GreaterThanReal:
1047         qWarning().nospace() << "\t" << "GreaterThanReal" << "\t\t" << instr->binaryop.output << "\t" << instr->binaryop.src1 << "\t" << instr->binaryop.src2;
1048         break;
1049     case Instr::MaxReal:
1050         qWarning().nospace() << "\t" << "MaxReal" << "\t\t\t" << instr->binaryop.output << "\t" << instr->binaryop.src1 << "\t" << instr->binaryop.src2;
1051         break;
1052     case Instr::MinReal:
1053         qWarning().nospace() << "\t" << "MinReal" << "\t\t\t" << instr->binaryop.output << "\t" << instr->binaryop.src1 << "\t" << instr->binaryop.src2;
1054         break;
1055     case Instr::NewString:
1056         qWarning().nospace() << "\t" << "NewString" << "\t\t" << instr->construct.reg;
1057         break;
1058     case Instr::NewUrl:
1059         qWarning().nospace() << "\t" << "NewUrl" << "\t\t\t" << instr->construct.reg;
1060         break;
1061     case Instr::CleanupString:
1062         qWarning().nospace() << "\t" << "CleanupString" << "\t\t" << instr->cleanup.reg;
1063         break;
1064     case Instr::CleanupUrl:
1065         qWarning().nospace() << "\t" << "CleanupUrl" << "\t\t" << instr->cleanup.reg;
1066         break;
1067     case Instr::Fetch:
1068         qWarning().nospace() << "\t" << "Fetch" << "\t\t\t" << instr->fetch.output << "\t" << instr->fetch.index << "\t" << instr->fetch.objectReg;
1069         break;
1070     case Instr::Store:
1071         qWarning().nospace() << "\t" << "Store" << "\t\t\t" << instr->store.output << "\t" << instr->store.index << "\t" << instr->store.reg;
1072         break;
1073     case Instr::Copy:
1074         qWarning().nospace() << "\t" << "Copy" << "\t\t\t" << instr->copy.reg << "\t" << instr->copy.src;
1075         break;
1076     case Instr::Skip:
1077         qWarning().nospace() << "\t" << "Skip" << "\t\t\t" << instr->skip.reg << "\t" << instr->skip.count;
1078         break;
1079     case Instr::Done:
1080         qWarning().nospace() << "\t" << "Done";
1081         break;
1082     case Instr::InitString:
1083         qWarning().nospace() << "\t" << "InitString" << "\t\t" << instr->initstring.offset << "\t" << instr->initstring.dataIdx;
1084         break;
1085     case Instr::FindGeneric:
1086         qWarning().nospace() << "\t" << "FindGeneric" << "\t\t" << instr->find.reg << "\t" << instr->find.name;
1087         break;
1088     case Instr::FindGenericTerminal:
1089         qWarning().nospace() << "\t" << "FindGenericTerminal" << "\t" << instr->find.reg << "\t" <<  instr->find.name;
1090         break;
1091     case Instr::FindProperty:
1092         qWarning().nospace() << "\t" << "FindProperty" << "\t\t" << instr->find.reg << "\t" << instr->find.src << "\t" << instr->find.name;
1093         break;
1094     case Instr::FindPropertyTerminal:
1095         qWarning().nospace() << "\t" << "FindPropertyTerminal" << "\t" << instr->find.reg << "\t" << instr->find.src << "\t" << instr->find.name;
1096         break;
1097     case Instr::CleanupGeneric:
1098         qWarning().nospace() << "\t" << "CleanupGeneric" << "\t\t" << instr->cleanup.reg;
1099         break;
1100     case Instr::ConvertGenericToReal:
1101         qWarning().nospace() << "\t" << "ConvertGenericToReal" << "\t" << instr->unaryop.output << "\t" << instr->unaryop.src;
1102         break;
1103     case Instr::ConvertGenericToBool:
1104         qWarning().nospace() << "\t" << "ConvertGenericToBool" << "\t" << instr->unaryop.output << "\t" << instr->unaryop.src;
1105         break;
1106     case Instr::ConvertGenericToString:
1107         qWarning().nospace() << "\t" << "ConvertGenericToString" << "\t" << instr->unaryop.output << "\t" << instr->unaryop.src;
1108         break;
1109     case Instr::ConvertGenericToUrl:
1110         qWarning().nospace() << "\t" << "ConvertGenericToUrl" << "\t" << instr->unaryop.output << "\t" << instr->unaryop.src;
1111         break;
1112     default:
1113         qWarning().nospace() << "\t" << "Unknown";
1114         break;
1115     }
1116 }
1117
1118 void QDeclarativeCompiledBindingsPrivate::run(int instrIndex,
1119                                               QDeclarativeContextData *context, QDeclarativeDelayedError *error,
1120                                               QObject *scope, QObject *output, QDeclarativePropertyPrivate::WriteFlags storeFlags)
1121 {
1122     Q_Q(QDeclarativeCompiledBindings);
1123
1124     error->removeError();
1125
1126     Register registers[32];
1127
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();
1133
1134 #ifdef QML_THREADED_INTERPRETER
1135     static void *decode_instr[] = {
1136         FOR_EACH_QML_INSTR(QML_INSTR_ADDR)
1137     };
1138
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];
1145         }
1146     }
1147
1148     goto *instr->common.code;
1149 #else
1150     // return;
1151
1152 #ifdef COMPILEDBINDINGS_DEBUG
1153     qWarning().nospace() << "Begin binding run";
1154 #endif
1155
1156     while (instr) {
1157         switch (instr->common.type) {
1158
1159 #ifdef COMPILEDBINDINGS_DEBUG
1160         dumpInstruction(instr);
1161 #endif
1162
1163 #endif
1164
1165     QML_BEGIN_INSTR(Noop)
1166     QML_END_INSTR(Noop)
1167
1168     QML_BEGIN_INSTR(BindingId)
1169     QML_END_INSTR(BindingId)
1170
1171     QML_BEGIN_INSTR(SubscribeId)
1172         subscribeId(context, instr->subscribe.index, instr->subscribe.offset);
1173     QML_END_INSTR(SubscribeId)
1174
1175     QML_BEGIN_INSTR(Subscribe)
1176     {
1177         QObject *o = 0;
1178         const Register &object = registers[instr->subscribe.reg];
1179         if (!object.isUndefined()) o = object.getQObject();
1180         subscribe(o, instr->subscribe.index, instr->subscribe.offset);
1181     }
1182     QML_END_INSTR(Subscribe)
1183
1184     QML_BEGIN_INSTR(FetchAndSubscribe)
1185     {
1186         const Register &input = registers[instr->fetchAndSubscribe.objectReg];
1187         Register &output = registers[instr->fetchAndSubscribe.output];
1188
1189         if (input.isUndefined()) {
1190             throwException(instr->fetchAndSubscribe.exceptionId, error, program, context);
1191             return;
1192         }
1193
1194         QObject *object = input.getQObject();
1195         if (!object) {
1196             output.setUndefined();
1197         } else {
1198             int subIdx = instr->fetchAndSubscribe.subscription;
1199             QDeclarativeCompiledBindingsPrivate::Subscription *sub = 0;
1200             if (subIdx != -1) {
1201                 sub = (subscriptions + subIdx);
1202                 sub->target = q;
1203                 sub->targetMethod = methodCount + subIdx; 
1204             }
1205             fastProperties()->accessor(instr->fetchAndSubscribe.function)(object, output.typeDataPtr(), sub);
1206         }
1207     }
1208     QML_END_INSTR(FetchAndSubscribe)
1209
1210     QML_BEGIN_INSTR(LoadId)
1211         registers[instr->load.reg].setQObject(context->idValues[instr->load.index].data());
1212     QML_END_INSTR(LoadId)
1213
1214     QML_BEGIN_INSTR(LoadScope)
1215         registers[instr->load.reg].setQObject(scope);
1216     QML_END_INSTR(LoadScope)
1217
1218     QML_BEGIN_INSTR(LoadRoot)
1219         registers[instr->load.reg].setQObject(context->contextObject);
1220     QML_END_INSTR(LoadRoot)
1221
1222     QML_BEGIN_INSTR(LoadAttached)
1223     {
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);
1228             return;
1229         }
1230
1231         QObject *object = registers[instr->attached.reg].getQObject();
1232         if (!object) {
1233             output.setUndefined();
1234         } else {
1235             QObject *attached = 
1236                 qmlAttachedPropertiesObjectById(instr->attached.id, 
1237                                                 registers[instr->attached.reg].getQObject(), 
1238                                                 true);
1239             Q_ASSERT(attached);
1240             output.setQObject(attached);
1241         }
1242     }
1243     QML_END_INSTR(LoadAttached)
1244
1245     QML_BEGIN_INSTR(ConvertIntToReal)
1246     {
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()));
1251     }
1252     QML_END_INSTR(ConvertIntToReal)
1253
1254     QML_BEGIN_INSTR(ConvertRealToInt)
1255     {
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()));
1260     }
1261     QML_END_INSTR(ConvertRealToInt)
1262
1263     QML_BEGIN_INSTR(Real)
1264         registers[instr->real_value.reg].setqreal(instr->real_value.value);
1265     QML_END_INSTR(Real)
1266
1267     QML_BEGIN_INSTR(Int)
1268         registers[instr->int_value.reg].setint(instr->int_value.value);
1269     QML_END_INSTR(Int)
1270         
1271     QML_BEGIN_INSTR(Bool)
1272         registers[instr->bool_value.reg].setbool(instr->bool_value.value);
1273     QML_END_INSTR(Bool)
1274
1275     QML_BEGIN_INSTR(String)
1276     {
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);
1281     }
1282     QML_END_INSTR(String)
1283
1284     QML_BEGIN_INSTR(AddReal)
1285     {
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());
1291     }
1292     QML_END_INSTR(AddReal)
1293
1294     QML_BEGIN_INSTR(AddInt)
1295     {
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());
1301     }
1302     QML_END_INSTR(AddInt)
1303         
1304     QML_BEGIN_INSTR(AddString)
1305     {
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(); }
1310         else {
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"));
1317             else
1318                 new (output.getstringptr()) 
1319                     QString(*registers[instr->binaryop.src1].getstringptr() + 
1320                             *registers[instr->binaryop.src2].getstringptr());
1321             output.settype(QMetaType::QString);
1322         }
1323     }
1324     QML_END_INSTR(AddString)
1325
1326     QML_BEGIN_INSTR(MinusReal)
1327     {
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());
1333     }
1334     QML_END_INSTR(MinusReal)
1335
1336     QML_BEGIN_INSTR(MinusInt)
1337     {
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());
1343     }
1344     QML_END_INSTR(MinusInt)
1345
1346     QML_BEGIN_INSTR(CompareReal)
1347     {
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());
1353     }
1354     QML_END_INSTR(CompareReal)
1355
1356     QML_BEGIN_INSTR(CompareString)
1357     {
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());
1363     }
1364     QML_END_INSTR(CompareString)
1365
1366     QML_BEGIN_INSTR(NotCompareReal)
1367     {
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());
1373     }
1374     QML_END_INSTR(NotCompareReal)
1375
1376     QML_BEGIN_INSTR(NotCompareString)
1377     {
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());
1383     }
1384     QML_END_INSTR(NotCompareString)
1385
1386     QML_BEGIN_INSTR(GreaterThanReal)
1387     {
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());
1393     }
1394     QML_END_INSTR(GreaterThanReal)
1395
1396     QML_BEGIN_INSTR(MaxReal)
1397     {
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()));
1403     }
1404     QML_END_INSTR(MaxReal)
1405
1406     QML_BEGIN_INSTR(MinReal)
1407     {
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()));
1413     }
1414     QML_END_INSTR(MinReal)
1415
1416     QML_BEGIN_INSTR(NewString)
1417     {
1418         Register &output = registers[instr->construct.reg];
1419         new (output.getstringptr()) QString;
1420         output.settype(QMetaType::QString);
1421     }
1422     QML_END_INSTR(NewString)
1423
1424     QML_BEGIN_INSTR(NewUrl)
1425     {
1426         Register &output = registers[instr->construct.reg];
1427         new (output.geturlptr()) QUrl;
1428         output.settype(QMetaType::QUrl);
1429     }
1430     QML_END_INSTR(NewUrl)
1431
1432     QML_BEGIN_INSTR(CleanupString)
1433         registers[instr->cleanup.reg].getstringptr()->~QString();
1434 #ifdef REGISTER_CLEANUP_DEBUG
1435         registers[instr->cleanup.reg].setUndefined();
1436 #endif
1437     QML_END_INSTR(CleanupString)
1438
1439     QML_BEGIN_INSTR(CleanupUrl)
1440         registers[instr->cleanup.reg].geturlptr()->~QUrl();
1441 #ifdef REGISTER_CLEANUP_DEBUG
1442         registers[instr->cleanup.reg].setUndefined();
1443 #endif
1444     QML_END_INSTR(CleanupUrl)
1445
1446     QML_BEGIN_INSTR(Fetch)
1447     {
1448         const Register &input = registers[instr->fetch.objectReg];
1449         Register &output = registers[instr->fetch.output];
1450
1451         if (input.isUndefined()) {
1452             throwException(instr->fetch.exceptionId, error, program, context);
1453             return;
1454         }
1455
1456         QObject *object = input.getQObject();
1457         if (!object) {
1458             output.setUndefined();
1459         } else {
1460             void *argv[] = { output.typeDataPtr(), 0 };
1461             QMetaObject::metacall(object, QMetaObject::ReadProperty, instr->fetch.index, argv);
1462         }
1463     }
1464     QML_END_INSTR(Fetch)
1465
1466     QML_BEGIN_INSTR(Store)
1467     {
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"));
1472             return;
1473         }
1474
1475         int status = -1;
1476         void *argv[] = { data.typeDataPtr(), 0, &status, &storeFlags };
1477         QMetaObject::metacall(output, QMetaObject::WriteProperty, 
1478                               instr->store.index, argv);
1479     }
1480     QML_END_INSTR(Store)
1481
1482     QML_BEGIN_INSTR(Copy)
1483         registers[instr->copy.reg] = registers[instr->copy.src];
1484     QML_END_INSTR(Copy)
1485
1486     QML_BEGIN_INSTR(Skip)
1487         if (instr->skip.reg == -1 || !registers[instr->skip.reg].getbool()) 
1488             instr += instr->skip.count;
1489     QML_END_INSTR(Skip)
1490
1491     QML_BEGIN_INSTR(Done)
1492         return;
1493     QML_END_INSTR(Done)
1494
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)); 
1499
1500             QString str = QString::fromRawData(strdata, len);
1501
1502             identifiers[instr->initstring.offset] = engine->objectClass->createPersistentIdentifier(str);
1503         }
1504     QML_END_INSTR(InitString)
1505
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, 
1511                     context->parent,
1512                     identifiers[instr->find.name].identifier, 
1513                     instr->common.type == Instr::FindGenericTerminal);
1514     QML_END_INSTR(FindGenericTerminal)
1515
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,
1521                     context->parent,
1522                     identifiers[instr->find.name].identifier,
1523                     instr->common.type == Instr::FindGenericTerminal);
1524     QML_END_INSTR(FindGeneric)
1525
1526     QML_BEGIN_INSTR(FindPropertyTerminal)
1527     {
1528         const Register &object = registers[instr->find.src];
1529         if (object.isUndefined()) {
1530             throwException(instr->find.exceptionId, error, program, context);
1531             return;
1532         }
1533
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);
1538     }
1539     QML_END_INSTR(FindPropertyTerminal)
1540
1541     QML_BEGIN_INSTR(FindProperty)
1542     {
1543         const Register &object = registers[instr->find.src];
1544         if (object.isUndefined()) {
1545             throwException(instr->find.exceptionId, error, program, context);
1546             return;
1547         }
1548
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);
1553     }
1554     QML_END_INSTR(FindProperty)
1555
1556     QML_BEGIN_INSTR(CleanupGeneric)
1557     {
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();
1563 #endif
1564         } else if (type == QMetaType::QString) {
1565             registers[instr->cleanup.reg].getstringptr()->~QString();
1566 #ifdef REGISTER_CLEANUP_DEBUG
1567         registers[instr->cleanup.reg].setUndefined();
1568 #endif
1569         } else if (type == QMetaType::QUrl) {
1570             registers[instr->cleanup.reg].geturlptr()->~QUrl();
1571 #ifdef REGISTER_CLEANUP_DEBUG
1572         registers[instr->cleanup.reg].setUndefined();
1573 #endif
1574         }
1575     }
1576     QML_END_INSTR(CleanupGeneric)
1577
1578     QML_BEGIN_INSTR(ConvertGenericToReal)
1579     {
1580         Register &output = registers[instr->unaryop.output];
1581         Register &input = registers[instr->unaryop.src];
1582         bool ok = true;
1583         output.setqreal(toReal(&input, input.gettype(), &ok));
1584         if (!ok) output.setUndefined();
1585     }
1586     QML_END_INSTR(ConvertGenericToReal)
1587
1588     QML_BEGIN_INSTR(ConvertGenericToBool)
1589     {
1590         Register &output = registers[instr->unaryop.output];
1591         Register &input = registers[instr->unaryop.src];
1592         bool ok = true;
1593         output.setbool(toBool(&input, input.gettype(), &ok));
1594         if (!ok) output.setUndefined();
1595     }
1596     QML_END_INSTR(ConvertGenericToBool)
1597
1598     QML_BEGIN_INSTR(ConvertGenericToString)
1599     {
1600         Register &output = registers[instr->unaryop.output];
1601         Register &input = registers[instr->unaryop.src];
1602         bool ok = true;
1603         QString str = toString(&input, input.gettype(), &ok);
1604         if (ok) { new (output.getstringptr()) QString(str); output.settype(QMetaType::QString); }
1605         else { output.setUndefined(); }
1606     }
1607     QML_END_INSTR(ConvertGenericToString)
1608
1609     QML_BEGIN_INSTR(ConvertGenericToUrl)
1610     {
1611         Register &output = registers[instr->unaryop.output];
1612         Register &input = registers[instr->unaryop.src];
1613         bool ok = true;
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(); }
1617     }
1618     QML_END_INSTR(ConvertGenericToUrl)
1619
1620 #ifdef QML_THREADED_INTERPRETER
1621     // nothing to do
1622 #else
1623     default:
1624         qFatal("EEK");
1625         break;
1626     } // switch
1627
1628     ++instr;
1629     } // while
1630 #endif
1631 }
1632
1633 void QDeclarativeBindingCompiler::dump(const QByteArray &programData)
1634 {
1635     const Program *program = (const Program *)programData.constData();
1636
1637     qWarning() << "Program.bindings:" << program->bindings;
1638     qWarning() << "Program.dataLength:" << program->dataLength;
1639     qWarning() << "Program.subscriptions:" << program->subscriptions;
1640     qWarning() << "Program.indentifiers:" << program->identifiers;
1641
1642     int count = program->instructionCount;
1643     const Instr *instr = program->instructions();
1644
1645     while (count--) {
1646
1647         dumpInstruction(instr);
1648         ++instr;
1649     }
1650 }
1651
1652 /*!
1653 Clear the state associated with attempting to compile a specific binding.
1654 This does not clear the global "committed binding" states.
1655 */
1656 void QDeclarativeBindingCompilerPrivate::resetInstanceState()
1657 {
1658     registers = 0;
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;
1666     bytecode.clear();
1667 }
1668
1669 /*!
1670 Mark the last compile as successful, and add it to the "committed data"
1671 section.
1672
1673 Returns the index for the committed binding.
1674 */
1675 int QDeclarativeBindingCompilerPrivate::commitCompile()
1676 {
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;
1685     return rv;
1686 }
1687
1688 bool QDeclarativeBindingCompilerPrivate::compile(QDeclarativeJS::AST::Node *node)
1689 {
1690     resetInstanceState();
1691
1692     if (destination->type == -1)
1693         return false;
1694
1695     if (bindingsDump()) {
1696         QDeclarativeJS::AST::ExpressionNode *n = node->expressionCast();
1697         if (n) {
1698             Instr id;
1699             id.common.type = Instr::BindingId;
1700             id.id.column = n->firstSourceLocation().startColumn;
1701             id.id.line = n->firstSourceLocation().startLine;
1702             bytecode << id;
1703         }
1704     }
1705
1706     Result type;
1707
1708     if (!parseExpression(node, type)) 
1709         return false;
1710
1711     if (subscriptionSet.count() > 0xFFFF ||
1712             registeredStrings.count() > 0xFFFF)
1713         return false;
1714
1715     if (type.unknownType) {
1716         if (!qmlExperimental())
1717             return false;
1718
1719         if (destination->type != QMetaType::QReal &&
1720             destination->type != QVariant::String &&
1721             destination->type != QMetaType::Bool &&
1722             destination->type != QVariant::Url)
1723             return false;
1724
1725         int convertReg = acquireReg();
1726         if (convertReg == -1)
1727             return false;
1728
1729         if (destination->type == QMetaType::QReal) {
1730             Instr convert;
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) {
1736             Instr convert;
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) {
1742             Instr convert;
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) {
1748             Instr convert;
1749             convert.common.type = Instr::ConvertGenericToUrl;
1750             convert.unaryop.output = convertReg;
1751             convert.unaryop.src = type.reg;
1752             bytecode << convert;
1753         }
1754
1755         Instr cleanup;
1756         cleanup.common.type = Instr::CleanupGeneric;
1757         cleanup.cleanup.reg = type.reg;
1758         bytecode << cleanup;
1759
1760         Instr instr;
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());
1766         bytecode << instr;
1767
1768         if (destination->type == QVariant::String) {
1769             Instr cleanup;
1770             cleanup.common.type = Instr::CleanupString;
1771             cleanup.cleanup.reg = convertReg;
1772             bytecode << cleanup;
1773         } else if (destination->type == QVariant::Url) {
1774             Instr cleanup;
1775             cleanup.common.type = Instr::CleanupUrl;
1776             cleanup.cleanup.reg = convertReg;
1777             bytecode << cleanup;
1778         }
1779
1780         releaseReg(convertReg);
1781
1782         Instr done;
1783         done.common.type = Instr::Done;
1784         bytecode << done;
1785
1786     } else {
1787         // Can we store the final value?
1788         if (type.type == QVariant::Int &&
1789             destination->type == QMetaType::QReal) {
1790             Instr instr;
1791             instr.common.type = Instr::ConvertIntToReal;
1792             instr.unaryop.output = type.reg;
1793             instr.unaryop.src = type.reg;
1794             bytecode << instr;
1795             type.type = QMetaType::QReal;
1796         } else if (type.type == QMetaType::QReal &&
1797                    destination->type == QVariant::Int) {
1798             Instr instr;
1799             instr.common.type = Instr::ConvertRealToInt;
1800             instr.unaryop.output = type.reg;
1801             instr.unaryop.src = type.reg;
1802             bytecode << instr;
1803             type.type = QVariant::Int;
1804         } else if (type.type == destination->type) {
1805         } else {
1806             const QMetaObject *from = type.metaObject;
1807             const QMetaObject *to = engine->rawMetaObjectForType(destination->type);
1808
1809             if (QDeclarativePropertyPrivate::canConvert(from, to))
1810                 type.type = destination->type;
1811         }
1812
1813         if (type.type == destination->type) {
1814             Instr instr;
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());
1820             bytecode << instr;
1821
1822             releaseReg(type.reg);
1823
1824             Instr done;
1825             done.common.type = Instr::Done;
1826             bytecode << done;
1827         } else {
1828             return false;
1829         }
1830     }
1831
1832     return true;
1833 }
1834
1835 bool QDeclarativeBindingCompilerPrivate::parseExpression(QDeclarativeJS::AST::Node *node, Result &type)
1836 {
1837     while (node->kind == AST::Node::Kind_NestedExpression)
1838         node = static_cast<AST::NestedExpression *>(node)->expression;
1839
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;
1852     } else {
1853         return false;
1854     }
1855     return true;
1856 }
1857
1858 bool QDeclarativeBindingCompilerPrivate::tryName(QDeclarativeJS::AST::Node *node)
1859 {
1860     return node->kind == AST::Node::Kind_IdentifierExpression ||
1861            node->kind == AST::Node::Kind_FieldMemberExpression;
1862 }
1863
1864 bool QDeclarativeBindingCompilerPrivate::parseName(AST::Node *node, Result &type)
1865 {
1866     QStringList nameParts;
1867     QList<AST::ExpressionNode *> nameNodes;
1868     if (!buildName(nameParts, node, &nameNodes))
1869         return false;
1870
1871     int reg = acquireReg();
1872     if (reg == -1)
1873         return false;
1874     type.reg = reg;
1875
1876     QDeclarativeParser::Object *absType = 0;
1877
1878     QStringList subscribeName;
1879
1880     bool wasAttachedObject = false;
1881
1882     for (int ii = 0; ii < nameParts.count(); ++ii) {
1883         const QString &name = nameParts.at(ii);
1884
1885         // We don't handle signal properties or attached properties
1886         if (name.length() > 2 && name.startsWith(QLatin1String("on")) &&
1887             name.at(2).isUpper())
1888             return false;
1889
1890         QDeclarativeType *attachType = 0;
1891         if (name.at(0).isUpper()) {
1892             // Could be an attached property
1893             if (ii == nameParts.count() - 1)
1894                 return false;
1895             if (nameParts.at(ii + 1).at(0).isUpper())
1896                 return false;
1897
1898             QDeclarativeImportedNamespace *ns = 0;
1899             if (!imports.resolveType(name.toUtf8(), &attachType, 0, 0, 0, &ns))
1900                 return false;
1901             if (ns || !attachType || !attachType->attachedPropertiesType())
1902                 return false;
1903
1904             wasAttachedObject = true;
1905         } 
1906
1907         if (ii == 0) {
1908
1909             if (attachType) {
1910                 Instr instr;
1911                 instr.common.type = Instr::LoadScope;
1912                 instr.load.index = 0;
1913                 instr.load.reg = reg;
1914                 bytecode << instr;
1915
1916                 Instr attach;
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));
1922                 bytecode << attach;
1923
1924                 subscribeName << contextName();
1925                 subscribeName << QLatin1String("$$$ATTACH_") + name;
1926
1927                 absType = 0;
1928                 type.metaObject = attachType->attachedPropertiesType();
1929
1930                 continue;
1931             } else if (ids.contains(name)) {
1932                 QDeclarativeParser::Object *idObject = ids.value(name);
1933                 absType = idObject;
1934                 type.metaObject = absType->metaObject();
1935
1936                 // We check if the id object is the root or 
1937                 // scope object to avoid a subscription
1938                 if (idObject == component) {
1939                     Instr instr;
1940                     instr.common.type = Instr::LoadRoot;
1941                     instr.load.index = 0;
1942                     instr.load.reg = reg;
1943                     bytecode << instr;
1944                 } else if (idObject == context) {
1945                     Instr instr;
1946                     instr.common.type = Instr::LoadScope;
1947                     instr.load.index = 0;
1948                     instr.load.reg = reg;
1949                     bytecode << instr;
1950                 } else {
1951                     Instr instr;
1952                     instr.common.type = Instr::LoadId;
1953                     instr.load.index = idObject->idIndex;
1954                     instr.load.reg = reg;
1955                     bytecode << instr;
1956
1957                     subscribeName << QLatin1String("$$$ID_") + name;
1958
1959                     if (subscription(subscribeName, &type)) {
1960                         Instr sub;
1961                         sub.common.type = Instr::SubscribeId;
1962                         sub.subscribe.offset = subscriptionIndex(subscribeName);
1963                         sub.subscribe.reg = reg;
1964                         sub.subscribe.index = instr.load.index;
1965                         bytecode << sub;
1966                     }
1967                 }
1968
1969             } else {
1970
1971                 QByteArray utf8Name = name.toUtf8();
1972                 const char *cname = utf8Name.constData();
1973
1974                 int d0Idx = (context == component)?-1:context->metaObject()->indexOfProperty(cname);
1975                 int d1Idx = -1;
1976                 if (d0Idx == -1)
1977                     d1Idx = component->metaObject()->indexOfProperty(cname);
1978
1979                 if (d0Idx != -1) {
1980                     Instr instr;
1981                     instr.common.type = Instr::LoadScope;
1982                     instr.load.index = 0;
1983                     instr.load.reg = reg;
1984                     bytecode << instr;
1985
1986                     subscribeName << contextName();
1987                     subscribeName << name;
1988
1989                     if (!fetch(type, context->metaObject(), reg, d0Idx, subscribeName, nameNodes.at(ii)))
1990                         return false;
1991                 } else if(d1Idx != -1) {
1992                     Instr instr;
1993                     instr.common.type = Instr::LoadRoot;
1994                     instr.load.index = 0;
1995                     instr.load.reg = reg;
1996                     bytecode << instr;
1997
1998                     subscribeName << QLatin1String("$$$ROOT");
1999                     subscribeName << name;
2000
2001                     if (!fetch(type, component->metaObject(), reg, d1Idx, subscribeName, nameNodes.at(ii)))
2002                         return false;
2003                 } else if (qmlExperimental()) {
2004                     Instr find;
2005                     if (nameParts.count() == 1)
2006                         find.common.type = Instr::FindGenericTerminal;
2007                     else
2008                         find.common.type = Instr::FindGeneric;
2009
2010                     find.find.reg = reg;
2011                     find.find.src = -1;
2012                     find.find.name = registerString(name);
2013                     find.find.exceptionId = exceptionId(nameNodes.at(ii));
2014
2015                     subscribeName << QString(QLatin1String("$$$Generic_") + name);
2016                     if (subscription(subscribeName, &type)) 
2017                         find.find.subscribeIndex = subscriptionIndex(subscribeName);
2018                     else
2019                         find.find.subscribeIndex = -1;
2020
2021                     bytecode << find;
2022                     type.unknownType = true;
2023                 } 
2024
2025                 if (!type.unknownType && type.type == -1)
2026                     return false; // Couldn't fetch that type
2027             } 
2028
2029         } else {
2030
2031             if (attachType) {
2032                 Instr attach;
2033                 attach.common.type = Instr::LoadAttached;
2034                 attach.attached.output = reg;
2035                 attach.attached.reg = reg;
2036                 attach.attached.id = attachType->attachedPropertiesId();
2037                 bytecode << attach;
2038
2039                 absType = 0;
2040                 type.metaObject = attachType->attachedPropertiesType();
2041
2042                 subscribeName << QLatin1String("$$$ATTACH_") + name;
2043                 continue;
2044             }
2045
2046             const QMetaObject *mo = 0;
2047             if (absType)
2048                 mo = absType->metaObject();
2049             else if (type.metaObject)
2050                 mo = type.metaObject;
2051
2052             QByteArray utf8Name = name.toUtf8();
2053             const char *cname = utf8Name.constData();
2054             int idx = mo?mo->indexOfProperty(cname):-1;
2055             if (absType && idx == -1)
2056                 return false;
2057
2058             subscribeName << name;
2059
2060             if (absType || (wasAttachedObject && idx != -1) || (mo && mo->property(idx).isFinal())) {
2061                 absType = 0; 
2062                 if (!fetch(type, mo, reg, idx, subscribeName, nameNodes.at(ii)))
2063                     return false;
2064             } else {
2065
2066                 Instr prop;
2067                 if (ii == nameParts.count() -1 ) 
2068                     prop.common.type = Instr::FindPropertyTerminal;
2069                 else
2070                     prop.common.type = Instr::FindProperty;
2071
2072                 prop.find.reg = reg;
2073                 prop.find.src = reg;
2074                 prop.find.name = registerString(name);
2075                 prop.find.exceptionId = exceptionId(nameNodes.at(ii));
2076
2077                 if (subscription(subscribeName, &type))
2078                     prop.find.subscribeIndex = subscriptionIndex(subscribeName);
2079                 else
2080                     prop.find.subscribeIndex = -1;
2081
2082                 type.unknownType = true;
2083                 type.metaObject = 0;
2084                 type.type = -1;
2085                 type.reg = reg;
2086                 bytecode << prop;
2087             }
2088         }
2089
2090         wasAttachedObject = false;
2091     }
2092
2093     return true;
2094 }
2095
2096 bool QDeclarativeBindingCompilerPrivate::tryArith(QDeclarativeJS::AST::Node *node)
2097 {
2098     if (node->kind != AST::Node::Kind_BinaryExpression)
2099         return false;
2100
2101     AST::BinaryExpression *expression = static_cast<AST::BinaryExpression *>(node);
2102     if (expression->op == QSOperator::Add ||
2103         expression->op == QSOperator::Sub)
2104         return true;
2105     else
2106         return false;
2107 }
2108
2109 bool QDeclarativeBindingCompilerPrivate::parseArith(QDeclarativeJS::AST::Node *node, Result &type)
2110 {
2111     AST::BinaryExpression *expression = static_cast<AST::BinaryExpression *>(node);
2112
2113     type.reg = acquireReg();
2114     if (type.reg == -1)
2115         return false;
2116
2117     Result lhs;
2118     Result rhs;
2119
2120     if (!parseExpression(expression->left, lhs)) return false;
2121     if (!parseExpression(expression->right, rhs)) return false;
2122
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);
2132     else
2133         return false;
2134 }
2135
2136 bool QDeclarativeBindingCompilerPrivate::numberArith(Result &type, const Result &lhs, const Result &rhs, QSOperator::Op op)
2137 {
2138     bool nativeReal = rhs.type == QMetaType::QReal ||
2139                       lhs.type == QMetaType::QReal ||
2140                       lhs.unknownType ||
2141                       rhs.unknownType;
2142
2143     if (nativeReal && lhs.type == QMetaType::Int) {
2144         Instr convert;
2145         convert.common.type = Instr::ConvertIntToReal;
2146         convert.unaryop.output = lhs.reg;
2147         convert.unaryop.src = lhs.reg;
2148         bytecode << convert;
2149     }
2150
2151     if (nativeReal && rhs.type == QMetaType::Int) {
2152         Instr convert;
2153         convert.common.type = Instr::ConvertIntToReal;
2154         convert.unaryop.output = rhs.reg;
2155         convert.unaryop.src = rhs.reg;
2156         bytecode << convert;
2157     }
2158
2159     int lhsTmp = -1;
2160     int rhsTmp = -1;
2161
2162     if (lhs.unknownType) {
2163         if (!qmlExperimental())
2164             return false;
2165
2166         lhsTmp = acquireReg();
2167         if (lhsTmp == -1)
2168             return false;
2169
2170         Instr conv;
2171         conv.common.type = Instr::ConvertGenericToReal;
2172         conv.unaryop.output = lhsTmp;
2173         conv.unaryop.src = lhs.reg;
2174         bytecode << conv;
2175     }
2176
2177     if (rhs.unknownType) {
2178         if (!qmlExperimental())
2179             return false;
2180
2181         rhsTmp = acquireReg();
2182         if (rhsTmp == -1)
2183             return false;
2184
2185         Instr conv;
2186         conv.common.type = Instr::ConvertGenericToReal;
2187         conv.unaryop.output = rhsTmp;
2188         conv.unaryop.src = rhs.reg;
2189         bytecode << conv;
2190     }
2191
2192     Instr arith;
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;
2197     } else {
2198         qFatal("Unsupported arithmetic operator");
2199     }
2200
2201     arith.binaryop.output = type.reg;
2202     arith.binaryop.src1 = (lhsTmp == -1)?lhs.reg:lhsTmp;
2203     arith.binaryop.src2 = (rhsTmp == -1)?rhs.reg:rhsTmp;
2204     bytecode << arith;
2205
2206     type.metaObject = 0;
2207     type.type = nativeReal?QMetaType::QReal:QMetaType::Int;
2208     type.subscriptionSet.unite(lhs.subscriptionSet);
2209     type.subscriptionSet.unite(rhs.subscriptionSet);
2210
2211     if (lhsTmp != -1) releaseReg(lhsTmp);
2212     if (rhsTmp != -1) releaseReg(rhsTmp);
2213     releaseReg(lhs.reg);
2214     releaseReg(rhs.reg);
2215
2216     return true;
2217 }
2218
2219 bool QDeclarativeBindingCompilerPrivate::stringArith(Result &type, const Result &lhs, const Result &rhs, QSOperator::Op op)
2220 {
2221     if (op != QSOperator::Add)
2222         return false;
2223
2224     int lhsTmp = -1;
2225     int rhsTmp = -1;
2226
2227     if (lhs.unknownType) {
2228         if (!qmlExperimental())
2229             return false;
2230
2231         lhsTmp = acquireReg(Instr::CleanupString);
2232         if (lhsTmp == -1)
2233             return false;
2234
2235         Instr convert;
2236         convert.common.type = Instr::ConvertGenericToString;
2237         convert.unaryop.output = lhsTmp;
2238         convert.unaryop.src = lhs.reg;
2239         bytecode << convert;
2240     }
2241
2242     if (rhs.unknownType) {
2243         if (!qmlExperimental())
2244             return false;
2245
2246         rhsTmp = acquireReg(Instr::CleanupString);
2247         if (rhsTmp == -1)
2248             return false;
2249
2250         Instr convert;
2251         convert.common.type = Instr::ConvertGenericToString;
2252         convert.unaryop.output = rhsTmp;
2253         convert.unaryop.src = rhs.reg;
2254         bytecode << convert;
2255     }
2256
2257     type.reg = acquireReg(Instr::CleanupString);
2258     if (type.reg == -1)
2259         return false;
2260
2261     type.type = QMetaType::QString;
2262
2263     Instr add;
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;
2268     bytecode << add;
2269
2270     if (lhsTmp != -1) releaseReg(lhsTmp);
2271     if (rhsTmp != -1) releaseReg(rhsTmp);
2272     releaseReg(lhs.reg);
2273     releaseReg(rhs.reg);
2274
2275     return true;
2276 }
2277
2278 bool QDeclarativeBindingCompilerPrivate::tryLogic(QDeclarativeJS::AST::Node *node)
2279 {
2280     if (node->kind != AST::Node::Kind_BinaryExpression)
2281         return false;
2282
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)
2287         return true;
2288     else
2289         return false;
2290 }
2291
2292 bool QDeclarativeBindingCompilerPrivate::parseLogic(QDeclarativeJS::AST::Node *node, Result &type)
2293 {
2294     AST::BinaryExpression *expression = static_cast<AST::BinaryExpression *>(node);
2295
2296     Result lhs;
2297     Result rhs;
2298
2299     if (!parseExpression(expression->left, lhs)) return false;
2300     if (!parseExpression(expression->right, rhs)) return false;
2301
2302     type.reg = acquireReg();
2303     if (type.reg == -1)
2304         return false;
2305
2306     type.metaObject = 0;
2307     type.type = QVariant::Bool;
2308
2309     if (lhs.type == QMetaType::QReal && rhs.type == QMetaType::QReal) {
2310
2311         Instr op;
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;
2318         else
2319             return false;
2320         op.binaryop.output = type.reg;
2321         op.binaryop.src1 = lhs.reg;
2322         op.binaryop.src2 = rhs.reg;
2323         bytecode << op;
2324
2325
2326     } else if (lhs.type == QMetaType::QString && rhs.type == QMetaType::QString) {
2327
2328         Instr op;
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;
2333         else
2334             return false;
2335         op.binaryop.output = type.reg;
2336         op.binaryop.src1 = lhs.reg;
2337         op.binaryop.src2 = rhs.reg;
2338         bytecode << op;
2339
2340     } else {
2341         return false;
2342     }
2343
2344     releaseReg(lhs.reg);
2345     releaseReg(rhs.reg);
2346
2347     return true;
2348 }
2349
2350 bool QDeclarativeBindingCompilerPrivate::tryConditional(QDeclarativeJS::AST::Node *node)
2351 {
2352     return (node->kind == AST::Node::Kind_ConditionalExpression);
2353 }
2354
2355 bool QDeclarativeBindingCompilerPrivate::parseConditional(QDeclarativeJS::AST::Node *node, Result &type)
2356 {
2357     AST::ConditionalExpression *expression = static_cast<AST::ConditionalExpression *>(node);
2358
2359     AST::Node *test = expression->expression;
2360     if (test->kind == AST::Node::Kind_NestedExpression)
2361         test = static_cast<AST::NestedExpression*>(test)->expression;
2362
2363     Result etype;
2364     if (!parseExpression(test, etype)) return false;
2365
2366     if (etype.type != QVariant::Bool) 
2367         return false;
2368
2369     Instr skip;
2370     skip.common.type = Instr::Skip;
2371     skip.skip.reg = etype.reg;
2372     skip.skip.count = 0;
2373     int skipIdx = bytecode.count();
2374     bytecode << skip;
2375
2376     // Release to allow reuse of reg
2377     releaseReg(etype.reg);
2378
2379     QSet<QString> preSubSet = subscriptionSet;
2380
2381     // int preConditionalSubscriptions = subscriptionSet.count();
2382
2383     Result ok;
2384     if (!parseExpression(expression->ok, ok)) return false;
2385     if (ok.unknownType) return false;
2386
2387     int skipIdx2 = bytecode.count();
2388     skip.skip.reg = -1;
2389     bytecode << skip;
2390
2391     // Release to allow reuse of reg
2392     releaseReg(ok.reg);
2393     bytecode[skipIdx].skip.count = bytecode.count() - skipIdx - 1;
2394
2395     subscriptionSet = preSubSet;
2396
2397     Result ko;
2398     if (!parseExpression(expression->ko, ko)) return false;
2399     if (ko.unknownType) return false;
2400
2401     // Release to allow reuse of reg
2402     releaseReg(ko.reg);
2403     bytecode[skipIdx2].skip.count = bytecode.count() - skipIdx2 - 1;
2404
2405     if (ok != ko)
2406         return false; // Must be same type and in same register
2407
2408     subscriptionSet = preSubSet;
2409
2410     if (!subscriptionNeutral(subscriptionSet, ok.subscriptionSet, ko.subscriptionSet))
2411         return false; // Conditionals cannot introduce new subscriptions
2412
2413     type = ok;
2414
2415     return true;
2416 }
2417
2418 bool QDeclarativeBindingCompilerPrivate::tryConstant(QDeclarativeJS::AST::Node *node)
2419 {
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;
2424 }
2425
2426 bool QDeclarativeBindingCompilerPrivate::parseConstant(QDeclarativeJS::AST::Node *node, Result &type)
2427 {
2428     type.metaObject = 0;
2429     type.type = -1;
2430     type.reg = acquireReg();
2431     if (type.reg == -1)
2432         return false;
2433
2434     if (node->kind == AST::Node::Kind_TrueLiteral) {
2435         type.type = QVariant::Bool;
2436         Instr instr;
2437         instr.common.type = Instr::Bool;
2438         instr.bool_value.reg = type.reg;
2439         instr.bool_value.value = true;
2440         bytecode << instr;
2441         return true;
2442     } else if (node->kind == AST::Node::Kind_FalseLiteral) {
2443         type.type = QVariant::Bool;
2444         Instr instr;
2445         instr.common.type = Instr::Bool;
2446         instr.bool_value.reg = type.reg;
2447         instr.bool_value.value = false;
2448         bytecode << instr;
2449         return true;
2450     } else if (node->kind == AST::Node::Kind_NumericLiteral) {
2451         qreal value = qreal(static_cast<AST::NumericLiteral *>(node)->value);
2452
2453         if (qreal(float(value)) != value)
2454             return false;
2455
2456         type.type = QMetaType::QReal;
2457         Instr instr;
2458         instr.common.type = Instr::Real;
2459         instr.real_value.reg = type.reg;
2460         instr.real_value.value = float(value);
2461         bytecode << instr;
2462         return true;
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);
2467         return true;
2468     } else {
2469         return false;
2470     }
2471 }
2472
2473 bool QDeclarativeBindingCompilerPrivate::tryMethod(QDeclarativeJS::AST::Node *node)
2474 {
2475     return node->kind == AST::Node::Kind_CallExpression; 
2476 }
2477
2478 bool QDeclarativeBindingCompilerPrivate::parseMethod(QDeclarativeJS::AST::Node *node, Result &result)
2479 {
2480     AST::CallExpression *expr = static_cast<AST::CallExpression *>(node);
2481
2482     QStringList name;
2483     if (!buildName(name, expr->base))
2484         return false;
2485
2486     if (name.count() != 2 || name.at(0) != QLatin1String("Math"))
2487         return false;
2488
2489     QString method = name.at(1);
2490
2491     AST::ArgumentList *args = expr->arguments;
2492     if (!args) return false;
2493     AST::ExpressionNode *arg0 = args->expression;
2494     args = args->next;
2495     if (!args) return false;
2496     AST::ExpressionNode *arg1 = args->expression;
2497     if (args->next != 0) return false;
2498     if (!arg0 || !arg1) return false;
2499
2500     Result r0;
2501     if (!parseExpression(arg0, r0)) return false;
2502     Result r1;
2503     if (!parseExpression(arg1, r1)) return false;
2504
2505     if (r0.type != QMetaType::QReal || r1.type != QMetaType::QReal)
2506         return false;
2507
2508     Instr op;
2509     if (method == QLatin1String("max")) {
2510         op.common.type = Instr::MaxReal;
2511     } else if (method == QLatin1String("min")) {
2512         op.common.type = Instr::MinReal;
2513     } else {
2514         return false;
2515     }
2516     // We release early to reuse registers
2517     releaseReg(r0.reg);
2518     releaseReg(r1.reg);
2519
2520     op.binaryop.output = acquireReg();
2521     if (op.binaryop.output == -1)
2522         return false;
2523
2524     op.binaryop.src1 = r0.reg;
2525     op.binaryop.src2 = r1.reg;
2526     bytecode << op;
2527
2528     result.type = QMetaType::QReal;
2529     result.reg = op.binaryop.output;
2530
2531     return true;
2532 }
2533
2534 bool QDeclarativeBindingCompilerPrivate::buildName(QStringList &name,
2535                                        QDeclarativeJS::AST::Node *node,
2536                                        QList<QDeclarativeJS::AST::ExpressionNode *> *nodes)
2537 {
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);
2544
2545         if (!buildName(name, expr->base, nodes))
2546             return false;
2547
2548         name << expr->name->asString();
2549         if (nodes) *nodes << expr;
2550     } else {
2551         return false;
2552     }
2553
2554     return true;
2555 }
2556
2557 bool QDeclarativeBindingCompilerPrivate::fetch(Result &rv, const QMetaObject *mo, int reg, 
2558                                                int idx, const QStringList &subName, 
2559                                                QDeclarativeJS::AST::ExpressionNode *node)
2560 {
2561     QMetaProperty prop = mo->property(idx);
2562     rv.metaObject = 0;
2563     rv.type = 0;
2564
2565     //XXX binding optimizer doesn't handle properties with a revision
2566     if (prop.revision() > 0)
2567         return false;
2568
2569     int fastFetchIndex = fastProperties()->accessorIndexForProperty(mo, idx);
2570
2571     Instr fetch;
2572
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);
2580     } else {
2581         if (subscription(subName, &rv) && prop.hasNotifySignal() && prop.notifySignalIndex() != -1) {
2582             Instr sub;
2583             sub.common.type = Instr::Subscribe;
2584             sub.subscribe.offset = subscriptionIndex(subName);
2585             sub.subscribe.reg = reg;
2586             sub.subscribe.index = prop.notifySignalIndex();
2587             bytecode << sub;
2588         }
2589
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);
2595     }
2596
2597     rv.type = prop.userType();
2598     rv.metaObject = engine->metaObjectForType(rv.type);
2599     rv.reg = reg;
2600
2601     if (rv.type == QMetaType::QString) {
2602         int tmp = acquireReg();
2603         if (tmp == -1)
2604             return false;
2605         Instr copy;
2606         copy.common.type = Instr::Copy;
2607         copy.copy.reg = tmp;
2608         copy.copy.src = reg;
2609         bytecode << copy;
2610         releaseReg(tmp);
2611         fetch.fetch.objectReg = tmp;
2612
2613         Instr setup;
2614         setup.common.type = Instr::NewString;
2615         setup.construct.reg = reg;
2616         bytecode << setup;
2617         registerCleanup(reg, Instr::CleanupString);
2618     }
2619
2620     bytecode << fetch;
2621
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) {
2628         rv.metaObject = 0;
2629         rv.type = 0;
2630         return false; // Unsupported type (string not supported yet);
2631     }
2632
2633     return true;
2634 }
2635
2636 void QDeclarativeBindingCompilerPrivate::registerCleanup(int reg, int cleanup, int cleanupType)
2637 {
2638     registerCleanups.insert(reg, qMakePair(cleanup, cleanupType));
2639 }
2640
2641 int QDeclarativeBindingCompilerPrivate::acquireReg(int cleanup, int cleanupType)
2642 {
2643     for (int ii = 0; ii < 32; ++ii) {
2644         if (!(registers & (1 << ii))) {
2645             registers |= (1 << ii);
2646
2647             if (cleanup != Instr::Noop)
2648                 registerCleanup(ii, cleanup, cleanupType);
2649
2650             return ii;
2651         }
2652     }
2653     return -1;
2654 }
2655
2656 void QDeclarativeBindingCompilerPrivate::releaseReg(int reg)
2657 {
2658     Q_ASSERT(reg >= 0 && reg <= 31);
2659
2660     if (registerCleanups.contains(reg)) {
2661         QPair<int, int> c = registerCleanups[reg];
2662         registerCleanups.remove(reg);
2663         Instr cleanup;
2664         cleanup.common.type = (quint8)c.first;
2665         cleanup.cleanup.reg = reg;
2666         bytecode << cleanup;
2667     }
2668
2669     quint32 mask = 1 << reg;
2670     registers &= ~mask;
2671 }
2672
2673 // Returns a reg
2674 int QDeclarativeBindingCompilerPrivate::registerLiteralString(const QString &str)
2675 {
2676     QByteArray strdata((const char *)str.constData(), str.length() * sizeof(QChar));
2677     int offset = data.count();
2678     data += strdata;
2679
2680     int reg = acquireReg(Instr::CleanupString);
2681     if (reg == -1)
2682         return false;
2683
2684     Instr string;
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();
2689     bytecode << string;
2690
2691     return reg;
2692 }
2693
2694 // Returns an identifier offset
2695 int QDeclarativeBindingCompilerPrivate::registerString(const QString &string)
2696 {
2697     Q_ASSERT(!string.isEmpty());
2698
2699     QHash<QString, QPair<int, int> >::ConstIterator iter = registeredStrings.find(string);
2700
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();
2707         data += strdata;
2708
2709         iter = registeredStrings.insert(string, qMakePair(registeredStrings.count(), rv));
2710     } 
2711
2712     Instr reg;
2713     reg.common.type = Instr::InitString;
2714     reg.initstring.offset = iter->first;
2715     reg.initstring.dataIdx = iter->second;
2716     bytecode << reg;
2717     return reg.initstring.offset;
2718 }
2719
2720 bool QDeclarativeBindingCompilerPrivate::subscription(const QStringList &sub, Result *result)
2721 {
2722     QString str = sub.join(QLatin1String("."));
2723     result->subscriptionSet.insert(str);
2724
2725     if (subscriptionSet.contains(str)) {
2726         return false;
2727     } else {
2728         subscriptionSet.insert(str);
2729         return true;
2730     }
2731 }
2732
2733 int QDeclarativeBindingCompilerPrivate::subscriptionIndex(const QStringList &sub)
2734 {
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);
2740     return *iter;
2741 }
2742
2743 /*
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.
2746 */ 
2747 bool QDeclarativeBindingCompilerPrivate::subscriptionNeutral(const QSet<QString> &base, 
2748                                              const QSet<QString> &lhs, 
2749                                              const QSet<QString> &rhs)
2750 {
2751     QSet<QString> difflhs = lhs;
2752     difflhs.subtract(rhs);
2753     QSet<QString> diffrhs = rhs;
2754     diffrhs.subtract(lhs);
2755
2756     difflhs.unite(diffrhs);
2757     difflhs.subtract(base);
2758
2759     return difflhs.isEmpty();
2760 }
2761
2762 quint8 QDeclarativeBindingCompilerPrivate::exceptionId(QDeclarativeJS::AST::ExpressionNode *n)
2763 {
2764     quint8 rv = 0xFF;
2765     if (n && exceptions.count() < 0xFF) {
2766         rv = (quint8)exceptions.count();
2767         QDeclarativeJS::AST::SourceLocation l = n->firstSourceLocation();
2768         quint64 e = l.startLine;
2769         e <<= 32;
2770         e |= l.startColumn;
2771         exceptions.append(e);
2772     }
2773     return rv;
2774 }
2775
2776 QDeclarativeBindingCompiler::QDeclarativeBindingCompiler()
2777 : d(new QDeclarativeBindingCompilerPrivate)
2778 {
2779 }
2780
2781 QDeclarativeBindingCompiler::~QDeclarativeBindingCompiler()
2782 {
2783     delete d; d = 0;
2784 }
2785
2786 /* 
2787 Returns true if any bindings were compiled.
2788 */
2789 bool QDeclarativeBindingCompiler::isValid() const
2790 {
2791     return !d->committed.bytecode.isEmpty();
2792 }
2793
2794 /* 
2795 -1 on failure, otherwise the binding index to use.
2796 */
2797 int QDeclarativeBindingCompiler::compile(const Expression &expression, QDeclarativeEnginePrivate *engine)
2798 {
2799     if (!expression.expression.asAST()) return false;
2800
2801     if (!qmlExperimental() && expression.property->isValueTypeSubProperty)
2802         return -1;
2803
2804     if (qmlDisableOptimizer())
2805         return -1;
2806
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;
2812     d->engine = engine;
2813
2814     if (d->compile(expression.expression.asAST())) {
2815         return d->commitCompile();
2816     } else {
2817         return -1;
2818     }
2819 }
2820
2821
2822 QByteArray QDeclarativeBindingCompilerPrivate::buildSignalTable() const
2823 {
2824     QHash<int, QList<int> > table;
2825
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);
2830     }
2831
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));
2840     }
2841     header << data;
2842
2843     return QByteArray((const char *)header.constData(), header.count() * sizeof(quint32));
2844 }
2845
2846 QByteArray QDeclarativeBindingCompilerPrivate::buildExceptionData() const
2847 {
2848     QByteArray rv;
2849     rv.resize(committed.exceptions.count() * sizeof(quint64));
2850     ::memcpy(rv.data(), committed.exceptions.constData(), rv.size());
2851     return rv;
2852 }
2853
2854 /* 
2855 Returns the compiled program.
2856 */
2857 QByteArray QDeclarativeBindingCompiler::program() const
2858 {
2859     QByteArray programData;
2860
2861     if (isValid()) {
2862         Program prog;
2863         prog.bindings = d->committed.count();
2864
2865         QVector<Instr> bytecode;
2866         Instr skip;
2867         skip.common.type = Instr::Skip;
2868         skip.skip.reg = -1;
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);
2872             bytecode << skip;
2873         }
2874         bytecode << d->committed.bytecode;
2875
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();
2883
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;
2891
2892         programData.resize(size);
2893         memcpy(programData.data(), &prog, sizeof(Program));
2894         if (prog.dataLength)
2895             memcpy((char *)((Program *)programData.data())->data(), data.constData(), 
2896                    data.size());
2897         memcpy((char *)((Program *)programData.data())->instructions(), bytecode.constData(), 
2898                bytecode.count() * sizeof(Instr));
2899     } 
2900
2901     return programData;
2902 }
2903
2904
2905
2906 QT_END_NAMESPACE