1 /****************************************************************************
2 **
3 ** Copyright (C) 2015 The Qt Company Ltd.
4 ** Contact: http://www.qt.io/licensing/
5 **
6 ** This file is part of the QtDeclarative module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see http://www.qt.io/terms-conditions. For further
15 ** information use the contact form at http://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 or version 3 as published by the Free
20 ** Software Foundation and appearing in the file LICENSE.LGPLv21 and
21 ** LICENSE.LGPLv3 included in the packaging of this file. Please review the
22 ** following information to ensure the GNU Lesser General Public License
23 ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
24 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25 **
26 ** As a special exception, The Qt Company gives you certain additional
27 ** rights. These rights are described in The Qt Company LGPL Exception
28 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29 **
30 ** GNU General Public License Usage
31 ** Alternatively, this file may be used under the terms of the GNU
32 ** General Public License version 3.0 as published by the Free Software
33 ** Foundation and appearing in the file LICENSE.GPL included in the
34 ** packaging of this file.  Please review the following information to
35 ** ensure the GNU General Public License version 3.0 requirements will be
36 ** met: http://www.gnu.org/copyleft/gpl.html.
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 {
setUndefined__anon64c994381c11::Register141     void setUndefined() { type = 0; }
setUnknownButDefined__anon64c994381c11::Register142     void setUnknownButDefined() { type = -1; }
setNaN__anon64c994381c11::Register143     void setNaN() { setqreal(qSNaN()); }
isUndefined__anon64c994381c11::Register144     bool isUndefined() const { return type == 0; }
145 
setQObject__anon64c994381c11::Register146     void setQObject(QObject *o) { qobjectValue = o; type = QMetaType::QObjectStar; }
getQObject__anon64c994381c11::Register147     QObject *getQObject() const { return qobjectValue; }
148 
setqreal__anon64c994381c11::Register149     void setqreal(qreal v) { qrealValue = v; type = QMetaType::QReal; }
getqreal__anon64c994381c11::Register150     qreal getqreal() const { return qrealValue; }
151 
setint__anon64c994381c11::Register152     void setint(int v) { intValue = v; type = QMetaType::Int; }
getint__anon64c994381c11::Register153     int getint() const { return intValue; }
154 
setbool__anon64c994381c11::Register155     void setbool(bool v) { boolValue = v; type = QMetaType::Bool; }
getbool__anon64c994381c11::Register156     bool getbool() const { return boolValue; }
157 
getvariantptr__anon64c994381c11::Register158     QVariant *getvariantptr() { return (QVariant *)typeDataPtr(); }
getstringptr__anon64c994381c11::Register159     QString *getstringptr() { return (QString *)typeDataPtr(); }
geturlptr__anon64c994381c11::Register160     QUrl *geturlptr() { return (QUrl *)typeDataPtr(); }
getvariantptr__anon64c994381c11::Register161     const QVariant *getvariantptr() const { return (QVariant *)typeDataPtr(); }
getstringptr__anon64c994381c11::Register162     const QString *getstringptr() const { return (QString *)typeDataPtr(); }
geturlptr__anon64c994381c11::Register163     const QUrl *geturlptr() const { return (QUrl *)typeDataPtr(); }
164 
typeDataPtr__anon64c994381c11::Register165     void *typeDataPtr() { return (void *)&data; }
typeMemory__anon64c994381c11::Register166     void *typeMemory() { return (void *)data; }
typeDataPtr__anon64c994381c11::Register167     const void *typeDataPtr() const { return (void *)&data; }
typeMemory__anon64c994381c11::Register168     const void *typeMemory() const { return (void *)data; }
169 
gettype__anon64c994381c11::Register170     int gettype() const { return type; }
settype__anon64c994381c11::Register171     void settype(int t) { type = t; }
172 
173     int type;          // Optional type
174     union {
175         QObject *qobjectValue;
176         qreal qrealValue;
177         int intValue;
178         bool boolValue;
179         char data[sizeof(QVariant)];
180         qint64 q_for_alignment_1;
181         double q_for_alignment_2;
182     };
183 
184 #ifdef REGISTER_CLEANUP_DEBUG
Register__anon64c994381c11::Register185     Register() {
186         type = 0;
187     }
188 
~Register__anon64c994381c11::Register189     ~Register() {
190         int allowedTypes[] = { QMetaType::QObjectStar, QMetaType::QReal, QMetaType::Int, QMetaType::Bool, 0 };
191         bool found = (type == 0);
192         int *ctype = allowedTypes;
193         while (!found && *ctype) {
194             found = (*ctype == type);
195             ++ctype;
196         }
197         if (!found)
198             qWarning("Register leaked of type %d", type);
199     }
200 #endif
201 };
202 }
203 
204 class QDeclarativeCompiledBindingsPrivate : public QObjectPrivate
205 {
206     Q_DECLARE_PUBLIC(QDeclarativeCompiledBindings)
207 
208 public:
209     QDeclarativeCompiledBindingsPrivate();
210     virtual ~QDeclarativeCompiledBindingsPrivate();
211 
212     struct Binding : public QDeclarativeAbstractBinding, public QDeclarativeDelayedError {
BindingQDeclarativeCompiledBindingsPrivate::Binding213         Binding() : enabled(false), updating(0), property(0),
214                     scope(0), target(0), parent(0) {}
215 
216         // Inherited from QDeclarativeAbstractBinding
217         virtual void setEnabled(bool, QDeclarativePropertyPrivate::WriteFlags flags);
218         virtual void update(QDeclarativePropertyPrivate::WriteFlags flags);
219         virtual void destroy(DestroyMode mode);
220         virtual void disconnect(DisconnectMode disconnectMode);
221 
222         int index:30;
223         bool enabled:1;
224         bool updating:1;
225         int property;
226         QObject *scope;
227         QObject *target;
228 
229         QDeclarativeCompiledBindingsPrivate *parent;
230     };
231 
232     typedef QDeclarativeNotifierEndpoint Subscription;
233     Subscription *subscriptions;
234     QScriptDeclarativeClass::PersistentIdentifier *identifiers;
235 
236     void run(Binding *, QDeclarativePropertyPrivate::WriteFlags flags);
237 
238     const char *programData;
239     QDeclarativeRefCount *dataRef;
240     Binding *m_bindings;
241     quint32 *m_signalTable;
242     bool m_bindingsDisconnected;
243 
244     static int methodCount;
245 
246     void init();
247     void run(int instr, QDeclarativeContextData *context,
248              QDeclarativeDelayedError *error, QObject *scope, QObject *output, QDeclarativePropertyPrivate::WriteFlags storeFlags);
249 
250 
251     inline void subscribeId(QDeclarativeContextData *p, int idIndex, int subIndex);
252     inline void subscribe(QObject *o, int notifyIndex, int subIndex);
253     inline void disconnectAll();
254     inline void disconnectOne(Binding *bindingToDisconnect);
255 
256     QDeclarativePropertyCache::Data *findproperty(QObject *obj,
257                                                   const QScriptDeclarativeClass::Identifier &name,
258                                                   QDeclarativeEnginePrivate *enginePriv,
259                                                   QDeclarativePropertyCache::Data &local);
260     bool findproperty(QObject *obj,
261                       Register *output,
262                       QDeclarativeEnginePrivate *enginePriv,
263                       int subIdx,
264                       const QScriptDeclarativeClass::Identifier &name,
265                       bool isTerminal);
266     void findgeneric(Register *output,                                 // value output
267                      int subIdx,                                       // Subscription index in config
268                      QDeclarativeContextData *context,                 // Context to search in
269                      const QScriptDeclarativeClass::Identifier &name,
270                      bool isTerminal);
271 };
272 
QDeclarativeCompiledBindingsPrivate()273 QDeclarativeCompiledBindingsPrivate::QDeclarativeCompiledBindingsPrivate()
274     : subscriptions(0), identifiers(0), programData(0), dataRef(0), m_bindings(0), m_signalTable(0),
275       m_bindingsDisconnected(false)
276 {
277 }
278 
~QDeclarativeCompiledBindingsPrivate()279 QDeclarativeCompiledBindingsPrivate::~QDeclarativeCompiledBindingsPrivate()
280 {
281     delete [] subscriptions; subscriptions = 0;
282     delete [] identifiers; identifiers = 0;
283     if (dataRef) {
284         dataRef->release();
285         dataRef = 0;
286     }
287 }
288 
289 int QDeclarativeCompiledBindingsPrivate::methodCount = -1;
290 
QDeclarativeCompiledBindings(const char * program,QDeclarativeContextData * context,QDeclarativeRefCount * dataRef)291 QDeclarativeCompiledBindings::QDeclarativeCompiledBindings(const char *program, QDeclarativeContextData *context,
292                                                            QDeclarativeRefCount *dataRef)
293 : QObject(*(new QDeclarativeCompiledBindingsPrivate))
294 {
295     Q_D(QDeclarativeCompiledBindings);
296 
297     if (d->methodCount == -1)
298         d->methodCount = QDeclarativeCompiledBindings::staticMetaObject.methodCount();
299 
300     d->programData = program;
301     d->dataRef = dataRef;
302     if (d->dataRef) d->dataRef->addref();
303 
304     d->init();
305 
306     QDeclarativeAbstractExpression::setContext(context);
307 }
308 
~QDeclarativeCompiledBindings()309 QDeclarativeCompiledBindings::~QDeclarativeCompiledBindings()
310 {
311     Q_D(QDeclarativeCompiledBindings);
312 
313     delete [] d->m_bindings;
314 }
315 
configBinding(int index,QObject * target,QObject * scope,int property)316 QDeclarativeAbstractBinding *QDeclarativeCompiledBindings::configBinding(int index, QObject *target,
317                                                         QObject *scope, int property)
318 {
319     Q_D(QDeclarativeCompiledBindings);
320 
321     QDeclarativeCompiledBindingsPrivate::Binding *rv = d->m_bindings + index;
322 
323     rv->index = index;
324     rv->property = property;
325     rv->target = target;
326     rv->scope = scope;
327     rv->parent = d;
328 
329     addref(); // This is decremented in Binding::destroy()
330 
331     return rv;
332 }
333 
setEnabled(bool e,QDeclarativePropertyPrivate::WriteFlags flags)334 void QDeclarativeCompiledBindingsPrivate::Binding::setEnabled(bool e, QDeclarativePropertyPrivate::WriteFlags flags)
335 {
336     if (enabled != e) {
337         enabled = e;
338 
339         if (e) update(flags);
340     }
341 }
342 
update(QDeclarativePropertyPrivate::WriteFlags flags)343 void QDeclarativeCompiledBindingsPrivate::Binding::update(QDeclarativePropertyPrivate::WriteFlags flags)
344 {
345     QDeclarativeDebugTrace::startRange(QDeclarativeDebugTrace::Binding);
346     parent->run(this, flags);
347     QDeclarativeDebugTrace::endRange(QDeclarativeDebugTrace::Binding);
348 }
349 
destroy(DestroyMode mode)350 void QDeclarativeCompiledBindingsPrivate::Binding::destroy(DestroyMode mode)
351 {
352     if (mode == DisconnectBinding)
353         disconnect(QDeclarativeAbstractBinding::DisconnectOne);
354 
355     enabled = false;
356     removeFromObject();
357     clear();
358     parent->q_func()->release();
359 }
360 
disconnect(DisconnectMode disconnectMode)361 void QDeclarativeCompiledBindingsPrivate::Binding::disconnect(DisconnectMode disconnectMode)
362 {
363     if (disconnectMode == QDeclarativeAbstractBinding::DisconnectAll)
364         parent->disconnectAll();
365     else
366         parent->disconnectOne(this);
367 }
368 
qt_metacall(QMetaObject::Call c,int id,void **)369 int QDeclarativeCompiledBindings::qt_metacall(QMetaObject::Call c, int id, void **)
370 {
371     Q_D(QDeclarativeCompiledBindings);
372 
373     if (c == QMetaObject::InvokeMetaMethod && id >= d->methodCount) {
374         id -= d->methodCount;
375 
376         quint32 *reeval = d->m_signalTable + d->m_signalTable[id];
377         quint32 count = *reeval;
378         ++reeval;
379         for (quint32 ii = 0; ii < count; ++ii) {
380             d->run(d->m_bindings + reeval[ii], QDeclarativePropertyPrivate::DontRemoveBinding);
381         }
382     }
383     return -1;
384 }
385 
run(Binding * binding,QDeclarativePropertyPrivate::WriteFlags flags)386 void QDeclarativeCompiledBindingsPrivate::run(Binding *binding, QDeclarativePropertyPrivate::WriteFlags flags)
387 {
388     Q_Q(QDeclarativeCompiledBindings);
389 
390     if (!binding->enabled)
391         return;
392 
393     QDeclarativeContextData *context = q->QDeclarativeAbstractExpression::context();
394     if (!context || !context->isValid())
395         return;
396 
397     if (binding->updating) {
398         QString name;
399         if (binding->property & 0xFFFF0000) {
400             QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(context->engine);
401 
402             QDeclarativeValueType *vt = ep->valueTypes[(binding->property >> 16) & 0xFF];
403             Q_ASSERT(vt);
404 
405             name = QLatin1String(binding->target->metaObject()->property(binding->property & 0xFFFF).name());
406             name.append(QLatin1String("."));
407             name.append(QLatin1String(vt->metaObject()->property(binding->property >> 24).name()));
408         } else {
409             name = QLatin1String(binding->target->metaObject()->property(binding->property).name());
410         }
411         qmlInfo(binding->target) << QCoreApplication::translate("QDeclarativeCompiledBindings", "Binding loop detected for property \"%1\"").arg(name);
412         return;
413     }
414 
415     binding->updating = true;
416     if (binding->property & 0xFFFF0000) {
417         QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(context->engine);
418 
419         QDeclarativeValueType *vt = ep->valueTypes[(binding->property >> 16) & 0xFF];
420         Q_ASSERT(vt);
421         vt->read(binding->target, binding->property & 0xFFFF);
422 
423         QObject *target = vt;
424         run(binding->index, context, binding, binding->scope, target, flags);
425 
426         vt->write(binding->target, binding->property & 0xFFFF, flags);
427     } else {
428         run(binding->index, context, binding, binding->scope, binding->target, flags);
429     }
430     binding->updating = false;
431 }
432 
433 namespace {
434 // This structure is exactly 8-bytes in size
435 struct Instr {
436     enum {
437         FOR_EACH_QML_INSTR(QML_INSTR_ENUM)
438     };
439 
440     union {
441         struct {
442             QML_INSTR_HEADER
443             quint8 type;
444             quint8 packing[7];
445         } common;
446         struct {
447             QML_INSTR_HEADER
448             quint8 type;
449             quint8 packing;
450             quint16 column;
451             quint32 line;
452         } id;
453         struct {
454             QML_INSTR_HEADER
455             quint8 type;
456             quint8 packing[3];
457             quint16 subscriptions;
458             quint16 identifiers;
459         } init;
460         struct {
461             QML_INSTR_HEADER
462             quint8 type;
463             qint8 reg;
464             quint16 offset;
465             quint32 index;
466         } subscribe;
467         struct {
468             QML_INSTR_HEADER
469             quint8 type;
470             qint8 reg;
471             quint8 packing[2];
472             quint32 index;
473         } load;
474         struct {
475             QML_INSTR_HEADER
476             quint8 type;
477             qint8 output;
478             qint8 reg;
479             quint8 exceptionId;
480             quint32 id;
481         } attached;
482         struct {
483             QML_INSTR_HEADER
484             quint8 type;
485             qint8 output;
486             qint8 reg;
487             quint8 exceptionId;
488             quint32 index;
489         } store;
490         struct {
491             QML_INSTR_HEADER
492             quint8 type;
493             qint8 output;
494             qint8 objectReg;
495             quint8 exceptionId;
496             quint16 subscription;
497             quint16 function;
498         } fetchAndSubscribe;
499         struct {
500             QML_INSTR_HEADER
501             quint8 type;
502             qint8 output;
503             qint8 objectReg;
504             quint8 exceptionId;
505             quint32 index;
506         } fetch;
507         struct {
508             QML_INSTR_HEADER
509             quint8 type;
510             qint8 reg;
511             qint8 src;
512             quint8 packing[5];
513         } copy;
514         struct {
515             QML_INSTR_HEADER
516             quint8 type;
517             qint8 reg;
518             quint8 packing[6];
519         } construct;
520         struct {
521             QML_INSTR_HEADER
522             quint8 type;
523             qint8 reg;
524             quint8 packing[2];
525             float value;
526         } real_value;
527         struct {
528             QML_INSTR_HEADER
529             quint8 type;
530             qint8 reg;
531             quint8 packing[2];
532             int value;
533         } int_value;
534         struct {
535             QML_INSTR_HEADER
536             quint8 type;
537             qint8 reg;
538             bool value;
539             quint8 packing[5];
540         } bool_value;
541         struct {
542             QML_INSTR_HEADER
543             quint8 type;
544             qint8 reg;
545             quint16 length;
546             quint32 offset;
547         } string_value;
548         struct {
549             QML_INSTR_HEADER
550             quint8 type;
551             qint8 output;
552             qint8 src1;
553             qint8 src2;
554             quint8 packing[4];
555         } binaryop;
556         struct {
557             QML_INSTR_HEADER
558             quint8 type;
559             qint8 output;
560             qint8 src;
561             quint8 packing[5];
562         } unaryop;
563         struct {
564             QML_INSTR_HEADER
565             quint8 type;
566             qint8 reg;
567             quint8 packing[2];
568             quint32 count;
569         } skip;
570         struct {
571             QML_INSTR_HEADER
572             quint8 type;
573             qint8 reg;
574             qint8 src;
575             quint8 exceptionId;
576             quint16 name;
577             quint16 subscribeIndex;
578         } find;
579         struct {
580             QML_INSTR_HEADER
581             quint8 type;
582             qint8 reg;
583             quint8 packing[6];
584         } cleanup;
585         struct {
586             QML_INSTR_HEADER
587             quint8 type;
588             quint8 packing[1];
589             quint16 offset;
590             quint32 dataIdx;
591         } initstring;
592     };
593 };
594 
595 struct Program {
596     quint32 bindings;
597     quint32 dataLength;
598     quint32 signalTableOffset;
599     quint32 exceptionDataOffset;
600     quint16 subscriptions;
601     quint16 identifiers;
602     quint16 instructionCount;
603     quint16 compiled;
604 
data__anon64c994381e11::Program605     const char *data() const { return ((const char *)this) + sizeof(Program); }
instructions__anon64c994381e11::Program606     const Instr *instructions() const { return (const Instr *)(data() + dataLength); }
607 };
608 }
609 
610 struct QDeclarativeBindingCompilerPrivate
611 {
612     struct Result {
ResultQDeclarativeBindingCompilerPrivate::Result613         Result() : unknownType(false), metaObject(0), type(-1), reg(-1) {}
operator ==QDeclarativeBindingCompilerPrivate::Result614         bool operator==(const Result &o) const {
615             return unknownType == o.unknownType &&
616                    metaObject == o.metaObject &&
617                    type == o.type &&
618                    reg == o.reg;
619         }
operator !=QDeclarativeBindingCompilerPrivate::Result620         bool operator!=(const Result &o) const {
621             return !(*this == o);
622         }
623         bool unknownType;
624         const QMetaObject *metaObject;
625         int type;
626         int reg;
627 
628         QSet<QString> subscriptionSet;
629     };
630 
QDeclarativeBindingCompilerPrivateQDeclarativeBindingCompilerPrivate631     QDeclarativeBindingCompilerPrivate() : registers(0) {}
632 
633     void resetInstanceState();
634     int commitCompile();
635 
636     QDeclarativeParser::Object *context;
637     QDeclarativeParser::Object *component;
638     QDeclarativeParser::Property *destination;
639     QHash<QString, QDeclarativeParser::Object *> ids;
640     QDeclarativeImports imports;
641     QDeclarativeEnginePrivate *engine;
642 
contextNameQDeclarativeBindingCompilerPrivate643     QString contextName() const { return QLatin1String("$$$SCOPE_") + QString::number((quintptr)context, 16); }
644 
645     bool compile(QDeclarativeJS::AST::Node *);
646 
647     bool parseExpression(QDeclarativeJS::AST::Node *, Result &);
648 
649     bool tryName(QDeclarativeJS::AST::Node *);
650     bool parseName(QDeclarativeJS::AST::Node *, Result &);
651 
652     bool tryArith(QDeclarativeJS::AST::Node *);
653     bool parseArith(QDeclarativeJS::AST::Node *, Result &);
654     bool numberArith(Result &, const Result &, const Result &, QSOperator::Op op);
655     bool stringArith(Result &, const Result &, const Result &, QSOperator::Op op);
656 
657     bool tryLogic(QDeclarativeJS::AST::Node *);
658     bool parseLogic(QDeclarativeJS::AST::Node *, Result &);
659 
660     bool tryConditional(QDeclarativeJS::AST::Node *);
661     bool parseConditional(QDeclarativeJS::AST::Node *, Result &);
662 
663     bool tryConstant(QDeclarativeJS::AST::Node *);
664     bool parseConstant(QDeclarativeJS::AST::Node *, Result &);
665 
666     bool tryMethod(QDeclarativeJS::AST::Node *);
667     bool parseMethod(QDeclarativeJS::AST::Node *, Result &);
668 
669     bool buildName(QStringList &, QDeclarativeJS::AST::Node *, QList<QDeclarativeJS::AST::ExpressionNode *> *nodes = 0);
670     bool fetch(Result &type, const QMetaObject *, int reg, int idx, const QStringList &, QDeclarativeJS::AST::ExpressionNode *);
671 
672     quint32 registers;
673     QHash<int, QPair<int, int> > registerCleanups;
674     int acquireReg(int cleanup = Instr::Noop, int cleanupType = 0);
675     void registerCleanup(int reg, int cleanup, int cleanupType = 0);
676     void releaseReg(int);
677 
678     int registerLiteralString(const QString &);
679     int registerString(const QString &);
680     QHash<QString, QPair<int, int> > registeredStrings;
681     QByteArray data;
682 
683     bool subscription(const QStringList &, Result *);
684     int subscriptionIndex(const QStringList &);
685     bool subscriptionNeutral(const QSet<QString> &base, const QSet<QString> &lhs, const QSet<QString> &rhs);
686 
687     quint8 exceptionId(QDeclarativeJS::AST::ExpressionNode *);
688     QVector<quint64> exceptions;
689 
690     QSet<int> usedSubscriptionIds;
691     QSet<QString> subscriptionSet;
692     QHash<QString, int> subscriptionIds;
693     QVector<Instr> bytecode;
694 
695     // Committed binding data
696     struct {
697         QList<int> offsets;
698         QList<QSet<int> > dependencies;
699 
700         QVector<Instr> bytecode;
701         QByteArray data;
702         QHash<QString, int> subscriptionIds;
703         QVector<quint64> exceptions;
704 
705         QHash<QString, QPair<int, int> > registeredStrings;
706 
countQDeclarativeBindingCompilerPrivate::__anon64c994383608707         int count() const { return offsets.count(); }
708     } committed;
709 
710     QByteArray buildSignalTable() const;
711     QByteArray buildExceptionData() const;
712 };
713 
subscribeId(QDeclarativeContextData * p,int idIndex,int subIndex)714 void QDeclarativeCompiledBindingsPrivate::subscribeId(QDeclarativeContextData *p, int idIndex, int subIndex)
715 {
716     Q_Q(QDeclarativeCompiledBindings);
717 
718     QDeclarativeCompiledBindingsPrivate::Subscription *sub = (subscriptions + subIndex);
719     sub->disconnect();
720 
721     if (p->idValues[idIndex]) {
722         sub->target = q;
723         sub->targetMethod = methodCount + subIndex;
724         sub->connect(&p->idValues[idIndex].bindings);
725     }
726 }
727 
subscribe(QObject * o,int notifyIndex,int subIndex)728 void QDeclarativeCompiledBindingsPrivate::subscribe(QObject *o, int notifyIndex, int subIndex)
729 {
730     Q_Q(QDeclarativeCompiledBindings);
731 
732     QDeclarativeCompiledBindingsPrivate::Subscription *sub = (subscriptions + subIndex);
733     sub->target = q;
734     sub->targetMethod = methodCount + subIndex;
735     if (o)
736         sub->connect(o, notifyIndex);
737     else
738         sub->disconnect();
739 }
740 
disconnectAll()741 void QDeclarativeCompiledBindingsPrivate::disconnectAll()
742 {
743     // This gets called multiple times in QDeclarativeData::disconnectNotifiers(), avoid unneeded
744     // work for all but the first call.
745     if (m_bindingsDisconnected)
746         return;
747 
748     // We disconnect all subscriptions, so we can call disconnect() unconditionally if there is at
749     // least one connection
750     Program *program = (Program *)programData;
751     for (int subIndex = 0; subIndex < program->subscriptions; ++subIndex) {
752         Subscription * const sub = (subscriptions + subIndex);
753         if (sub->isConnected())
754             sub->disconnect();
755     }
756     m_bindingsDisconnected = true;
757 }
758 
disconnectOne(QDeclarativeCompiledBindingsPrivate::Binding * bindingToDisconnect)759 void QDeclarativeCompiledBindingsPrivate::disconnectOne(
760         QDeclarativeCompiledBindingsPrivate::Binding *bindingToDisconnect)
761 {
762     // We iterate over the signal table to find all subscriptions for this binding. This is slowish,
763     // but disconnectOne() is only called when overwriting a binding, which is quite rare.
764     Program *program = (Program *)programData;
765     for (int subIndex = 0; subIndex < program->subscriptions; ++subIndex) {
766         Subscription * const sub = (subscriptions + subIndex);
767         quint32 *reeval = m_signalTable + m_signalTable[subIndex];
768         quint32 bindingCount = *reeval;
769         ++reeval;
770         for (quint32 bindingIndex = 0; bindingIndex < bindingCount; ++bindingIndex) {
771             Binding * const binding = m_bindings + reeval[bindingIndex];
772             if (binding == bindingToDisconnect)
773                 sub->deref();
774         }
775     }
776 }
777 
778 // Conversion functions - these MUST match the QtScript expression path
toReal(Register * reg,int type,bool * ok=0)779 inline static qreal toReal(Register *reg, int type, bool *ok = 0)
780 {
781     if (ok) *ok = true;
782 
783     if (type == QMetaType::QReal) {
784         return reg->getqreal();
785     } else if (type == qMetaTypeId<QVariant>()) {
786         return reg->getvariantptr()->toReal();
787     } else {
788         if (ok) *ok = false;
789         return 0;
790     }
791 }
792 
toString(Register * reg,int type,bool * ok=0)793 inline static QString toString(Register *reg, int type, bool *ok = 0)
794 {
795     if (ok) *ok = true;
796 
797     if (type == QMetaType::QReal) {
798         return QString::number(reg->getqreal());
799     } else if (type == QMetaType::Int) {
800         return QString::number(reg->getint());
801     } else if (type == qMetaTypeId<QVariant>()) {
802         return reg->getvariantptr()->toString();
803     } else if (type == QMetaType::QString) {
804         return *reg->getstringptr();
805     } else {
806         if (ok) *ok = false;
807         return QString();
808     }
809 }
810 
toBool(Register * reg,int type,bool * ok=0)811 inline static bool toBool(Register *reg, int type, bool *ok = 0)
812 {
813     if (ok) *ok = true;
814 
815     if (type == QMetaType::Bool) {
816         return reg->getbool();
817     } else if (type == qMetaTypeId<QVariant>()) {
818         return reg->getvariantptr()->toBool();
819     } else {
820         if (ok) *ok = false;
821         return false;
822     }
823 }
824 
toUrl(Register * reg,int type,QDeclarativeContextData * context,bool * ok=0)825 inline static QUrl toUrl(Register *reg, int type, QDeclarativeContextData *context, bool *ok = 0)
826 {
827     if (ok) *ok = true;
828 
829     QUrl base;
830     if (type == qMetaTypeId<QVariant>()) {
831         QVariant *var = reg->getvariantptr();
832         int vt = var->type();
833         if (vt == QVariant::Url) {
834             base = var->toUrl();
835         } else if (vt == QVariant::ByteArray) {
836             base = QUrl(QString::fromUtf8(var->toByteArray()));
837         } else if (vt == QVariant::String) {
838             base = QUrl(var->toString());
839         } else {
840             if (ok) *ok = false;
841             return QUrl();
842         }
843     } else if (type == QMetaType::QString) {
844         base = QUrl(*reg->getstringptr());
845     } else {
846         if (ok) *ok = false;
847         return QUrl();
848     }
849 
850     if (!base.isEmpty() && base.isRelative())
851         return context->url.resolved(base);
852     else
853         return base;
854 }
855 
variantToQObject(const QVariant & value,bool * ok)856 static QObject *variantToQObject(const QVariant &value, bool *ok)
857 {
858     if (ok) *ok = true;
859 
860     if (value.userType() == QMetaType::QObjectStar) {
861         return qvariant_cast<QObject*>(value);
862     } else {
863         if (ok) *ok = false;
864         return 0;
865     }
866 }
867 
findproperty(QObject * obj,Register * output,QDeclarativeEnginePrivate * enginePriv,int subIdx,const QScriptDeclarativeClass::Identifier & name,bool isTerminal)868 bool QDeclarativeCompiledBindingsPrivate::findproperty(QObject *obj, Register *output,
869                                                        QDeclarativeEnginePrivate *enginePriv,
870                                                        int subIdx, const QScriptDeclarativeClass::Identifier &name,
871                                                        bool isTerminal)
872 {
873     if (!obj) {
874         output->setUndefined();
875         return false;
876     }
877 
878     QDeclarativePropertyCache::Data local;
879     QDeclarativePropertyCache::Data *property =
880         QDeclarativePropertyCache::property(QDeclarativeEnginePrivate::get(enginePriv), obj, name, local);
881 
882     if (property) {
883         if (subIdx != -1)
884             subscribe(obj, property->notifyIndex, subIdx);
885 
886         if (property->flags & QDeclarativePropertyCache::Data::IsQObjectDerived) {
887             void *args[] = { output->typeDataPtr(), 0 };
888             QMetaObject::metacall(obj, QMetaObject::ReadProperty, property->coreIndex, args);
889             output->settype(QMetaType::QObjectStar);
890         } else if (property->propType == qMetaTypeId<QVariant>()) {
891             QVariant v;
892             void *args[] = { &v, 0 };
893             QMetaObject::metacall(obj, QMetaObject::ReadProperty, property->coreIndex, args);
894 
895             if (isTerminal) {
896                 new (output->typeDataPtr()) QVariant(v);
897                 output->settype(qMetaTypeId<QVariant>());
898             } else {
899                 bool ok;
900                 output->setQObject(variantToQObject(v, &ok));
901                 if (!ok)
902                     output->setUndefined();
903                 else
904                     output->settype(QMetaType::QObjectStar);
905             }
906 
907         } else {
908             if (!isTerminal) {
909                 output->setUndefined();
910             } else if (property->propType == QMetaType::QReal) {
911                 void *args[] = { output->typeDataPtr(), 0 };
912                 QMetaObject::metacall(obj, QMetaObject::ReadProperty, property->coreIndex, args);
913                 output->settype(QMetaType::QReal);
914             } else if (property->propType == QMetaType::Int) {
915                 void *args[] = { output->typeDataPtr(), 0 };
916                 QMetaObject::metacall(obj, QMetaObject::ReadProperty, property->coreIndex, args);
917                 output->settype(QMetaType::Int);
918             } else if (property->propType == QMetaType::Bool) {
919                 void *args[] = { output->typeDataPtr(), 0 };
920                 QMetaObject::metacall(obj, QMetaObject::ReadProperty, property->coreIndex, args);
921                 output->settype(QMetaType::Bool);
922             } else if (property->propType == QMetaType::QString) {
923                 new (output->typeDataPtr()) QString();
924                 void *args[] = { output->typeDataPtr(), 0 };
925                 QMetaObject::metacall(obj, QMetaObject::ReadProperty, property->coreIndex, args);
926                 output->settype(QMetaType::QString);
927             } else {
928                 new (output->typeDataPtr())
929                     QVariant(obj->metaObject()->property(property->coreIndex).read(obj));
930                 output->settype(qMetaTypeId<QVariant>());
931             }
932         }
933 
934         return true;
935     } else {
936         output->setUndefined();
937         return false;
938     }
939 }
940 
findgeneric(Register * output,int subIdx,QDeclarativeContextData * context,const QScriptDeclarativeClass::Identifier & name,bool isTerminal)941 void QDeclarativeCompiledBindingsPrivate::findgeneric(Register *output,
942                                                       int subIdx,
943                                                       QDeclarativeContextData *context,
944                                                       const QScriptDeclarativeClass::Identifier &name,
945                                                       bool isTerminal)
946 {
947     QDeclarativeEnginePrivate *enginePriv = QDeclarativeEnginePrivate::get(context->engine);
948 
949     while (context) {
950 
951         int contextPropertyIndex = context->propertyNames?context->propertyNames->value(name):-1;
952 
953 
954         if (contextPropertyIndex != -1) {
955 
956             if (contextPropertyIndex < context->idValueCount) {
957                 output->setQObject(context->idValues[contextPropertyIndex]);
958                 output->settype(QMetaType::QObjectStar);
959 
960                 if (subIdx != -1)
961                     subscribeId(context, contextPropertyIndex, subIdx);
962 
963             } else {
964                 QDeclarativeContextPrivate *cp = context->asQDeclarativeContextPrivate();
965                 const QVariant &value = cp->propertyValues.at(contextPropertyIndex);
966 
967                 if (isTerminal) {
968                     new (output->typeDataPtr()) QVariant(value);
969                     output->settype(qMetaTypeId<QVariant>());
970                 } else {
971                     bool ok;
972                     output->setQObject(variantToQObject(value, &ok));
973                     if (!ok) { output->setUndefined(); }
974                     else { output->settype(QMetaType::QObjectStar); }
975                     return;
976                 }
977 
978                 if (subIdx != -1)
979                     subscribe(context->asQDeclarativeContext(), contextPropertyIndex + cp->notifyIndex, subIdx);
980 
981 
982             }
983 
984             return;
985         }
986 
987         if (QObject *root = context->contextObject) {
988 
989             if (findproperty(root, output, enginePriv, subIdx, name, isTerminal))
990                 return;
991 
992         }
993 
994         context = context->parent;
995     }
996 
997     output->setUndefined();
998 }
999 
init()1000 void QDeclarativeCompiledBindingsPrivate::init()
1001 {
1002     Program *program = (Program *)programData;
1003     if (program->subscriptions)
1004         subscriptions = new QDeclarativeCompiledBindingsPrivate::Subscription[program->subscriptions];
1005     if (program->identifiers)
1006         identifiers = new QScriptDeclarativeClass::PersistentIdentifier[program->identifiers];
1007 
1008     m_signalTable = (quint32 *)(program->data() + program->signalTableOffset);
1009     m_bindings = new QDeclarativeCompiledBindingsPrivate::Binding[program->bindings];
1010 }
1011 
throwException(int id,QDeclarativeDelayedError * error,Program * program,QDeclarativeContextData * context,const QString & description=QString ())1012 static void throwException(int id, QDeclarativeDelayedError *error,
1013                            Program *program, QDeclarativeContextData *context,
1014                            const QString &description = QString())
1015 {
1016     error->error.setUrl(context->url);
1017     if (description.isEmpty())
1018         error->error.setDescription(QLatin1String("TypeError: Result of expression is not an object"));
1019     else
1020         error->error.setDescription(description);
1021     if (id != 0xFF) {
1022         quint64 e = *((quint64 *)(program->data() + program->exceptionDataOffset) + id);
1023         error->error.setLine((e >> 32) & 0xFFFFFFFF);
1024         error->error.setColumn(e & 0xFFFFFFFF);
1025     } else {
1026         error->error.setLine(-1);
1027         error->error.setColumn(-1);
1028     }
1029     if (!context->engine || !error->addError(QDeclarativeEnginePrivate::get(context->engine)))
1030         QDeclarativeEnginePrivate::warning(context->engine, error->error);
1031 }
1032 
dumpInstruction(const Instr * instr)1033 static void dumpInstruction(const Instr *instr)
1034 {
1035     switch (instr->common.type) {
1036     case Instr::Noop:
1037         qWarning().nospace() << "\t" << "Noop";
1038         break;
1039     case Instr::BindingId:
1040         qWarning().nospace() << instr->id.line << ":" << instr->id.column << ":";
1041         break;
1042     case Instr::Subscribe:
1043         qWarning().nospace() << "\t" << "Subscribe" << "\t\t" << instr->subscribe.offset << "\t" << instr->subscribe.reg << "\t" << instr->subscribe.index;
1044         break;
1045     case Instr::SubscribeId:
1046         qWarning().nospace() << "\t" << "SubscribeId" << "\t\t" << instr->subscribe.offset << "\t" << instr->subscribe.reg << "\t" << instr->subscribe.index;
1047         break;
1048     case Instr::FetchAndSubscribe:
1049         qWarning().nospace() << "\t" << "FetchAndSubscribe" << "\t" << instr->fetchAndSubscribe.output << "\t" << instr->fetchAndSubscribe.objectReg << "\t" << instr->fetchAndSubscribe.subscription;
1050         break;
1051     case Instr::LoadId:
1052         qWarning().nospace() << "\t" << "LoadId" << "\t\t\t" << instr->load.index << "\t" << instr->load.reg;
1053         break;
1054     case Instr::LoadScope:
1055         qWarning().nospace() << "\t" << "LoadScope" << "\t\t" << instr->load.index << "\t" << instr->load.reg;
1056         break;
1057     case Instr::LoadRoot:
1058         qWarning().nospace() << "\t" << "LoadRoot" << "\t\t" << instr->load.index << "\t" << instr->load.reg;
1059         break;
1060     case Instr::LoadAttached:
1061         qWarning().nospace() << "\t" << "LoadAttached" << "\t\t" << instr->attached.output << "\t" << instr->attached.reg << "\t" << instr->attached.id;
1062         break;
1063     case Instr::ConvertIntToReal:
1064         qWarning().nospace() << "\t" << "ConvertIntToReal" << "\t" << instr->unaryop.output << "\t" << instr->unaryop.src;
1065         break;
1066     case Instr::ConvertRealToInt:
1067         qWarning().nospace() << "\t" << "ConvertRealToInt" << "\t" << instr->unaryop.output << "\t" << instr->unaryop.src;
1068         break;
1069     case Instr::Real:
1070         qWarning().nospace() << "\t" << "Real" << "\t\t\t" << instr->real_value.reg << "\t" << instr->real_value.value;
1071         break;
1072     case Instr::Int:
1073         qWarning().nospace() << "\t" << "Int" << "\t\t\t" << instr->int_value.reg << "\t" << instr->int_value.value;
1074         break;
1075     case Instr::Bool:
1076         qWarning().nospace() << "\t" << "Bool" << "\t\t\t" << instr->bool_value.reg << "\t" << instr->bool_value.value;
1077         break;
1078     case Instr::String:
1079         qWarning().nospace() << "\t" << "String" << "\t\t\t" << instr->string_value.reg << "\t" << instr->string_value.offset << "\t" << instr->string_value.length;
1080         break;
1081     case Instr::AddReal:
1082         qWarning().nospace() << "\t" << "AddReal" << "\t\t\t" << instr->binaryop.output << "\t" << instr->binaryop.src1 << "\t" << instr->binaryop.src2;
1083         break;
1084     case Instr::AddInt:
1085         qWarning().nospace() << "\t" << "AddInt" << "\t\t\t" << instr->binaryop.output << "\t" << instr->binaryop.src1 << "\t" << instr->binaryop.src2;
1086         break;
1087     case Instr::AddString:
1088         qWarning().nospace() << "\t" << "AddString" << "\t\t" << instr->binaryop.output << "\t" << instr->binaryop.src1 << "\t" << instr->binaryop.src2;
1089         break;
1090     case Instr::MinusReal:
1091         qWarning().nospace() << "\t" << "MinusReal" << "\t\t" << instr->binaryop.output << "\t" << instr->binaryop.src1 << "\t" << instr->binaryop.src2;
1092         break;
1093     case Instr::MinusInt:
1094         qWarning().nospace() << "\t" << "MinusInt" << "\t\t" << instr->binaryop.output << "\t" << instr->binaryop.src1 << "\t" << instr->binaryop.src2;
1095         break;
1096     case Instr::CompareReal:
1097         qWarning().nospace() << "\t" << "CompareReal" << "\t\t" << instr->binaryop.output << "\t" << instr->binaryop.src1 << "\t" << instr->binaryop.src2;
1098         break;
1099     case Instr::CompareString:
1100         qWarning().nospace() << "\t" << "CompareString" << "\t\t" << instr->binaryop.output << "\t" << instr->binaryop.src1 << "\t" << instr->binaryop.src2;
1101         break;
1102     case Instr::NotCompareReal:
1103         qWarning().nospace() << "\t" << "NotCompareReal" << "\t\t" << instr->binaryop.output << "\t" << instr->binaryop.src1 << "\t" << instr->binaryop.src2;
1104         break;
1105     case Instr::NotCompareString:
1106         qWarning().nospace() << "\t" << "NotCompareString" << "\t\t" << instr->binaryop.output << "\t" << instr->binaryop.src1 << "\t" << instr->binaryop.src2;
1107         break;
1108     case Instr::GreaterThanReal:
1109         qWarning().nospace() << "\t" << "GreaterThanReal" << "\t\t" << instr->binaryop.output << "\t" << instr->binaryop.src1 << "\t" << instr->binaryop.src2;
1110         break;
1111     case Instr::MaxReal:
1112         qWarning().nospace() << "\t" << "MaxReal" << "\t\t\t" << instr->binaryop.output << "\t" << instr->binaryop.src1 << "\t" << instr->binaryop.src2;
1113         break;
1114     case Instr::MinReal:
1115         qWarning().nospace() << "\t" << "MinReal" << "\t\t\t" << instr->binaryop.output << "\t" << instr->binaryop.src1 << "\t" << instr->binaryop.src2;
1116         break;
1117     case Instr::NewString:
1118         qWarning().nospace() << "\t" << "NewString" << "\t\t" << instr->construct.reg;
1119         break;
1120     case Instr::NewUrl:
1121         qWarning().nospace() << "\t" << "NewUrl" << "\t\t\t" << instr->construct.reg;
1122         break;
1123     case Instr::CleanupString:
1124         qWarning().nospace() << "\t" << "CleanupString" << "\t\t" << instr->cleanup.reg;
1125         break;
1126     case Instr::CleanupUrl:
1127         qWarning().nospace() << "\t" << "CleanupUrl" << "\t\t" << instr->cleanup.reg;
1128         break;
1129     case Instr::Fetch:
1130         qWarning().nospace() << "\t" << "Fetch" << "\t\t\t" << instr->fetch.output << "\t" << instr->fetch.index << "\t" << instr->fetch.objectReg;
1131         break;
1132     case Instr::Store:
1133         qWarning().nospace() << "\t" << "Store" << "\t\t\t" << instr->store.output << "\t" << instr->store.index << "\t" << instr->store.reg;
1134         break;
1135     case Instr::Copy:
1136         qWarning().nospace() << "\t" << "Copy" << "\t\t\t" << instr->copy.reg << "\t" << instr->copy.src;
1137         break;
1138     case Instr::Skip:
1139         qWarning().nospace() << "\t" << "Skip" << "\t\t\t" << instr->skip.reg << "\t" << instr->skip.count;
1140         break;
1141     case Instr::Done:
1142         qWarning().nospace() << "\t" << "Done";
1143         break;
1144     case Instr::InitString:
1145         qWarning().nospace() << "\t" << "InitString" << "\t\t" << instr->initstring.offset << "\t" << instr->initstring.dataIdx;
1146         break;
1147     case Instr::FindGeneric:
1148         qWarning().nospace() << "\t" << "FindGeneric" << "\t\t" << instr->find.reg << "\t" << instr->find.name;
1149         break;
1150     case Instr::FindGenericTerminal:
1151         qWarning().nospace() << "\t" << "FindGenericTerminal" << "\t" << instr->find.reg << "\t" <<  instr->find.name;
1152         break;
1153     case Instr::FindProperty:
1154         qWarning().nospace() << "\t" << "FindProperty" << "\t\t" << instr->find.reg << "\t" << instr->find.src << "\t" << instr->find.name;
1155         break;
1156     case Instr::FindPropertyTerminal:
1157         qWarning().nospace() << "\t" << "FindPropertyTerminal" << "\t" << instr->find.reg << "\t" << instr->find.src << "\t" << instr->find.name;
1158         break;
1159     case Instr::CleanupGeneric:
1160         qWarning().nospace() << "\t" << "CleanupGeneric" << "\t\t" << instr->cleanup.reg;
1161         break;
1162     case Instr::ConvertGenericToReal:
1163         qWarning().nospace() << "\t" << "ConvertGenericToReal" << "\t" << instr->unaryop.output << "\t" << instr->unaryop.src;
1164         break;
1165     case Instr::ConvertGenericToBool:
1166         qWarning().nospace() << "\t" << "ConvertGenericToBool" << "\t" << instr->unaryop.output << "\t" << instr->unaryop.src;
1167         break;
1168     case Instr::ConvertGenericToString:
1169         qWarning().nospace() << "\t" << "ConvertGenericToString" << "\t" << instr->unaryop.output << "\t" << instr->unaryop.src;
1170         break;
1171     case Instr::ConvertGenericToUrl:
1172         qWarning().nospace() << "\t" << "ConvertGenericToUrl" << "\t" << instr->unaryop.output << "\t" << instr->unaryop.src;
1173         break;
1174     default:
1175         qWarning().nospace() << "\t" << "Unknown";
1176         break;
1177     }
1178 }
1179 
run(int instrIndex,QDeclarativeContextData * context,QDeclarativeDelayedError * error,QObject * scope,QObject * output,QDeclarativePropertyPrivate::WriteFlags storeFlags)1180 void QDeclarativeCompiledBindingsPrivate::run(int instrIndex,
1181                                               QDeclarativeContextData *context, QDeclarativeDelayedError *error,
1182                                               QObject *scope, QObject *output, QDeclarativePropertyPrivate::WriteFlags storeFlags)
1183 {
1184     Q_Q(QDeclarativeCompiledBindings);
1185 
1186     error->removeError();
1187 
1188     Register registers[32];
1189 
1190     QDeclarativeEnginePrivate *engine = QDeclarativeEnginePrivate::get(context->engine);
1191     Program *program = (Program *)programData;
1192     const Instr *instr = program->instructions();
1193     instr += instrIndex;
1194     const char *data = program->data();
1195 
1196 #ifdef QML_THREADED_INTERPRETER
1197     static void *decode_instr[] = {
1198         FOR_EACH_QML_INSTR(QML_INSTR_ADDR)
1199     };
1200 
1201     if (!program->compiled) {
1202         program->compiled = true;
1203         const Instr *inop = program->instructions();
1204         for (int i = 0; i < program->instructionCount; ++i) {
1205             Instr *op = (Instr *) inop++;
1206             op->common.code = decode_instr[op->common.type];
1207         }
1208     }
1209 
1210     goto *instr->common.code;
1211 #else
1212     // return;
1213 
1214 #ifdef COMPILEDBINDINGS_DEBUG
1215     qWarning().nospace() << "Begin binding run";
1216 #endif
1217 
1218     while (instr) {
1219         switch (instr->common.type) {
1220 
1221 #ifdef COMPILEDBINDINGS_DEBUG
1222         dumpInstruction(instr);
1223 #endif
1224 
1225 #endif
1226 
1227     QML_BEGIN_INSTR(Noop)
1228     QML_END_INSTR(Noop)
1229 
1230     QML_BEGIN_INSTR(BindingId)
1231     QML_END_INSTR(BindingId)
1232 
1233     QML_BEGIN_INSTR(SubscribeId)
1234         subscribeId(context, instr->subscribe.index, instr->subscribe.offset);
1235     QML_END_INSTR(SubscribeId)
1236 
1237     QML_BEGIN_INSTR(Subscribe)
1238     {
1239         QObject *o = 0;
1240         const Register &object = registers[instr->subscribe.reg];
1241         if (!object.isUndefined()) o = object.getQObject();
1242         subscribe(o, instr->subscribe.index, instr->subscribe.offset);
1243     }
1244     QML_END_INSTR(Subscribe)
1245 
1246     QML_BEGIN_INSTR(FetchAndSubscribe)
1247     {
1248         const Register &input = registers[instr->fetchAndSubscribe.objectReg];
1249         Register &output = registers[instr->fetchAndSubscribe.output];
1250 
1251         if (input.isUndefined()) {
1252             throwException(instr->fetchAndSubscribe.exceptionId, error, program, context);
1253             return;
1254         }
1255 
1256         QObject *object = input.getQObject();
1257         if (!object) {
1258             output.setUndefined();
1259         } else {
1260             int subIdx = instr->fetchAndSubscribe.subscription;
1261             QDeclarativeCompiledBindingsPrivate::Subscription *sub = 0;
1262             if (subIdx != -1) {
1263                 sub = (subscriptions + subIdx);
1264                 sub->target = q;
1265                 sub->targetMethod = methodCount + subIdx;
1266             }
1267             fastProperties()->accessor(instr->fetchAndSubscribe.function)(object, output.typeDataPtr(), sub);
1268         }
1269     }
1270     QML_END_INSTR(FetchAndSubscribe)
1271 
1272     QML_BEGIN_INSTR(LoadId)
1273         registers[instr->load.reg].setQObject(context->idValues[instr->load.index].data());
1274     QML_END_INSTR(LoadId)
1275 
1276     QML_BEGIN_INSTR(LoadScope)
1277         registers[instr->load.reg].setQObject(scope);
1278     QML_END_INSTR(LoadScope)
1279 
1280     QML_BEGIN_INSTR(LoadRoot)
1281         registers[instr->load.reg].setQObject(context->contextObject);
1282     QML_END_INSTR(LoadRoot)
1283 
1284     QML_BEGIN_INSTR(LoadAttached)
1285     {
1286         const Register &input = registers[instr->attached.reg];
1287         Register &output = registers[instr->attached.output];
1288         if (input.isUndefined()) {
1289             throwException(instr->attached.exceptionId, error, program, context);
1290             return;
1291         }
1292 
1293         QObject *object = registers[instr->attached.reg].getQObject();
1294         if (!object) {
1295             output.setUndefined();
1296         } else {
1297             QObject *attached =
1298                 qmlAttachedPropertiesObjectById(instr->attached.id,
1299                                                 registers[instr->attached.reg].getQObject(),
1300                                                 true);
1301             Q_ASSERT(attached);
1302             output.setQObject(attached);
1303         }
1304     }
1305     QML_END_INSTR(LoadAttached)
1306 
1307     QML_BEGIN_INSTR(ConvertIntToReal)
1308     {
1309         const Register &input = registers[instr->unaryop.src];
1310         Register &output = registers[instr->unaryop.output];
1311         if (input.isUndefined()) output.setUndefined();
1312         else output.setqreal(qreal(input.getint()));
1313     }
1314     QML_END_INSTR(ConvertIntToReal)
1315 
1316     QML_BEGIN_INSTR(ConvertRealToInt)
1317     {
1318         const Register &input = registers[instr->unaryop.src];
1319         Register &output = registers[instr->unaryop.output];
1320         if (input.isUndefined()) output.setUndefined();
1321         else output.setint(qRound(input.getqreal()));
1322     }
1323     QML_END_INSTR(ConvertRealToInt)
1324 
1325     QML_BEGIN_INSTR(Real)
1326         registers[instr->real_value.reg].setqreal(instr->real_value.value);
1327     QML_END_INSTR(Real)
1328 
1329     QML_BEGIN_INSTR(Int)
1330         registers[instr->int_value.reg].setint(instr->int_value.value);
1331     QML_END_INSTR(Int)
1332 
1333     QML_BEGIN_INSTR(Bool)
1334         registers[instr->bool_value.reg].setbool(instr->bool_value.value);
1335     QML_END_INSTR(Bool)
1336 
1337     QML_BEGIN_INSTR(String)
1338     {
1339         Register &output = registers[instr->string_value.reg];
1340         new (output.getstringptr())
1341             QString((QChar *)(data + instr->string_value.offset), instr->string_value.length);
1342         output.settype(QMetaType::QString);
1343     }
1344     QML_END_INSTR(String)
1345 
1346     QML_BEGIN_INSTR(AddReal)
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.setNaN();
1352         else output.setqreal(lhs.getqreal() + rhs.getqreal());
1353     }
1354     QML_END_INSTR(AddReal)
1355 
1356     QML_BEGIN_INSTR(AddInt)
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.setNaN();
1362         else output.setint(lhs.getint() + rhs.getint());
1363     }
1364     QML_END_INSTR(AddInt)
1365 
1366     QML_BEGIN_INSTR(AddString)
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.setNaN(); }
1372         else {
1373             if (lhs.isUndefined())
1374                 new (output.getstringptr())
1375                     QString(QLatin1String("undefined") + *registers[instr->binaryop.src2].getstringptr());
1376             else if (rhs.isUndefined())
1377                 new (output.getstringptr())
1378                     QString(*registers[instr->binaryop.src1].getstringptr() + QLatin1String("undefined"));
1379             else
1380                 new (output.getstringptr())
1381                     QString(*registers[instr->binaryop.src1].getstringptr() +
1382                             *registers[instr->binaryop.src2].getstringptr());
1383             output.settype(QMetaType::QString);
1384         }
1385     }
1386     QML_END_INSTR(AddString)
1387 
1388     QML_BEGIN_INSTR(MinusReal)
1389     {
1390         const Register &lhs = registers[instr->binaryop.src1];
1391         const Register &rhs = registers[instr->binaryop.src2];
1392         Register &output = registers[instr->binaryop.output];
1393         if (lhs.isUndefined() || rhs.isUndefined()) output.setNaN();
1394         else output.setqreal(lhs.getqreal() - rhs.getqreal());
1395     }
1396     QML_END_INSTR(MinusReal)
1397 
1398     QML_BEGIN_INSTR(MinusInt)
1399     {
1400         const Register &lhs = registers[instr->binaryop.src1];
1401         const Register &rhs = registers[instr->binaryop.src2];
1402         Register &output = registers[instr->binaryop.output];
1403         if (lhs.isUndefined() || rhs.isUndefined()) output.setNaN();
1404         else output.setint(lhs.getint() - rhs.getint());
1405     }
1406     QML_END_INSTR(MinusInt)
1407 
1408     QML_BEGIN_INSTR(CompareReal)
1409     {
1410         const Register &lhs = registers[instr->binaryop.src1];
1411         const Register &rhs = registers[instr->binaryop.src2];
1412         Register &output = registers[instr->binaryop.output];
1413         if (lhs.isUndefined() || rhs.isUndefined()) output.setbool(lhs.isUndefined() == rhs.isUndefined());
1414         else output.setbool(lhs.getqreal() == rhs.getqreal());
1415     }
1416     QML_END_INSTR(CompareReal)
1417 
1418     QML_BEGIN_INSTR(CompareString)
1419     {
1420         const Register &lhs = registers[instr->binaryop.src1];
1421         const Register &rhs = registers[instr->binaryop.src2];
1422         Register &output = registers[instr->binaryop.output];
1423         if (lhs.isUndefined() || rhs.isUndefined()) output.setbool(lhs.isUndefined() == rhs.isUndefined());
1424         else output.setbool(*lhs.getstringptr() == *rhs.getstringptr());
1425     }
1426     QML_END_INSTR(CompareString)
1427 
1428     QML_BEGIN_INSTR(NotCompareReal)
1429     {
1430         const Register &lhs = registers[instr->binaryop.src1];
1431         const Register &rhs = registers[instr->binaryop.src2];
1432         Register &output = registers[instr->binaryop.output];
1433         if (lhs.isUndefined() || rhs.isUndefined()) output.setbool(lhs.isUndefined() != rhs.isUndefined());
1434         else output.setbool(lhs.getqreal() != rhs.getqreal());
1435     }
1436     QML_END_INSTR(NotCompareReal)
1437 
1438     QML_BEGIN_INSTR(NotCompareString)
1439     {
1440         const Register &lhs = registers[instr->binaryop.src1];
1441         const Register &rhs = registers[instr->binaryop.src2];
1442         Register &output = registers[instr->binaryop.output];
1443         if (lhs.isUndefined() || rhs.isUndefined()) output.setbool(lhs.isUndefined() != rhs.isUndefined());
1444         else output.setbool(*lhs.getstringptr() != *rhs.getstringptr());
1445     }
1446     QML_END_INSTR(NotCompareString)
1447 
1448     QML_BEGIN_INSTR(GreaterThanReal)
1449     {
1450         const Register &lhs = registers[instr->binaryop.src1];
1451         const Register &rhs = registers[instr->binaryop.src2];
1452         Register &output = registers[instr->binaryop.output];
1453         if (lhs.isUndefined() || rhs.isUndefined()) output.setbool(false);
1454         else output.setbool(lhs.getqreal() > rhs.getqreal());
1455     }
1456     QML_END_INSTR(GreaterThanReal)
1457 
1458     QML_BEGIN_INSTR(MaxReal)
1459     {
1460         const Register &lhs = registers[instr->binaryop.src1];
1461         const Register &rhs = registers[instr->binaryop.src2];
1462         Register &output = registers[instr->binaryop.output];
1463         if (lhs.isUndefined() || rhs.isUndefined()) output.setNaN();
1464         else output.setqreal(qMax(lhs.getqreal(), rhs.getqreal()));
1465     }
1466     QML_END_INSTR(MaxReal)
1467 
1468     QML_BEGIN_INSTR(MinReal)
1469     {
1470         const Register &lhs = registers[instr->binaryop.src1];
1471         const Register &rhs = registers[instr->binaryop.src2];
1472         Register &output = registers[instr->binaryop.output];
1473         if (lhs.isUndefined() || rhs.isUndefined()) output.setNaN();
1474         else output.setqreal(qMin(lhs.getqreal(), rhs.getqreal()));
1475     }
1476     QML_END_INSTR(MinReal)
1477 
1478     QML_BEGIN_INSTR(NewString)
1479     {
1480         Register &output = registers[instr->construct.reg];
1481         new (output.getstringptr()) QString;
1482         output.settype(QMetaType::QString);
1483     }
1484     QML_END_INSTR(NewString)
1485 
1486     QML_BEGIN_INSTR(NewUrl)
1487     {
1488         Register &output = registers[instr->construct.reg];
1489         new (output.geturlptr()) QUrl;
1490         output.settype(QMetaType::QUrl);
1491     }
1492     QML_END_INSTR(NewUrl)
1493 
1494     QML_BEGIN_INSTR(CleanupString)
1495         registers[instr->cleanup.reg].getstringptr()->~QString();
1496 #ifdef REGISTER_CLEANUP_DEBUG
1497         registers[instr->cleanup.reg].setUndefined();
1498 #endif
1499     QML_END_INSTR(CleanupString)
1500 
1501     QML_BEGIN_INSTR(CleanupUrl)
1502         registers[instr->cleanup.reg].geturlptr()->~QUrl();
1503 #ifdef REGISTER_CLEANUP_DEBUG
1504         registers[instr->cleanup.reg].setUndefined();
1505 #endif
1506     QML_END_INSTR(CleanupUrl)
1507 
1508     QML_BEGIN_INSTR(Fetch)
1509     {
1510         const Register &input = registers[instr->fetch.objectReg];
1511         Register &output = registers[instr->fetch.output];
1512 
1513         if (input.isUndefined()) {
1514             throwException(instr->fetch.exceptionId, error, program, context);
1515             return;
1516         }
1517 
1518         QObject *object = input.getQObject();
1519         if (!object) {
1520             output.setUndefined();
1521         } else {
1522             void *argv[] = { output.typeDataPtr(), 0 };
1523             QMetaObject::metacall(object, QMetaObject::ReadProperty, instr->fetch.index, argv);
1524         }
1525     }
1526     QML_END_INSTR(Fetch)
1527 
1528     QML_BEGIN_INSTR(Store)
1529     {
1530         Register &data = registers[instr->store.reg];
1531         if (data.isUndefined()) {
1532             throwException(instr->store.exceptionId, error, program, context,
1533                            QLatin1String("Unable to assign undefined value"));
1534             return;
1535         }
1536 
1537         int status = -1;
1538         void *argv[] = { data.typeDataPtr(), 0, &status, &storeFlags };
1539         QMetaObject::metacall(output, QMetaObject::WriteProperty,
1540                               instr->store.index, argv);
1541     }
1542     QML_END_INSTR(Store)
1543 
1544     QML_BEGIN_INSTR(Copy)
1545         registers[instr->copy.reg] = registers[instr->copy.src];
1546     QML_END_INSTR(Copy)
1547 
1548     QML_BEGIN_INSTR(Skip)
1549         if (instr->skip.reg == -1 || !registers[instr->skip.reg].getbool())
1550             instr += instr->skip.count;
1551     QML_END_INSTR(Skip)
1552 
1553     QML_BEGIN_INSTR(Done)
1554         return;
1555     QML_END_INSTR(Done)
1556 
1557     QML_BEGIN_INSTR(InitString)
1558         if (!identifiers[instr->initstring.offset].identifier) {
1559             quint32 len = *(quint32 *)(data + instr->initstring.dataIdx);
1560             QChar *strdata = (QChar *)(data + instr->initstring.dataIdx + sizeof(quint32));
1561 
1562             QString str = QString::fromRawData(strdata, len);
1563 
1564             identifiers[instr->initstring.offset] = engine->objectClass->createPersistentIdentifier(str);
1565         }
1566     QML_END_INSTR(InitString)
1567 
1568     QML_BEGIN_INSTR(FindGenericTerminal)
1569         // We start the search in the parent context, as we know that the
1570         // name is not present in the current context or it would have been
1571         // found during the static compile
1572         findgeneric(registers + instr->find.reg, instr->find.subscribeIndex,
1573                     context->parent,
1574                     identifiers[instr->find.name].identifier,
1575                     instr->common.type == Instr::FindGenericTerminal);
1576     QML_END_INSTR(FindGenericTerminal)
1577 
1578     QML_BEGIN_INSTR(FindGeneric)
1579         // We start the search in the parent context, as we know that the
1580         // name is not present in the current context or it would have been
1581         // found during the static compile
1582         findgeneric(registers + instr->find.reg, instr->find.subscribeIndex,
1583                     context->parent,
1584                     identifiers[instr->find.name].identifier,
1585                     instr->common.type == Instr::FindGenericTerminal);
1586     QML_END_INSTR(FindGeneric)
1587 
1588     QML_BEGIN_INSTR(FindPropertyTerminal)
1589     {
1590         const Register &object = registers[instr->find.src];
1591         if (object.isUndefined()) {
1592             throwException(instr->find.exceptionId, error, program, context);
1593             return;
1594         }
1595 
1596         findproperty(object.getQObject(), registers + instr->find.reg,
1597                      QDeclarativeEnginePrivate::get(context->engine),
1598                      instr->find.subscribeIndex, identifiers[instr->find.name].identifier,
1599                      instr->common.type == Instr::FindPropertyTerminal);
1600     }
1601     QML_END_INSTR(FindPropertyTerminal)
1602 
1603     QML_BEGIN_INSTR(FindProperty)
1604     {
1605         const Register &object = registers[instr->find.src];
1606         if (object.isUndefined()) {
1607             throwException(instr->find.exceptionId, error, program, context);
1608             return;
1609         }
1610 
1611         findproperty(object.getQObject(), registers + instr->find.reg,
1612                      QDeclarativeEnginePrivate::get(context->engine),
1613                      instr->find.subscribeIndex, identifiers[instr->find.name].identifier,
1614                      instr->common.type == Instr::FindPropertyTerminal);
1615     }
1616     QML_END_INSTR(FindProperty)
1617 
1618     QML_BEGIN_INSTR(CleanupGeneric)
1619     {
1620         int type = registers[instr->cleanup.reg].gettype();
1621         if (type == qMetaTypeId<QVariant>()) {
1622             registers[instr->cleanup.reg].getvariantptr()->~QVariant();
1623 #ifdef REGISTER_CLEANUP_DEBUG
1624         registers[instr->cleanup.reg].setUndefined();
1625 #endif
1626         } else if (type == QMetaType::QString) {
1627             registers[instr->cleanup.reg].getstringptr()->~QString();
1628 #ifdef REGISTER_CLEANUP_DEBUG
1629         registers[instr->cleanup.reg].setUndefined();
1630 #endif
1631         } else if (type == QMetaType::QUrl) {
1632             registers[instr->cleanup.reg].geturlptr()->~QUrl();
1633 #ifdef REGISTER_CLEANUP_DEBUG
1634         registers[instr->cleanup.reg].setUndefined();
1635 #endif
1636         }
1637     }
1638     QML_END_INSTR(CleanupGeneric)
1639 
1640     QML_BEGIN_INSTR(ConvertGenericToReal)
1641     {
1642         Register &output = registers[instr->unaryop.output];
1643         Register &input = registers[instr->unaryop.src];
1644         bool ok = true;
1645         output.setqreal(toReal(&input, input.gettype(), &ok));
1646         if (!ok) output.setUndefined();
1647     }
1648     QML_END_INSTR(ConvertGenericToReal)
1649 
1650     QML_BEGIN_INSTR(ConvertGenericToBool)
1651     {
1652         Register &output = registers[instr->unaryop.output];
1653         Register &input = registers[instr->unaryop.src];
1654         bool ok = true;
1655         output.setbool(toBool(&input, input.gettype(), &ok));
1656         if (!ok) output.setUndefined();
1657     }
1658     QML_END_INSTR(ConvertGenericToBool)
1659 
1660     QML_BEGIN_INSTR(ConvertGenericToString)
1661     {
1662         Register &output = registers[instr->unaryop.output];
1663         Register &input = registers[instr->unaryop.src];
1664         bool ok = true;
1665         QString str = toString(&input, input.gettype(), &ok);
1666         if (ok) { new (output.getstringptr()) QString(str); output.settype(QMetaType::QString); }
1667         else { output.setUndefined(); }
1668     }
1669     QML_END_INSTR(ConvertGenericToString)
1670 
1671     QML_BEGIN_INSTR(ConvertGenericToUrl)
1672     {
1673         Register &output = registers[instr->unaryop.output];
1674         Register &input = registers[instr->unaryop.src];
1675         bool ok = true;
1676         QUrl url = toUrl(&input, input.gettype(), context, &ok);
1677         if (ok) { new (output.geturlptr()) QUrl(url); output.settype(QMetaType::QUrl); }
1678         else { output.setUndefined(); }
1679     }
1680     QML_END_INSTR(ConvertGenericToUrl)
1681 
1682 #ifdef QML_THREADED_INTERPRETER
1683     // nothing to do
1684 #else
1685     default:
1686         qFatal("EEK");
1687         break;
1688     } // switch
1689 
1690     ++instr;
1691     } // while
1692 #endif
1693 }
1694 
1695 void QDeclarativeBindingCompiler::dump(const QByteArray &programData)
1696 {
1697     const Program *program = (const Program *)programData.constData();
1698 
1699     qWarning() << "Program.bindings:" << program->bindings;
1700     qWarning() << "Program.dataLength:" << program->dataLength;
1701     qWarning() << "Program.subscriptions:" << program->subscriptions;
1702     qWarning() << "Program.indentifiers:" << program->identifiers;
1703 
1704     int count = program->instructionCount;
1705     const Instr *instr = program->instructions();
1706 
1707     while (count--) {
1708 
1709         dumpInstruction(instr);
1710         ++instr;
1711     }
1712 }
1713 
1714 /*!
1715 Clear the state associated with attempting to compile a specific binding.
1716 This does not clear the global "committed binding" states.
1717 */
1718 void QDeclarativeBindingCompilerPrivate::resetInstanceState()
1719 {
1720     registers = 0;
1721     registerCleanups.clear();
1722     data = committed.data;
1723     exceptions = committed.exceptions;
1724     usedSubscriptionIds.clear();
1725     subscriptionSet.clear();
1726     subscriptionIds = committed.subscriptionIds;
1727     registeredStrings = committed.registeredStrings;
1728     bytecode.clear();
1729 }
1730 
1731 /*!
1732 Mark the last compile as successful, and add it to the "committed data"
1733 section.
1734 
1735 Returns the index for the committed binding.
1736 */
1737 int QDeclarativeBindingCompilerPrivate::commitCompile()
1738 {
1739     int rv = committed.count();
1740     committed.offsets << committed.bytecode.count();
1741     committed.dependencies << usedSubscriptionIds;
1742     committed.bytecode << bytecode;
1743     committed.data = data;
1744     committed.exceptions = exceptions;
1745     committed.subscriptionIds = subscriptionIds;
1746     committed.registeredStrings = registeredStrings;
1747     return rv;
1748 }
1749 
1750 bool QDeclarativeBindingCompilerPrivate::compile(QDeclarativeJS::AST::Node *node)
1751 {
1752     resetInstanceState();
1753 
1754     if (destination->type == -1)
1755         return false;
1756 
1757     if (bindingsDump()) {
1758         QDeclarativeJS::AST::ExpressionNode *n = node->expressionCast();
1759         if (n) {
1760             Instr id;
1761             id.common.type = Instr::BindingId;
1762             id.id.column = n->firstSourceLocation().startColumn;
1763             id.id.line = n->firstSourceLocation().startLine;
1764             bytecode << id;
1765         }
1766     }
1767 
1768     Result type;
1769 
1770     if (!parseExpression(node, type))
1771         return false;
1772 
1773     if (subscriptionSet.count() > 0xFFFF ||
1774             registeredStrings.count() > 0xFFFF)
1775         return false;
1776 
1777     if (type.unknownType) {
1778         if (!qmlExperimental())
1779             return false;
1780 
1781         if (destination->type != QMetaType::QReal &&
1782             destination->type != QVariant::String &&
1783             destination->type != QMetaType::Bool &&
1784             destination->type != QVariant::Url)
1785             return false;
1786 
1787         int convertReg = acquireReg();
1788         if (convertReg == -1)
1789             return false;
1790 
1791         if (destination->type == QMetaType::QReal) {
1792             Instr convert;
1793             convert.common.type = Instr::ConvertGenericToReal;
1794             convert.unaryop.output = convertReg;
1795             convert.unaryop.src = type.reg;
1796             bytecode << convert;
1797         } else if (destination->type == QVariant::String) {
1798             Instr convert;
1799             convert.common.type = Instr::ConvertGenericToString;
1800             convert.unaryop.output = convertReg;
1801             convert.unaryop.src = type.reg;
1802             bytecode << convert;
1803         } else if (destination->type == QMetaType::Bool) {
1804             Instr convert;
1805             convert.common.type = Instr::ConvertGenericToBool;
1806             convert.unaryop.output = convertReg;
1807             convert.unaryop.src = type.reg;
1808             bytecode << convert;
1809         } else if (destination->type == QVariant::Url) {
1810             Instr convert;
1811             convert.common.type = Instr::ConvertGenericToUrl;
1812             convert.unaryop.output = convertReg;
1813             convert.unaryop.src = type.reg;
1814             bytecode << convert;
1815         }
1816 
1817         Instr cleanup;
1818         cleanup.common.type = Instr::CleanupGeneric;
1819         cleanup.cleanup.reg = type.reg;
1820         bytecode << cleanup;
1821 
1822         Instr instr;
1823         instr.common.type = Instr::Store;
1824         instr.store.output = 0;
1825         instr.store.index = destination->index;
1826         instr.store.reg = convertReg;
1827         instr.store.exceptionId = exceptionId(node->expressionCast());
1828         bytecode << instr;
1829 
1830         if (destination->type == QVariant::String) {
1831             Instr cleanup;
1832             cleanup.common.type = Instr::CleanupString;
1833             cleanup.cleanup.reg = convertReg;
1834             bytecode << cleanup;
1835         } else if (destination->type == QVariant::Url) {
1836             Instr cleanup;
1837             cleanup.common.type = Instr::CleanupUrl;
1838             cleanup.cleanup.reg = convertReg;
1839             bytecode << cleanup;
1840         }
1841 
1842         releaseReg(convertReg);
1843 
1844         Instr done;
1845         done.common.type = Instr::Done;
1846         bytecode << done;
1847 
1848     } else {
1849         // Can we store the final value?
1850         if (type.type == QVariant::Int &&
1851             destination->type == QMetaType::QReal) {
1852             Instr instr;
1853             instr.common.type = Instr::ConvertIntToReal;
1854             instr.unaryop.output = type.reg;
1855             instr.unaryop.src = type.reg;
1856             bytecode << instr;
1857             type.type = QMetaType::QReal;
1858         } else if (type.type == QMetaType::QReal &&
1859                    destination->type == QVariant::Int) {
1860             Instr instr;
1861             instr.common.type = Instr::ConvertRealToInt;
1862             instr.unaryop.output = type.reg;
1863             instr.unaryop.src = type.reg;
1864             bytecode << instr;
1865             type.type = QVariant::Int;
1866         } else if (type.type == destination->type) {
1867         } else {
1868             const QMetaObject *from = type.metaObject;
1869             const QMetaObject *to = engine->rawMetaObjectForType(destination->type);
1870 
1871             if (QDeclarativePropertyPrivate::canConvert(from, to))
1872                 type.type = destination->type;
1873         }
1874 
1875         if (type.type == destination->type) {
1876             Instr instr;
1877             instr.common.type = Instr::Store;
1878             instr.store.output = 0;
1879             instr.store.index = destination->index;
1880             instr.store.reg = type.reg;
1881             instr.store.exceptionId = exceptionId(node->expressionCast());
1882             bytecode << instr;
1883 
1884             releaseReg(type.reg);
1885 
1886             Instr done;
1887             done.common.type = Instr::Done;
1888             bytecode << done;
1889         } else {
1890             return false;
1891         }
1892     }
1893 
1894     return true;
1895 }
1896 
1897 bool QDeclarativeBindingCompilerPrivate::parseExpression(QDeclarativeJS::AST::Node *node, Result &type)
1898 {
1899     while (node->kind == AST::Node::Kind_NestedExpression)
1900         node = static_cast<AST::NestedExpression *>(node)->expression;
1901 
1902     if (tryArith(node)) {
1903         if (!parseArith(node, type)) return false;
1904     } else if (tryLogic(node)) {
1905         if (!parseLogic(node, type)) return false;
1906     } else if (tryConditional(node)) {
1907         if (!parseConditional(node, type)) return false;
1908     } else if (tryName(node)) {
1909         if (!parseName(node, type)) return false;
1910     } else if (tryConstant(node)) {
1911         if (!parseConstant(node, type)) return false;
1912     } else if (tryMethod(node)) {
1913         if (!parseMethod(node, type)) return false;
1914     } else {
1915         return false;
1916     }
1917     return true;
1918 }
1919 
1920 bool QDeclarativeBindingCompilerPrivate::tryName(QDeclarativeJS::AST::Node *node)
1921 {
1922     return node->kind == AST::Node::Kind_IdentifierExpression ||
1923            node->kind == AST::Node::Kind_FieldMemberExpression;
1924 }
1925 
1926 bool QDeclarativeBindingCompilerPrivate::parseName(AST::Node *node, Result &type)
1927 {
1928     QStringList nameParts;
1929     QList<AST::ExpressionNode *> nameNodes;
1930     if (!buildName(nameParts, node, &nameNodes))
1931         return false;
1932 
1933     int reg = acquireReg();
1934     if (reg == -1)
1935         return false;
1936     type.reg = reg;
1937 
1938     QDeclarativeParser::Object *absType = 0;
1939 
1940     QStringList subscribeName;
1941 
1942     bool wasAttachedObject = false;
1943 
1944     for (int ii = 0; ii < nameParts.count(); ++ii) {
1945         const QString &name = nameParts.at(ii);
1946 
1947         // We don't handle signal properties or attached properties
1948         if (name.length() > 2 && name.startsWith(QLatin1String("on")) &&
1949             name.at(2).isUpper())
1950             return false;
1951 
1952         QDeclarativeType *attachType = 0;
1953         if (name.at(0).isUpper()) {
1954             // Could be an attached property
1955             if (ii == nameParts.count() - 1)
1956                 return false;
1957             if (nameParts.at(ii + 1).at(0).isUpper())
1958                 return false;
1959 
1960             QDeclarativeImportedNamespace *ns = 0;
1961             if (!imports.resolveType(name.toUtf8(), &attachType, 0, 0, 0, &ns))
1962                 return false;
1963             if (ns || !attachType || !attachType->attachedPropertiesType())
1964                 return false;
1965 
1966             wasAttachedObject = true;
1967         }
1968 
1969         if (ii == 0) {
1970 
1971             if (attachType) {
1972                 Instr instr;
1973                 instr.common.type = Instr::LoadScope;
1974                 instr.load.index = 0;
1975                 instr.load.reg = reg;
1976                 bytecode << instr;
1977 
1978                 Instr attach;
1979                 attach.common.type = Instr::LoadAttached;
1980                 attach.attached.output = reg;
1981                 attach.attached.reg = reg;
1982                 attach.attached.id = attachType->attachedPropertiesId();
1983                 attach.attached.exceptionId = exceptionId(nameNodes.at(ii));
1984                 bytecode << attach;
1985 
1986                 subscribeName << contextName();
1987                 subscribeName << QLatin1String("$$$ATTACH_") + name;
1988 
1989                 absType = 0;
1990                 type.metaObject = attachType->attachedPropertiesType();
1991 
1992                 continue;
1993             } else if (ids.contains(name)) {
1994                 QDeclarativeParser::Object *idObject = ids.value(name);
1995                 absType = idObject;
1996                 type.metaObject = absType->metaObject();
1997 
1998                 // We check if the id object is the root or
1999                 // scope object to avoid a subscription
2000                 if (idObject == component) {
2001                     Instr instr;
2002                     instr.common.type = Instr::LoadRoot;
2003                     instr.load.index = 0;
2004                     instr.load.reg = reg;
2005                     bytecode << instr;
2006                 } else if (idObject == context) {
2007                     Instr instr;
2008                     instr.common.type = Instr::LoadScope;
2009                     instr.load.index = 0;
2010                     instr.load.reg = reg;
2011                     bytecode << instr;
2012                 } else {
2013                     Instr instr;
2014                     instr.common.type = Instr::LoadId;
2015                     instr.load.index = idObject->idIndex;
2016                     instr.load.reg = reg;
2017                     bytecode << instr;
2018 
2019                     subscribeName << QLatin1String("$$$ID_") + name;
2020 
2021                     if (subscription(subscribeName, &type)) {
2022                         Instr sub;
2023                         sub.common.type = Instr::SubscribeId;
2024                         sub.subscribe.offset = subscriptionIndex(subscribeName);
2025                         sub.subscribe.reg = reg;
2026                         sub.subscribe.index = instr.load.index;
2027                         bytecode << sub;
2028                     }
2029                 }
2030 
2031             } else {
2032 
2033                 QByteArray utf8Name = name.toUtf8();
2034                 const char *cname = utf8Name.constData();
2035 
2036                 int d0Idx = (context == component)?-1:context->metaObject()->indexOfProperty(cname);
2037                 int d1Idx = -1;
2038                 if (d0Idx == -1)
2039                     d1Idx = component->metaObject()->indexOfProperty(cname);
2040 
2041                 if (d0Idx != -1) {
2042                     Instr instr;
2043                     instr.common.type = Instr::LoadScope;
2044                     instr.load.index = 0;
2045                     instr.load.reg = reg;
2046                     bytecode << instr;
2047 
2048                     subscribeName << contextName();
2049                     subscribeName << name;
2050 
2051                     if (!fetch(type, context->metaObject(), reg, d0Idx, subscribeName, nameNodes.at(ii)))
2052                         return false;
2053                 } else if(d1Idx != -1) {
2054                     Instr instr;
2055                     instr.common.type = Instr::LoadRoot;
2056                     instr.load.index = 0;
2057                     instr.load.reg = reg;
2058                     bytecode << instr;
2059 
2060                     subscribeName << QLatin1String("$$$ROOT");
2061                     subscribeName << name;
2062 
2063                     if (!fetch(type, component->metaObject(), reg, d1Idx, subscribeName, nameNodes.at(ii)))
2064                         return false;
2065                 } else if (qmlExperimental()) {
2066                     Instr find;
2067                     if (nameParts.count() == 1)
2068                         find.common.type = Instr::FindGenericTerminal;
2069                     else
2070                         find.common.type = Instr::FindGeneric;
2071 
2072                     find.find.reg = reg;
2073                     find.find.src = -1;
2074                     find.find.name = registerString(name);
2075                     find.find.exceptionId = exceptionId(nameNodes.at(ii));
2076 
2077                     subscribeName << QString(QLatin1String("$$$Generic_") + name);
2078                     if (subscription(subscribeName, &type))
2079                         find.find.subscribeIndex = subscriptionIndex(subscribeName);
2080                     else
2081                         find.find.subscribeIndex = -1;
2082 
2083                     bytecode << find;
2084                     type.unknownType = true;
2085                 }
2086 
2087                 if (!type.unknownType && type.type == -1)
2088                     return false; // Couldn't fetch that type
2089             }
2090 
2091         } else {
2092 
2093             if (attachType) {
2094                 Instr attach;
2095                 attach.common.type = Instr::LoadAttached;
2096                 attach.attached.output = reg;
2097                 attach.attached.reg = reg;
2098                 attach.attached.id = attachType->attachedPropertiesId();
2099                 bytecode << attach;
2100 
2101                 absType = 0;
2102                 type.metaObject = attachType->attachedPropertiesType();
2103 
2104                 subscribeName << QLatin1String("$$$ATTACH_") + name;
2105                 continue;
2106             }
2107 
2108             const QMetaObject *mo = 0;
2109             if (absType)
2110                 mo = absType->metaObject();
2111             else if (type.metaObject)
2112                 mo = type.metaObject;
2113 
2114             QByteArray utf8Name = name.toUtf8();
2115             const char *cname = utf8Name.constData();
2116             int idx = mo?mo->indexOfProperty(cname):-1;
2117             if (absType && idx == -1)
2118                 return false;
2119 
2120             subscribeName << name;
2121 
2122             if (absType || (wasAttachedObject && idx != -1) || (mo && mo->property(idx).isFinal())) {
2123                 absType = 0;
2124                 if (!fetch(type, mo, reg, idx, subscribeName, nameNodes.at(ii)))
2125                     return false;
2126             } else {
2127 
2128                 Instr prop;
2129                 if (ii == nameParts.count() -1 )
2130                     prop.common.type = Instr::FindPropertyTerminal;
2131                 else
2132                     prop.common.type = Instr::FindProperty;
2133 
2134                 prop.find.reg = reg;
2135                 prop.find.src = reg;
2136                 prop.find.name = registerString(name);
2137                 prop.find.exceptionId = exceptionId(nameNodes.at(ii));
2138 
2139                 if (subscription(subscribeName, &type))
2140                     prop.find.subscribeIndex = subscriptionIndex(subscribeName);
2141                 else
2142                     prop.find.subscribeIndex = -1;
2143 
2144                 type.unknownType = true;
2145                 type.metaObject = 0;
2146                 type.type = -1;
2147                 type.reg = reg;
2148                 bytecode << prop;
2149             }
2150         }
2151 
2152         wasAttachedObject = false;
2153     }
2154 
2155     return true;
2156 }
2157 
2158 bool QDeclarativeBindingCompilerPrivate::tryArith(QDeclarativeJS::AST::Node *node)
2159 {
2160     if (node->kind != AST::Node::Kind_BinaryExpression)
2161         return false;
2162 
2163     AST::BinaryExpression *expression = static_cast<AST::BinaryExpression *>(node);
2164     if (expression->op == QSOperator::Add ||
2165         expression->op == QSOperator::Sub)
2166         return true;
2167     else
2168         return false;
2169 }
2170 
2171 bool QDeclarativeBindingCompilerPrivate::parseArith(QDeclarativeJS::AST::Node *node, Result &type)
2172 {
2173     AST::BinaryExpression *expression = static_cast<AST::BinaryExpression *>(node);
2174 
2175     type.reg = acquireReg();
2176     if (type.reg == -1)
2177         return false;
2178 
2179     Result lhs;
2180     Result rhs;
2181 
2182     if (!parseExpression(expression->left, lhs)) return false;
2183     if (!parseExpression(expression->right, rhs)) return false;
2184 
2185     if ((lhs.type == QVariant::Int || lhs.type == QMetaType::QReal) &&
2186         (rhs.type == QVariant::Int || rhs.type == QMetaType::QReal))
2187         return numberArith(type, lhs, rhs, (QSOperator::Op)expression->op);
2188     else if(expression->op == QSOperator::Sub)
2189         return numberArith(type, lhs, rhs, (QSOperator::Op)expression->op);
2190     else if ((lhs.type == QMetaType::QString || lhs.unknownType) &&
2191              (rhs.type == QMetaType::QString || rhs.unknownType) &&
2192              (lhs.type == QMetaType::QString || rhs.type == QMetaType::QString))
2193         return stringArith(type, lhs, rhs, (QSOperator::Op)expression->op);
2194     else
2195         return false;
2196 }
2197 
2198 bool QDeclarativeBindingCompilerPrivate::numberArith(Result &type, const Result &lhs, const Result &rhs, QSOperator::Op op)
2199 {
2200     bool nativeReal = rhs.type == QMetaType::QReal ||
2201                       lhs.type == QMetaType::QReal ||
2202                       lhs.unknownType ||
2203                       rhs.unknownType;
2204 
2205     if (nativeReal && lhs.type == QMetaType::Int) {
2206         Instr convert;
2207         convert.common.type = Instr::ConvertIntToReal;
2208         convert.unaryop.output = lhs.reg;
2209         convert.unaryop.src = lhs.reg;
2210         bytecode << convert;
2211     }
2212 
2213     if (nativeReal && rhs.type == QMetaType::Int) {
2214         Instr convert;
2215         convert.common.type = Instr::ConvertIntToReal;
2216         convert.unaryop.output = rhs.reg;
2217         convert.unaryop.src = rhs.reg;
2218         bytecode << convert;
2219     }
2220 
2221     int lhsTmp = -1;
2222     int rhsTmp = -1;
2223 
2224     if (lhs.unknownType) {
2225         if (!qmlExperimental())
2226             return false;
2227 
2228         lhsTmp = acquireReg();
2229         if (lhsTmp == -1)
2230             return false;
2231 
2232         Instr conv;
2233         conv.common.type = Instr::ConvertGenericToReal;
2234         conv.unaryop.output = lhsTmp;
2235         conv.unaryop.src = lhs.reg;
2236         bytecode << conv;
2237     }
2238 
2239     if (rhs.unknownType) {
2240         if (!qmlExperimental())
2241             return false;
2242 
2243         rhsTmp = acquireReg();
2244         if (rhsTmp == -1)
2245             return false;
2246 
2247         Instr conv;
2248         conv.common.type = Instr::ConvertGenericToReal;
2249         conv.unaryop.output = rhsTmp;
2250         conv.unaryop.src = rhs.reg;
2251         bytecode << conv;
2252     }
2253 
2254     Instr arith;
2255     if (op == QSOperator::Add) {
2256         arith.common.type = nativeReal?Instr::AddReal:Instr::AddInt;
2257     } else if (op == QSOperator::Sub) {
2258         arith.common.type = nativeReal?Instr::MinusReal:Instr::MinusInt;
2259     } else {
2260         qFatal("Unsupported arithmetic operator");
2261     }
2262 
2263     arith.binaryop.output = type.reg;
2264     arith.binaryop.src1 = (lhsTmp == -1)?lhs.reg:lhsTmp;
2265     arith.binaryop.src2 = (rhsTmp == -1)?rhs.reg:rhsTmp;
2266     bytecode << arith;
2267 
2268     type.metaObject = 0;
2269     type.type = nativeReal?QMetaType::QReal:QMetaType::Int;
2270     type.subscriptionSet.unite(lhs.subscriptionSet);
2271     type.subscriptionSet.unite(rhs.subscriptionSet);
2272 
2273     if (lhsTmp != -1) releaseReg(lhsTmp);
2274     if (rhsTmp != -1) releaseReg(rhsTmp);
2275     releaseReg(lhs.reg);
2276     releaseReg(rhs.reg);
2277 
2278     return true;
2279 }
2280 
2281 bool QDeclarativeBindingCompilerPrivate::stringArith(Result &type, const Result &lhs, const Result &rhs, QSOperator::Op op)
2282 {
2283     if (op != QSOperator::Add)
2284         return false;
2285 
2286     int lhsTmp = -1;
2287     int rhsTmp = -1;
2288 
2289     if (lhs.unknownType) {
2290         if (!qmlExperimental())
2291             return false;
2292 
2293         lhsTmp = acquireReg(Instr::CleanupString);
2294         if (lhsTmp == -1)
2295             return false;
2296 
2297         Instr convert;
2298         convert.common.type = Instr::ConvertGenericToString;
2299         convert.unaryop.output = lhsTmp;
2300         convert.unaryop.src = lhs.reg;
2301         bytecode << convert;
2302     }
2303 
2304     if (rhs.unknownType) {
2305         if (!qmlExperimental())
2306             return false;
2307 
2308         rhsTmp = acquireReg(Instr::CleanupString);
2309         if (rhsTmp == -1)
2310             return false;
2311 
2312         Instr convert;
2313         convert.common.type = Instr::ConvertGenericToString;
2314         convert.unaryop.output = rhsTmp;
2315         convert.unaryop.src = rhs.reg;
2316         bytecode << convert;
2317     }
2318 
2319     type.reg = acquireReg(Instr::CleanupString);
2320     if (type.reg == -1)
2321         return false;
2322 
2323     type.type = QMetaType::QString;
2324 
2325     Instr add;
2326     add.common.type = Instr::AddString;
2327     add.binaryop.output = type.reg;
2328     add.binaryop.src1 = (lhsTmp == -1)?lhs.reg:lhsTmp;
2329     add.binaryop.src2 = (rhsTmp == -1)?rhs.reg:rhsTmp;
2330     bytecode << add;
2331 
2332     if (lhsTmp != -1) releaseReg(lhsTmp);
2333     if (rhsTmp != -1) releaseReg(rhsTmp);
2334     releaseReg(lhs.reg);
2335     releaseReg(rhs.reg);
2336 
2337     return true;
2338 }
2339 
2340 bool QDeclarativeBindingCompilerPrivate::tryLogic(QDeclarativeJS::AST::Node *node)
2341 {
2342     if (node->kind != AST::Node::Kind_BinaryExpression)
2343         return false;
2344 
2345     AST::BinaryExpression *expression = static_cast<AST::BinaryExpression *>(node);
2346     if (expression->op == QSOperator::Gt ||
2347         expression->op == QSOperator::Equal ||
2348         expression->op == QSOperator::NotEqual)
2349         return true;
2350     else
2351         return false;
2352 }
2353 
2354 bool QDeclarativeBindingCompilerPrivate::parseLogic(QDeclarativeJS::AST::Node *node, Result &type)
2355 {
2356     AST::BinaryExpression *expression = static_cast<AST::BinaryExpression *>(node);
2357 
2358     Result lhs;
2359     Result rhs;
2360 
2361     if (!parseExpression(expression->left, lhs)) return false;
2362     if (!parseExpression(expression->right, rhs)) return false;
2363 
2364     type.reg = acquireReg();
2365     if (type.reg == -1)
2366         return false;
2367 
2368     type.metaObject = 0;
2369     type.type = QVariant::Bool;
2370 
2371     if (lhs.type == QMetaType::QReal && rhs.type == QMetaType::QReal) {
2372 
2373         Instr op;
2374         if (expression->op == QSOperator::Gt)
2375             op.common.type = Instr::GreaterThanReal;
2376         else if (expression->op == QSOperator::Equal)
2377             op.common.type = Instr::CompareReal;
2378         else if (expression->op == QSOperator::NotEqual)
2379             op.common.type = Instr::NotCompareReal;
2380         else
2381             return false;
2382         op.binaryop.output = type.reg;
2383         op.binaryop.src1 = lhs.reg;
2384         op.binaryop.src2 = rhs.reg;
2385         bytecode << op;
2386 
2387 
2388     } else if (lhs.type == QMetaType::QString && rhs.type == QMetaType::QString) {
2389 
2390         Instr op;
2391         if (expression->op == QSOperator::Equal)
2392             op.common.type = Instr::CompareString;
2393         else if (expression->op == QSOperator::NotEqual)
2394             op.common.type = Instr::NotCompareString;
2395         else
2396             return false;
2397         op.binaryop.output = type.reg;
2398         op.binaryop.src1 = lhs.reg;
2399         op.binaryop.src2 = rhs.reg;
2400         bytecode << op;
2401 
2402     } else {
2403         return false;
2404     }
2405 
2406     releaseReg(lhs.reg);
2407     releaseReg(rhs.reg);
2408 
2409     return true;
2410 }
2411 
2412 bool QDeclarativeBindingCompilerPrivate::tryConditional(QDeclarativeJS::AST::Node *node)
2413 {
2414     return (node->kind == AST::Node::Kind_ConditionalExpression);
2415 }
2416 
2417 bool QDeclarativeBindingCompilerPrivate::parseConditional(QDeclarativeJS::AST::Node *node, Result &type)
2418 {
2419     AST::ConditionalExpression *expression = static_cast<AST::ConditionalExpression *>(node);
2420 
2421     AST::Node *test = expression->expression;
2422     if (test->kind == AST::Node::Kind_NestedExpression)
2423         test = static_cast<AST::NestedExpression*>(test)->expression;
2424 
2425     Result etype;
2426     if (!parseExpression(test, etype)) return false;
2427 
2428     if (etype.type != QVariant::Bool)
2429         return false;
2430 
2431     Instr skip;
2432     skip.common.type = Instr::Skip;
2433     skip.skip.reg = etype.reg;
2434     skip.skip.count = 0;
2435     int skipIdx = bytecode.count();
2436     bytecode << skip;
2437 
2438     // Release to allow reuse of reg
2439     releaseReg(etype.reg);
2440 
2441     QSet<QString> preSubSet = subscriptionSet;
2442 
2443     // int preConditionalSubscriptions = subscriptionSet.count();
2444 
2445     Result ok;
2446     if (!parseExpression(expression->ok, ok)) return false;
2447     if (ok.unknownType) return false;
2448 
2449     int skipIdx2 = bytecode.count();
2450     skip.skip.reg = -1;
2451     bytecode << skip;
2452 
2453     // Release to allow reuse of reg in else path
2454     releaseReg(ok.reg);
2455     bytecode[skipIdx].skip.count = bytecode.count() - skipIdx - 1;
2456 
2457     subscriptionSet = preSubSet;
2458 
2459     Result ko;
2460     if (!parseExpression(expression->ko, ko)) return false;
2461     if (ko.unknownType) return false;
2462 
2463     // Do not release reg here, so that its ownership passes to the caller
2464     bytecode[skipIdx2].skip.count = bytecode.count() - skipIdx2 - 1;
2465 
2466     if (ok != ko)
2467         return false; // Must be same type and in same register
2468 
2469     subscriptionSet = preSubSet;
2470 
2471     if (!subscriptionNeutral(subscriptionSet, ok.subscriptionSet, ko.subscriptionSet))
2472         return false; // Conditionals cannot introduce new subscriptions
2473 
2474     type = ok;
2475 
2476     return true;
2477 }
2478 
2479 bool QDeclarativeBindingCompilerPrivate::tryConstant(QDeclarativeJS::AST::Node *node)
2480 {
2481     return node->kind == AST::Node::Kind_TrueLiteral ||
2482            node->kind == AST::Node::Kind_FalseLiteral ||
2483            node->kind == AST::Node::Kind_NumericLiteral ||
2484            node->kind == AST::Node::Kind_StringLiteral;
2485 }
2486 
2487 bool QDeclarativeBindingCompilerPrivate::parseConstant(QDeclarativeJS::AST::Node *node, Result &type)
2488 {
2489     type.metaObject = 0;
2490     type.type = -1;
2491     type.reg = acquireReg();
2492     if (type.reg == -1)
2493         return false;
2494 
2495     if (node->kind == AST::Node::Kind_TrueLiteral) {
2496         type.type = QVariant::Bool;
2497         Instr instr;
2498         instr.common.type = Instr::Bool;
2499         instr.bool_value.reg = type.reg;
2500         instr.bool_value.value = true;
2501         bytecode << instr;
2502         return true;
2503     } else if (node->kind == AST::Node::Kind_FalseLiteral) {
2504         type.type = QVariant::Bool;
2505         Instr instr;
2506         instr.common.type = Instr::Bool;
2507         instr.bool_value.reg = type.reg;
2508         instr.bool_value.value = false;
2509         bytecode << instr;
2510         return true;
2511     } else if (node->kind == AST::Node::Kind_NumericLiteral) {
2512         qreal value = qreal(static_cast<AST::NumericLiteral *>(node)->value);
2513 
2514         if (qreal(float(value)) != value)
2515             return false;
2516 
2517         type.type = QMetaType::QReal;
2518         Instr instr;
2519         instr.common.type = Instr::Real;
2520         instr.real_value.reg = type.reg;
2521         instr.real_value.value = float(value);
2522         bytecode << instr;
2523         return true;
2524     } else if (node->kind == AST::Node::Kind_StringLiteral) {
2525         QString str = static_cast<AST::StringLiteral *>(node)->value->asString();
2526         type.type = QMetaType::QString;
2527         type.reg = registerLiteralString(str);
2528         return true;
2529     } else {
2530         return false;
2531     }
2532 }
2533 
2534 bool QDeclarativeBindingCompilerPrivate::tryMethod(QDeclarativeJS::AST::Node *node)
2535 {
2536     return node->kind == AST::Node::Kind_CallExpression;
2537 }
2538 
2539 bool QDeclarativeBindingCompilerPrivate::parseMethod(QDeclarativeJS::AST::Node *node, Result &result)
2540 {
2541     AST::CallExpression *expr = static_cast<AST::CallExpression *>(node);
2542 
2543     QStringList name;
2544     if (!buildName(name, expr->base))
2545         return false;
2546 
2547     if (name.count() != 2 || name.at(0) != QLatin1String("Math"))
2548         return false;
2549 
2550     QString method = name.at(1);
2551 
2552     AST::ArgumentList *args = expr->arguments;
2553     if (!args) return false;
2554     AST::ExpressionNode *arg0 = args->expression;
2555     args = args->next;
2556     if (!args) return false;
2557     AST::ExpressionNode *arg1 = args->expression;
2558     if (args->next != 0) return false;
2559     if (!arg0 || !arg1) return false;
2560 
2561     Result r0;
2562     if (!parseExpression(arg0, r0)) return false;
2563     Result r1;
2564     if (!parseExpression(arg1, r1)) return false;
2565 
2566     if (r0.type != QMetaType::QReal || r1.type != QMetaType::QReal)
2567         return false;
2568 
2569     Instr op;
2570     if (method == QLatin1String("max")) {
2571         op.common.type = Instr::MaxReal;
2572     } else if (method == QLatin1String("min")) {
2573         op.common.type = Instr::MinReal;
2574     } else {
2575         return false;
2576     }
2577     // We release early to reuse registers
2578     releaseReg(r0.reg);
2579     releaseReg(r1.reg);
2580 
2581     op.binaryop.output = acquireReg();
2582     if (op.binaryop.output == -1)
2583         return false;
2584 
2585     op.binaryop.src1 = r0.reg;
2586     op.binaryop.src2 = r1.reg;
2587     bytecode << op;
2588 
2589     result.type = QMetaType::QReal;
2590     result.reg = op.binaryop.output;
2591 
2592     return true;
2593 }
2594 
2595 bool QDeclarativeBindingCompilerPrivate::buildName(QStringList &name,
2596                                        QDeclarativeJS::AST::Node *node,
2597                                        QList<QDeclarativeJS::AST::ExpressionNode *> *nodes)
2598 {
2599     if (node->kind == AST::Node::Kind_IdentifierExpression) {
2600         name << static_cast<AST::IdentifierExpression*>(node)->name->asString();
2601         if (nodes) *nodes << static_cast<AST::IdentifierExpression*>(node);
2602     } else if (node->kind == AST::Node::Kind_FieldMemberExpression) {
2603         AST::FieldMemberExpression *expr =
2604             static_cast<AST::FieldMemberExpression *>(node);
2605 
2606         if (!buildName(name, expr->base, nodes))
2607             return false;
2608 
2609         name << expr->name->asString();
2610         if (nodes) *nodes << expr;
2611     } else {
2612         return false;
2613     }
2614 
2615     return true;
2616 }
2617 
2618 bool QDeclarativeBindingCompilerPrivate::fetch(Result &rv, const QMetaObject *mo, int reg,
2619                                                int idx, const QStringList &subName,
2620                                                QDeclarativeJS::AST::ExpressionNode *node)
2621 {
2622     QMetaProperty prop = mo->property(idx);
2623     rv.metaObject = 0;
2624     rv.type = 0;
2625 
2626     //XXX binding optimizer doesn't handle properties with a revision
2627     if (prop.revision() > 0)
2628         return false;
2629 
2630     int fastFetchIndex = fastProperties()->accessorIndexForProperty(mo, idx);
2631 
2632     Instr fetch;
2633 
2634     if (!qmlDisableFastProperties() && fastFetchIndex != -1) {
2635         fetch.common.type = Instr::FetchAndSubscribe;
2636         fetch.fetchAndSubscribe.objectReg = reg;
2637         fetch.fetchAndSubscribe.output = reg;
2638         fetch.fetchAndSubscribe.function = fastFetchIndex;
2639         fetch.fetchAndSubscribe.subscription = subscriptionIndex(subName);
2640         fetch.fetchAndSubscribe.exceptionId = exceptionId(node);
2641     } else {
2642         if (subscription(subName, &rv) && prop.hasNotifySignal() && prop.notifySignalIndex() != -1) {
2643             Instr sub;
2644             sub.common.type = Instr::Subscribe;
2645             sub.subscribe.offset = subscriptionIndex(subName);
2646             sub.subscribe.reg = reg;
2647             sub.subscribe.index = prop.notifySignalIndex();
2648             bytecode << sub;
2649         }
2650 
2651         fetch.common.type = Instr::Fetch;
2652         fetch.fetch.objectReg = reg;
2653         fetch.fetch.index = idx;
2654         fetch.fetch.output = reg;
2655         fetch.fetch.exceptionId = exceptionId(node);
2656     }
2657 
2658     rv.type = prop.userType();
2659     rv.metaObject = engine->metaObjectForType(rv.type);
2660     rv.reg = reg;
2661 
2662     if (rv.type == QMetaType::QString) {
2663         int tmp = acquireReg();
2664         if (tmp == -1)
2665             return false;
2666         Instr copy;
2667         copy.common.type = Instr::Copy;
2668         copy.copy.reg = tmp;
2669         copy.copy.src = reg;
2670         bytecode << copy;
2671         releaseReg(tmp);
2672         fetch.fetch.objectReg = tmp;
2673 
2674         Instr setup;
2675         setup.common.type = Instr::NewString;
2676         setup.construct.reg = reg;
2677         bytecode << setup;
2678         registerCleanup(reg, Instr::CleanupString);
2679     }
2680 
2681     bytecode << fetch;
2682 
2683     if (!rv.metaObject &&
2684         rv.type != QMetaType::QReal &&
2685         rv.type != QMetaType::Int &&
2686         rv.type != QMetaType::Bool &&
2687         rv.type != qMetaTypeId<QDeclarativeAnchorLine>() &&
2688         rv.type != QMetaType::QString) {
2689         rv.metaObject = 0;
2690         rv.type = 0;
2691         return false; // Unsupported type (string not supported yet);
2692     }
2693 
2694     return true;
2695 }
2696 
2697 void QDeclarativeBindingCompilerPrivate::registerCleanup(int reg, int cleanup, int cleanupType)
2698 {
2699     registerCleanups.insert(reg, qMakePair(cleanup, cleanupType));
2700 }
2701 
2702 int QDeclarativeBindingCompilerPrivate::acquireReg(int cleanup, int cleanupType)
2703 {
2704     for (int ii = 0; ii < 32; ++ii) {
2705         if (!(registers & (1 << ii))) {
2706             registers |= (1 << ii);
2707 
2708             if (cleanup != Instr::Noop)
2709                 registerCleanup(ii, cleanup, cleanupType);
2710 
2711             return ii;
2712         }
2713     }
2714     return -1;
2715 }
2716 
2717 void QDeclarativeBindingCompilerPrivate::releaseReg(int reg)
2718 {
2719     Q_ASSERT(reg >= 0 && reg <= 31);
2720 
2721     if (registerCleanups.contains(reg)) {
2722         QPair<int, int> c = registerCleanups[reg];
2723         registerCleanups.remove(reg);
2724         Instr cleanup;
2725         cleanup.common.type = (quint8)c.first;
2726         cleanup.cleanup.reg = reg;
2727         bytecode << cleanup;
2728     }
2729 
2730     quint32 mask = 1 << reg;
2731     registers &= ~mask;
2732 }
2733 
2734 // Returns a reg
2735 int QDeclarativeBindingCompilerPrivate::registerLiteralString(const QString &str)
2736 {
2737     QByteArray strdata((const char *)str.constData(), str.length() * sizeof(QChar));
2738     int offset = data.count();
2739     data += strdata;
2740 
2741     int reg = acquireReg(Instr::CleanupString);
2742     if (reg == -1)
2743         return false;
2744 
2745     Instr string;
2746     string.common.type = Instr::String;
2747     string.string_value.reg = reg;
2748     string.string_value.offset = offset;
2749     string.string_value.length = str.length();
2750     bytecode << string;
2751 
2752     return reg;
2753 }
2754 
2755 // Returns an identifier offset
2756 int QDeclarativeBindingCompilerPrivate::registerString(const QString &string)
2757 {
2758     Q_ASSERT(!string.isEmpty());
2759 
2760     QHash<QString, QPair<int, int> >::ConstIterator iter = registeredStrings.find(string);
2761 
2762     if (iter == registeredStrings.end()) {
2763         quint32 len = string.length();
2764         QByteArray lendata((const char *)&len, sizeof(quint32));
2765         QByteArray strdata((const char *)string.constData(), string.length() * sizeof(QChar));
2766         strdata.prepend(lendata);
2767         int rv = data.count();
2768         data += strdata;
2769 
2770         iter = registeredStrings.insert(string, qMakePair(registeredStrings.count(), rv));
2771     }
2772 
2773     Instr reg;
2774     reg.common.type = Instr::InitString;
2775     reg.initstring.offset = iter->first;
2776     reg.initstring.dataIdx = iter->second;
2777     bytecode << reg;
2778     return reg.initstring.offset;
2779 }
2780 
2781 bool QDeclarativeBindingCompilerPrivate::subscription(const QStringList &sub, Result *result)
2782 {
2783     QString str = sub.join(QLatin1String("."));
2784     result->subscriptionSet.insert(str);
2785 
2786     if (subscriptionSet.contains(str)) {
2787         return false;
2788     } else {
2789         subscriptionSet.insert(str);
2790         return true;
2791     }
2792 }
2793 
2794 int QDeclarativeBindingCompilerPrivate::subscriptionIndex(const QStringList &sub)
2795 {
2796     QString str = sub.join(QLatin1String("."));
2797     QHash<QString, int>::ConstIterator iter = subscriptionIds.find(str);
2798     if (iter == subscriptionIds.end())
2799         iter = subscriptionIds.insert(str, subscriptionIds.count());
2800     usedSubscriptionIds.insert(*iter);
2801     return *iter;
2802 }
2803 
2804 /*
2805     Returns true if lhs contains no subscriptions that aren't also in base or rhs AND
2806     rhs contains no subscriptions that aren't also in base or lhs.
2807 */
2808 bool QDeclarativeBindingCompilerPrivate::subscriptionNeutral(const QSet<QString> &base,
2809                                              const QSet<QString> &lhs,
2810                                              const QSet<QString> &rhs)
2811 {
2812     QSet<QString> difflhs = lhs;
2813     difflhs.subtract(rhs);
2814     QSet<QString> diffrhs = rhs;
2815     diffrhs.subtract(lhs);
2816 
2817     difflhs.unite(diffrhs);
2818     difflhs.subtract(base);
2819 
2820     return difflhs.isEmpty();
2821 }
2822 
2823 quint8 QDeclarativeBindingCompilerPrivate::exceptionId(QDeclarativeJS::AST::ExpressionNode *n)
2824 {
2825     quint8 rv = 0xFF;
2826     if (n && exceptions.count() < 0xFF) {
2827         rv = (quint8)exceptions.count();
2828         QDeclarativeJS::AST::SourceLocation l = n->firstSourceLocation();
2829         quint64 e = l.startLine;
2830         e <<= 32;
2831         e |= l.startColumn;
2832         exceptions.append(e);
2833     }
2834     return rv;
2835 }
2836 
2837 QDeclarativeBindingCompiler::QDeclarativeBindingCompiler()
2838 : d(new QDeclarativeBindingCompilerPrivate)
2839 {
2840 }
2841 
2842 QDeclarativeBindingCompiler::~QDeclarativeBindingCompiler()
2843 {
2844     delete d; d = 0;
2845 }
2846 
2847 /*
2848 Returns true if any bindings were compiled.
2849 */
2850 bool QDeclarativeBindingCompiler::isValid() const
2851 {
2852     return !d->committed.bytecode.isEmpty();
2853 }
2854 
2855 /*
2856 -1 on failure, otherwise the binding index to use.
2857 */
2858 int QDeclarativeBindingCompiler::compile(const Expression &expression, QDeclarativeEnginePrivate *engine)
2859 {
2860     if (!expression.expression.asAST()) return false;
2861 
2862     if (!qmlExperimental() && expression.property->isValueTypeSubProperty)
2863         return -1;
2864 
2865     if (qmlDisableOptimizer())
2866         return -1;
2867 
2868     d->context = expression.context;
2869     d->component = expression.component;
2870     d->destination = expression.property;
2871     d->ids = expression.ids;
2872     d->imports = expression.imports;
2873     d->engine = engine;
2874 
2875     if (d->compile(expression.expression.asAST())) {
2876         return d->commitCompile();
2877     } else {
2878         return -1;
2879     }
2880 }
2881 
2882 
2883 QByteArray QDeclarativeBindingCompilerPrivate::buildSignalTable() const
2884 {
2885     QHash<int, QList<int> > table;
2886 
2887     for (int ii = 0; ii < committed.count(); ++ii) {
2888         const QSet<int> &deps = committed.dependencies.at(ii);
2889         for (QSet<int>::ConstIterator iter = deps.begin(); iter != deps.end(); ++iter)
2890             table[*iter].append(ii);
2891     }
2892 
2893     QVector<quint32> header;
2894     QVector<quint32> data;
2895     for (int ii = 0; ii < committed.subscriptionIds.count(); ++ii) {
2896         header.append(committed.subscriptionIds.count() + data.count());
2897         const QList<int> &bindings = table[ii];
2898         data.append(bindings.count());
2899         for (int jj = 0; jj < bindings.count(); ++jj)
2900             data.append(bindings.at(jj));
2901     }
2902     header << data;
2903 
2904     return QByteArray((const char *)header.constData(), header.count() * sizeof(quint32));
2905 }
2906 
2907 QByteArray QDeclarativeBindingCompilerPrivate::buildExceptionData() const
2908 {
2909     QByteArray rv;
2910     rv.resize(committed.exceptions.count() * sizeof(quint64));
2911     ::memcpy(rv.data(), committed.exceptions.constData(), rv.size());
2912     return rv;
2913 }
2914 
2915 /*
2916 Returns the compiled program.
2917 */
2918 QByteArray QDeclarativeBindingCompiler::program() const
2919 {
2920     QByteArray programData;
2921 
2922     if (isValid()) {
2923         Program prog;
2924         prog.bindings = d->committed.count();
2925 
2926         QVector<Instr> bytecode;
2927         Instr skip;
2928         skip.common.type = Instr::Skip;
2929         skip.skip.reg = -1;
2930         for (int ii = 0; ii < d->committed.count(); ++ii) {
2931             skip.skip.count = d->committed.count() - ii - 1;
2932             skip.skip.count+= d->committed.offsets.at(ii);
2933             bytecode << skip;
2934         }
2935         bytecode << d->committed.bytecode;
2936 
2937         QByteArray data = d->committed.data;
2938         while (data.count() % 4) data.append('\0');
2939         prog.signalTableOffset = data.count();
2940         data += d->buildSignalTable();
2941         while (data.count() % 4) data.append('\0');
2942         prog.exceptionDataOffset = data.count();
2943         data += d->buildExceptionData();
2944 
2945         prog.dataLength = 4 * ((data.size() + 3) / 4);
2946         prog.subscriptions = d->committed.subscriptionIds.count();
2947         prog.identifiers = d->committed.registeredStrings.count();
2948         prog.instructionCount = bytecode.count();
2949         prog.compiled = false;
2950         int size = sizeof(Program) + bytecode.count() * sizeof(Instr);
2951         size += prog.dataLength;
2952 
2953         programData.resize(size);
2954         memcpy(programData.data(), &prog, sizeof(Program));
2955         if (prog.dataLength)
2956             memcpy((char *)((Program *)programData.data())->data(), data.constData(),
2957                    data.size());
2958         memcpy((char *)((Program *)programData.data())->instructions(), bytecode.constData(),
2959                bytecode.count() * sizeof(Instr));
2960     }
2961 
2962     return programData;
2963 }
2964 
2965 
2966 
2967 QT_END_NAMESPACE
2968