Support variable length instructions in QML bytecode
[profile/ivi/qtdeclarative.git] / src / declarative / qml / v4 / qdeclarativev4bindings.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
6 **
7 ** This file is part of the QtDeclarative module of the Qt Toolkit.
8 **
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** No Commercial Usage
11 ** This file contains pre-release code and may not be distributed.
12 ** You may use this file in accordance with the terms and conditions
13 ** contained in the Technology Preview License Agreement accompanying
14 ** this package.
15 **
16 ** GNU Lesser General Public License Usage
17 ** Alternatively, this file may be used under the terms of the GNU Lesser
18 ** General Public License version 2.1 as published by the Free Software
19 ** Foundation and appearing in the file LICENSE.LGPL included in the
20 ** packaging of this file.  Please review the following information to
21 ** ensure the GNU Lesser General Public License version 2.1 requirements
22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23 **
24 ** In addition, as a special exception, Nokia gives you certain additional
25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
27 **
28 ** If you have questions regarding the use of this file, please contact
29 ** Nokia at qt-info@nokia.com.
30 **
31 **
32 **
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 // #define REGISTER_CLEANUP_DEBUG
43
44 #include "private/qdeclarativev4bindings_p.h"
45 #include "private/qdeclarativev4program_p.h"
46 #include "private/qdeclarativev4compiler_p.h"
47
48 #include <private/qdeclarativefastproperties_p.h>
49 #include <private/qdeclarativedebugtrace_p.h>
50 #include <private/qdeclarativeanchors_p_p.h> // For AnchorLine
51 #include <private/qsganchors_p_p.h> // For AnchorLine
52
53 #include <QtDeclarative/qdeclarativeinfo.h>
54 #include <QtCore/qnumeric.h>
55 #include <QtCore/qmath.h>
56 #include <math.h> // ::fmod
57
58 QT_BEGIN_NAMESPACE
59
60 using namespace QDeclarativeJS;
61
62 namespace {
63 struct Register {
64     typedef QDeclarativeRegisterType Type;
65
66     void setUndefined() { dataType = UndefinedType; }
67     void setNaN() { setqreal(qSNaN()); }
68     bool isUndefined() const { return dataType == UndefinedType; }
69
70     void setQObject(QObject *o) { *((QObject **)data) = o; dataType = QObjectStarType; }
71     QObject *getQObject() const { return *((QObject **)data); }
72
73     void setqreal(qreal v) { *((qreal *)data) = v; dataType = QRealType; }
74     qreal getqreal() const { return *((qreal *)data); }
75     qreal &getqrealref() const { return *((qreal *)data); }
76
77     void setint(int v) { *((int *)data) = v; dataType = IntType; }
78     int getint() const { return *((int *)data); }
79     int &getintref() const { return *((int *)data); }
80
81     void setbool(bool v) { *((bool *)data) = v; dataType = BoolType; }
82     bool getbool() const { return *((bool *)data); }
83     bool &getboolref() const { return *((bool *)data); }
84
85     QVariant *getvariantptr() { return (QVariant *)typeDataPtr(); }
86     QString *getstringptr() { return (QString *)typeDataPtr(); }
87     QUrl *geturlptr() { return (QUrl *)typeDataPtr(); }
88     const QVariant *getvariantptr() const { return (QVariant *)typeDataPtr(); }
89     const QString *getstringptr() const { return (QString *)typeDataPtr(); }
90     const QUrl *geturlptr() const { return (QUrl *)typeDataPtr(); }
91
92     void *typeDataPtr() { return (void *)&data; }
93     void *typeMemory() { return (void *)data; }
94     const void *typeDataPtr() const { return (void *)&data; }
95     const void *typeMemory() const { return (void *)data; }
96
97     Type gettype() const { return dataType; }
98     void settype(Type t) { dataType = t; }
99
100     // int type;          // Optional type
101
102     Type dataType;     // Type of data
103     void *data[2];     // Object stored here
104
105     inline void cleanup();
106     inline void cleanupString();
107     inline void cleanupUrl();
108     inline void cleanupVariant();
109
110     inline void copy(const Register &other);
111     inline void init(Type type);
112 #ifdef REGISTER_CLEANUP_DEBUG
113     Register() {
114         type = 0;
115     }
116
117     ~Register() {
118         if (dataType >= FirstCleanupType)
119             qWarning("Register leaked of type %d", dataType);
120     }
121 #endif
122 };
123
124 void Register::cleanup()
125 {
126     if (dataType >= FirstCleanupType) {
127         if (dataType == QStringType) {
128             getstringptr()->~QString();
129         } else if (dataType == QUrlType) {
130             geturlptr()->~QUrl();
131         } else if (dataType == QVariantType) {
132             getvariantptr()->~QVariant();
133         }
134     }
135     setUndefined();
136 }
137
138 void Register::cleanupString()
139 {
140     getstringptr()->~QString();
141     setUndefined();
142 }
143
144 void Register::cleanupUrl()
145 {
146     geturlptr()->~QUrl();
147     setUndefined();
148 }
149
150 void Register::cleanupVariant()
151 {
152     getvariantptr()->~QVariant();
153     setUndefined();
154 }
155
156 void Register::copy(const Register &other)
157 {
158     *this = other;
159     if (other.dataType >= FirstCleanupType) {
160         if (other.dataType == QStringType) 
161             new (getstringptr()) QString(*other.getstringptr());
162         else if (other.dataType == QUrlType)
163             new (geturlptr()) QUrl(*other.geturlptr());
164         else if (other.dataType == QVariantType)
165             new (getvariantptr()) QVariant(*other.getvariantptr());
166     } 
167 }
168
169 void Register::init(Type type)
170 {
171     dataType = type;
172     if (dataType >= FirstCleanupType) {
173         if (dataType == QStringType) 
174             new (getstringptr()) QString();
175         else if (dataType == QUrlType)
176             new (geturlptr()) QUrl();
177         else if (dataType == QVariantType)
178             new (getvariantptr()) QVariant();
179     }
180 }
181
182 } // end of anonymous namespace
183
184 class QDeclarativeV4BindingsPrivate : public QObjectPrivate
185 {
186     Q_DECLARE_PUBLIC(QDeclarativeV4Bindings)
187
188 public:
189     QDeclarativeV4BindingsPrivate();
190     virtual ~QDeclarativeV4BindingsPrivate();
191
192     struct Binding : public QDeclarativeAbstractBinding, public QDeclarativeDelayedError {
193         Binding() : enabled(false), updating(0), property(0),
194                     scope(0), target(0), executedBlocks(0), parent(0) {}
195
196         // Inherited from QDeclarativeAbstractBinding
197         virtual void setEnabled(bool, QDeclarativePropertyPrivate::WriteFlags flags);
198         virtual void update(QDeclarativePropertyPrivate::WriteFlags flags);
199         virtual void destroy();
200
201         int index:30;
202         bool enabled:1;
203         bool updating:1;
204         int property;
205         QObject *scope;
206         QObject *target;
207         quint32 executedBlocks;
208
209         QDeclarativeV4BindingsPrivate *parent;
210     };
211
212     typedef QDeclarativeNotifierEndpoint Subscription;
213     Subscription *subscriptions;
214     QScriptDeclarativeClass::PersistentIdentifier *identifiers;
215
216     void run(Binding *, QDeclarativePropertyPrivate::WriteFlags flags);
217
218     QDeclarativeV4Program *program;
219     Binding *bindings;
220
221     static int methodCount;
222
223     void init();
224     void run(int instr, quint32 &executedBlocks, QDeclarativeContextData *context,
225              QDeclarativeDelayedError *error, QObject *scope, QObject *output, 
226              QDeclarativePropertyPrivate::WriteFlags storeFlags
227 #ifdef QML_THREADED_INTERPRETER
228              , void ***decode_instr = 0
229 #endif
230              );
231
232
233     inline void unsubscribe(int subIndex);
234     inline void subscribeId(QDeclarativeContextData *p, int idIndex, int subIndex);
235     inline void subscribe(QObject *o, int notifyIndex, int subIndex);
236
237     inline static qint32 toInt32(qsreal n);
238     static const qsreal D32;
239     static quint32 toUint32(qsreal n);
240 };
241
242 QDeclarativeV4BindingsPrivate::QDeclarativeV4BindingsPrivate()
243 : subscriptions(0), identifiers(0), program(0), bindings(0)
244 {
245 }
246
247 QDeclarativeV4BindingsPrivate::~QDeclarativeV4BindingsPrivate()
248 {
249     delete [] subscriptions; subscriptions = 0;
250     delete [] identifiers; identifiers = 0;
251 }
252
253 int QDeclarativeV4BindingsPrivate::methodCount = -1;
254
255 QDeclarativeV4Bindings::QDeclarativeV4Bindings(const char *program, QDeclarativeContextData *context)
256 : QObject(*(new QDeclarativeV4BindingsPrivate))
257 {
258     Q_D(QDeclarativeV4Bindings);
259
260     if (d->methodCount == -1)
261         d->methodCount = QDeclarativeV4Bindings::staticMetaObject.methodCount();
262
263     d->program = (QDeclarativeV4Program *)program;
264
265     if (program) {
266         d->init();
267
268         QDeclarativeAbstractExpression::setContext(context);
269     }
270 }
271
272 QDeclarativeV4Bindings::~QDeclarativeV4Bindings()
273 {
274     Q_D(QDeclarativeV4Bindings);
275
276     delete [] d->bindings;
277 }
278
279 QDeclarativeAbstractBinding *QDeclarativeV4Bindings::configBinding(int index, QObject *target, 
280                                                         QObject *scope, int property)
281 {
282     Q_D(QDeclarativeV4Bindings);
283
284     QDeclarativeV4BindingsPrivate::Binding *rv = d->bindings + index;
285
286     rv->index = index;
287     rv->property = property;
288     rv->target = target;
289     rv->scope = scope;
290     rv->parent = d;
291
292     addref(); // This is decremented in Binding::destroy()
293
294     return rv;
295 }
296
297 void QDeclarativeV4BindingsPrivate::Binding::setEnabled(bool e, QDeclarativePropertyPrivate::WriteFlags flags)
298 {
299     if (enabled != e) {
300         enabled = e;
301
302         if (e) update(flags);
303     }
304 }
305
306 void QDeclarativeV4BindingsPrivate::Binding::update(QDeclarativePropertyPrivate::WriteFlags flags)
307 {
308     QDeclarativeDebugTrace::startRange(QDeclarativeDebugTrace::Binding);
309     parent->run(this, flags);
310     QDeclarativeDebugTrace::endRange(QDeclarativeDebugTrace::Binding);
311 }
312
313 void QDeclarativeV4BindingsPrivate::Binding::destroy()
314 {
315     enabled = false;
316     removeFromObject();
317     clear();
318     parent->q_func()->release();
319 }
320
321 int QDeclarativeV4Bindings::qt_metacall(QMetaObject::Call c, int id, void **)
322 {
323     Q_D(QDeclarativeV4Bindings);
324
325     if (c == QMetaObject::InvokeMetaMethod && id >= d->methodCount) {
326         id -= d->methodCount;
327
328         QDeclarativeV4Program::BindingReferenceList *list = d->program->signalTable(id);
329
330         for (quint32 ii = 0; ii < list->count; ++ii) {
331             QDeclarativeV4Program::BindingReference *bindingRef = list->bindings + ii;
332
333             QDeclarativeV4BindingsPrivate::Binding *binding = d->bindings + bindingRef->binding;
334             if (binding->executedBlocks & bindingRef->blockMask)
335                 d->run(binding, QDeclarativePropertyPrivate::DontRemoveBinding);
336         }
337     }
338     return -1;
339 }
340
341 void QDeclarativeV4BindingsPrivate::run(Binding *binding, QDeclarativePropertyPrivate::WriteFlags flags)
342 {
343     Q_Q(QDeclarativeV4Bindings);
344
345     if (!binding->enabled)
346         return;
347
348     QDeclarativeContextData *context = q->QDeclarativeAbstractExpression::context();
349     if (!context || !context->isValid()) 
350         return;
351
352     if (binding->updating) {
353         QString name;
354         if (binding->property & 0xFFFF0000) {
355             QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(context->engine);
356
357             QDeclarativeValueType *vt = ep->valueTypes[(binding->property >> 16) & 0xFF];
358             Q_ASSERT(vt);
359
360             name = QLatin1String(binding->target->metaObject()->property(binding->property & 0xFFFF).name());
361             name.append(QLatin1String("."));
362             name.append(QLatin1String(vt->metaObject()->property(binding->property >> 24).name()));
363         } else {
364             name = QLatin1String(binding->target->metaObject()->property(binding->property).name());
365         }
366         qmlInfo(binding->target) << QCoreApplication::translate("QDeclarativeV4Bindings", "Binding loop detected for property \"%1\"").arg(name);
367         return;
368     }
369
370     binding->updating = true;
371     if (binding->property & 0xFFFF0000) {
372         QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(context->engine);
373
374         QDeclarativeValueType *vt = ep->valueTypes[(binding->property >> 16) & 0xFF];
375         Q_ASSERT(vt);
376         vt->read(binding->target, binding->property & 0xFFFF);
377
378         QObject *target = vt;
379         run(binding->index, binding->executedBlocks, context, binding, binding->scope, target, flags);
380
381         vt->write(binding->target, binding->property & 0xFFFF, flags);
382     } else {
383         run(binding->index, binding->executedBlocks, context, binding, binding->scope, binding->target, flags);
384     }
385     binding->updating = false;
386 }
387
388
389 void QDeclarativeV4BindingsPrivate::unsubscribe(int subIndex)
390 {
391     QDeclarativeV4BindingsPrivate::Subscription *sub = (subscriptions + subIndex);
392     sub->disconnect();
393 }
394
395 void QDeclarativeV4BindingsPrivate::subscribeId(QDeclarativeContextData *p, int idIndex, int subIndex)
396 {
397     Q_Q(QDeclarativeV4Bindings);
398
399     unsubscribe(subIndex);
400
401     if (p->idValues[idIndex]) {
402         QDeclarativeV4BindingsPrivate::Subscription *sub = (subscriptions + subIndex);
403         sub->target = q;
404         sub->targetMethod = methodCount + subIndex;
405         sub->connect(&p->idValues[idIndex].bindings);
406     }
407 }
408  
409 void QDeclarativeV4BindingsPrivate::subscribe(QObject *o, int notifyIndex, int subIndex)
410 {
411     Q_Q(QDeclarativeV4Bindings);
412
413     QDeclarativeV4BindingsPrivate::Subscription *sub = (subscriptions + subIndex);
414     sub->target = q;
415     sub->targetMethod = methodCount + subIndex; 
416     if (o)
417         sub->connect(o, notifyIndex);
418     else
419         sub->disconnect();
420 }
421
422 // Conversion functions - these MUST match the QtScript expression path
423 inline static qreal toReal(Register *reg, int type, bool *ok = 0)
424 {
425     if (ok) *ok = true;
426
427     if (type == QMetaType::QReal) {
428         return reg->getqreal();
429     } else if (type == qMetaTypeId<QVariant>()) {
430         return reg->getvariantptr()->toReal();
431     } else {
432         if (ok) *ok = false;
433         return 0;
434     }
435 }
436
437 inline static QString toString(Register *reg, int type, bool *ok = 0)
438 {
439     if (ok) *ok = true;
440
441     if (type == QMetaType::QReal) {
442         return QString::number(reg->getqreal());
443     } else if (type == QMetaType::Int) {
444         return QString::number(reg->getint());
445     } else if (type == qMetaTypeId<QVariant>()) {
446         return reg->getvariantptr()->toString();
447     } else if (type == QMetaType::QString) {
448         return *reg->getstringptr();
449     } else {
450         if (ok) *ok = false;
451         return QString();
452     }
453 }
454
455 inline static bool toBool(Register *reg, int type, bool *ok = 0)
456 {
457     if (ok) *ok = true;
458
459     if (type == QMetaType::Bool) {
460         return reg->getbool();
461     } else if (type == qMetaTypeId<QVariant>()) {
462         return reg->getvariantptr()->toBool();
463     } else {
464         if (ok) *ok = false;
465         return false;
466     }
467 }
468
469 inline static QUrl toUrl(Register *reg, int type, QDeclarativeContextData *context, bool *ok = 0)
470 {
471     if (ok) *ok = true;
472
473     QUrl base;
474     if (type == qMetaTypeId<QVariant>()) {
475         QVariant *var = reg->getvariantptr();
476         int vt = var->type();
477         if (vt == QVariant::Url) {
478             base = var->toUrl();
479         } else if (vt == QVariant::ByteArray) {
480             base = QUrl(QString::fromUtf8(var->toByteArray()));
481         } else if (vt == QVariant::String) {
482             base = QUrl(var->toString());
483         } else {
484             if (ok) *ok = false;
485             return QUrl();
486         }
487     } else if (type == QMetaType::QString) {
488         base = QUrl(*reg->getstringptr());
489     } else {
490         if (ok) *ok = false;
491         return QUrl();
492     }
493
494     if (!base.isEmpty() && base.isRelative())
495         return context->url.resolved(base);
496     else
497         return base;
498 }
499
500 static QObject *variantToQObject(const QVariant &value, bool *ok)
501 {
502     if (ok) *ok = true;
503
504     if (value.userType() == QMetaType::QObjectStar) {
505         return qvariant_cast<QObject*>(value);
506     } else {
507         if (ok) *ok = false;
508         return 0;
509     }
510 }
511
512 void QDeclarativeV4BindingsPrivate::init()
513 {
514     if (program->subscriptions)
515         subscriptions = new QDeclarativeV4BindingsPrivate::Subscription[program->subscriptions];
516     if (program->identifiers)
517         identifiers = new QScriptDeclarativeClass::PersistentIdentifier[program->identifiers];
518
519     bindings = new QDeclarativeV4BindingsPrivate::Binding[program->bindings];
520 }
521
522 static bool testCompareVariants(const QVariant &qtscriptRaw, const QVariant &v4)
523 {
524     QVariant qtscript = qtscriptRaw;
525
526     if (qtscript.userType() == v4.userType()) {
527     } else if (qtscript.canConvert((QVariant::Type)v4.userType())) {
528         qtscript.convert((QVariant::Type)v4.userType());
529     } else if (qtscript.userType() == QVariant::Invalid && v4.userType() == QMetaType::QObjectStar) {
530         qtscript = qVariantFromValue<QObject *>(0);
531     } else {
532         return false;
533     }
534
535     int type = qtscript.userType();
536     
537     if (type == qMetaTypeId<QDeclarativeAnchorLine>()) {
538         QDeclarativeAnchorLine la = qvariant_cast<QDeclarativeAnchorLine>(qtscript);
539         QDeclarativeAnchorLine ra = qvariant_cast<QDeclarativeAnchorLine>(v4);
540
541         return la == ra;
542     } else if (type == qMetaTypeId<QSGAnchorLine>()) {
543         QSGAnchorLine la = qvariant_cast<QSGAnchorLine>(qtscript);
544         QSGAnchorLine ra = qvariant_cast<QSGAnchorLine>(v4);
545
546         return la == ra;
547     } else if (type == QMetaType::Double) {
548
549         double la = qvariant_cast<double>(qtscript);
550         double lr = qvariant_cast<double>(v4);
551
552         return la == lr || (qIsNaN(la) && qIsNaN(lr));
553
554     } else if (type == QMetaType::Float) {
555
556         float la = qvariant_cast<float>(qtscript);
557         float lr = qvariant_cast<float>(v4);
558
559         return la == lr || (qIsNaN(la) && qIsNaN(lr));
560
561     } else {
562         return qtscript == v4;
563     }
564 }
565
566 QByteArray testResultToString(const QVariant &result, bool undefined)
567 {
568     if (undefined) {
569         return "undefined";
570     } else {
571         QString rv;
572         QDebug d(&rv);
573         d << result;
574         return rv.toUtf8();
575     }
576 }
577
578 static void testBindingResult(const QString &binding, int line, int column, 
579                               QDeclarativeContextData *context, QObject *scope, 
580                               const Register &result, int resultType)
581 {
582     QDeclarativeExpression expression(context->asQDeclarativeContext(), scope, binding);
583     bool isUndefined = false;
584     QVariant value = expression.evaluate(&isUndefined);
585
586     bool iserror = false;
587     QByteArray qtscriptResult;
588     QByteArray v4Result;
589
590     if (expression.hasError()) {
591         iserror = true;
592         qtscriptResult = "exception";
593     } else {
594         qtscriptResult = testResultToString(value, isUndefined);
595     }
596
597     if (isUndefined && result.isUndefined()) {
598         return;
599     } else if(isUndefined != result.isUndefined()) {
600         iserror = true;
601     } 
602     
603     QVariant v4value;
604     if (!result.isUndefined()) {
605         switch (resultType) {
606         case QMetaType::QString:
607             v4value = *result.getstringptr();
608             break;
609         case QMetaType::QUrl:
610             v4value = *result.geturlptr();
611             break;
612         case QMetaType::QObjectStar:
613             v4value = qVariantFromValue<QObject *>(result.getQObject());
614             break;
615         case QMetaType::Bool:
616             v4value = result.getbool();
617             break;
618         case QMetaType::Int:
619             v4value = result.getint();
620             break;
621         case QMetaType::QReal:
622             v4value = result.getqreal();
623             break;
624         default:
625             if (resultType == qMetaTypeId<QDeclarativeAnchorLine>()) {
626                 v4value = qVariantFromValue<QDeclarativeAnchorLine>(*(QDeclarativeAnchorLine *)result.typeDataPtr());
627             } else if (resultType == qMetaTypeId<QSGAnchorLine>()) {
628                 v4value = qVariantFromValue<QSGAnchorLine>(*(QSGAnchorLine *)result.typeDataPtr());
629             } else {
630                 iserror = true;
631                 v4Result = "Unknown V4 type";
632             }
633         }
634     }
635     if (v4Result.isEmpty())
636         v4Result = testResultToString(v4value, result.isUndefined());
637
638     if (!testCompareVariants(value, v4value)) 
639         iserror = true;
640
641     if (iserror) {
642         qWarning().nospace() << "QDeclarativeV4: Optimization error @" << context->url.toString().toUtf8().constData() << ":" << line << ":" << column;
643
644         qWarning().nospace() << "    Binding:  " << binding;
645         qWarning().nospace() << "    QtScript: " << qtscriptResult.constData();
646         qWarning().nospace() << "    V4:       " << v4Result.constData();
647     }
648 }
649
650 static void testBindingException(const QString &binding, int line, int column, 
651                                  QDeclarativeContextData *context, QObject *scope)
652 {
653     QDeclarativeExpression expression(context->asQDeclarativeContext(), scope, binding);
654     bool isUndefined = false;
655     QVariant value = expression.evaluate(&isUndefined);
656
657     if (!expression.hasError()) {
658         QByteArray qtscriptResult = testResultToString(value, isUndefined);
659         qWarning().nospace() << "QDeclarativeV4: Optimization error @" << context->url.toString().toUtf8().constData() << ":" << line << ":" << column;
660         qWarning().nospace() << "    Binding:  " << binding;
661         qWarning().nospace() << "    QtScript: " << qtscriptResult.constData();
662         qWarning().nospace() << "    V4:       exception";
663     }
664 }
665
666 static void throwException(int id, QDeclarativeDelayedError *error, 
667                            QDeclarativeV4Program *program, QDeclarativeContextData *context,
668                            const QString &description = QString())
669 {
670     error->error.setUrl(context->url);
671     if (description.isEmpty())
672         error->error.setDescription(QLatin1String("TypeError: Result of expression is not an object"));
673     else
674         error->error.setDescription(description);
675     if (id != 0xFF) {
676         quint64 e = *((quint64 *)(program->data() + program->exceptionDataOffset) + id); 
677         error->error.setLine((e >> 32) & 0xFFFFFFFF);
678         error->error.setColumn(e & 0xFFFFFFFF); 
679     } else {
680         error->error.setLine(-1);
681         error->error.setColumn(-1);
682     }
683     if (!context->engine || !error->addError(QDeclarativeEnginePrivate::get(context->engine)))
684         QDeclarativeEnginePrivate::warning(context->engine, error->error);
685 }
686
687 const qsreal QDeclarativeV4BindingsPrivate::D32 = 4294967296.0;
688
689 qint32 QDeclarativeV4BindingsPrivate::toInt32(qsreal n)
690 {
691     if (qIsNaN(n) || qIsInf(n) || (n == 0))
692         return 0;
693
694     double sign = (n < 0) ? -1.0 : 1.0;
695     qsreal abs_n = fabs(n);
696
697     n = ::fmod(sign * ::floor(abs_n), D32);
698     const double D31 = D32 / 2.0;
699
700     if (sign == -1 && n < -D31)
701         n += D32;
702
703     else if (sign != -1 && n >= D31)
704         n -= D32;
705
706     return qint32 (n);
707 }
708
709 inline quint32 QDeclarativeV4BindingsPrivate::toUint32(qsreal n)
710 {
711     if (qIsNaN(n) || qIsInf(n) || (n == 0))
712         return 0;
713
714     double sign = (n < 0) ? -1.0 : 1.0;
715     qsreal abs_n = fabs(n);
716
717     n = ::fmod(sign * ::floor(abs_n), D32);
718
719     if (n < 0)
720         n += D32;
721
722     return quint32 (n);
723 }
724
725 #define THROW_EXCEPTION_STR(id, str) { \
726     if (testBinding) testBindingException(*testBindingSource, bindingLine, bindingColumn, context, scope); \
727     throwException((id), error, program, context, (str)); \
728     goto exceptionExit; \
729
730
731 #define THROW_EXCEPTION(id) THROW_EXCEPTION_STR(id, QString())
732
733 #define MARK_REGISTER(reg) cleanupRegisterMask |= (1 << (reg))
734 #define MARK_CLEAN_REGISTER(reg) cleanupRegisterMask &= ~(1 << (reg))
735
736 #define STRING_REGISTER(reg) { \
737     registers[(reg)].settype(QStringType); \
738     MARK_REGISTER(reg); \
739 }
740
741 #define URL_REGISTER(reg) { \
742     registers[(reg)].settype(QUrlType); \
743     MARK_REGISTER(reg); \
744 }
745
746 #define VARIANT_REGISTER(reg) { \
747     registers[(reg)].settype(QVariantType); \
748     MARK_REGISTER(reg); \
749 }
750
751 #ifdef QML_THREADED_INTERPRETER
752 void **QDeclarativeV4Bindings::getDecodeInstrTable()
753 {
754     static void **decode_instr;
755     if (!decode_instr) {
756         QDeclarativeV4Bindings dummy(0, 0);
757         quint32 executedBlocks = 0;
758         dummy.d_func()->run(0, executedBlocks, 0, 0, 0, 0, QDeclarativePropertyPrivate::BypassInterceptor, &decode_instr);
759     }
760     return decode_instr;
761 }
762 #endif
763
764 void QDeclarativeV4BindingsPrivate::run(int instrIndex, quint32 &executedBlocks,
765                                         QDeclarativeContextData *context, QDeclarativeDelayedError *error,
766                                         QObject *scope, QObject *output, QDeclarativePropertyPrivate::WriteFlags storeFlags
767 #ifdef QML_THREADED_INTERPRETER
768                                         ,void ***table
769 #endif
770                                         )
771 {
772     Q_Q(QDeclarativeV4Bindings);
773
774 #ifdef QML_THREADED_INTERPRETER
775     if (table) {
776         static void *decode_instr[] = {
777             FOR_EACH_V4_INSTR(QML_V4_INSTR_ADDR)
778         };
779
780         *table = decode_instr;
781         return;
782     }
783 #endif
784
785
786     error->removeError();
787
788     Register registers[32];
789     quint32 cleanupRegisterMask = 0;
790
791     executedBlocks = 0;
792
793     QDeclarativeEnginePrivate *engine = QDeclarativeEnginePrivate::get(context->engine);
794     const char *code = program->instructions();
795     code += instrIndex * QML_V4_INSTR_SIZE(Jump, jump);
796     const Instr *instr = (const Instr *) code;
797
798     const char *data = program->data();
799
800     QString *testBindingSource = 0;
801     bool testBinding = false;
802     int bindingLine = 0;
803     int bindingColumn = 0;
804
805 #ifdef QML_THREADED_INTERPRETER
806     goto *instr->common.code;
807 #else
808     for (;;) {
809         switch (instr->common.type) {
810 #endif
811
812     QML_V4_BEGIN_INSTR(Noop, common)
813     QML_V4_END_INSTR(Noop, common)
814
815     QML_V4_BEGIN_INSTR(BindingId, id)
816         bindingLine = instr->id.line;
817         bindingColumn = instr->id.column;
818     QML_V4_END_INSTR(BindingId, id)
819
820     QML_V4_BEGIN_INSTR(SubscribeId, subscribeop)
821         subscribeId(context, instr->subscribeop.index, instr->subscribeop.offset);
822     QML_V4_END_INSTR(SubscribeId, subscribeop)
823
824     QML_V4_BEGIN_INSTR(Subscribe, subscribeop)
825     {
826         QObject *o = 0;
827         const Register &object = registers[instr->subscribeop.reg];
828         if (!object.isUndefined()) o = object.getQObject();
829         subscribe(o, instr->subscribeop.index, instr->subscribeop.offset);
830     }
831     QML_V4_END_INSTR(Subscribe, subscribeop)
832
833     QML_V4_BEGIN_INSTR(FetchAndSubscribe, fetchAndSubscribe)
834     {
835         Register &reg = registers[instr->fetchAndSubscribe.reg];
836
837         if (reg.isUndefined()) 
838             THROW_EXCEPTION(instr->fetchAndSubscribe.exceptionId);
839
840         QObject *object = reg.getQObject();
841         if (!object) {
842             reg.setUndefined();
843         } else {
844             int subIdx = instr->fetchAndSubscribe.subscription;
845             QDeclarativeV4BindingsPrivate::Subscription *sub = 0;
846             if (subIdx != -1) {
847                 sub = (subscriptions + subIdx);
848                 sub->target = q;
849                 sub->targetMethod = methodCount + subIdx;
850             }
851             reg.init((Register::Type)instr->fetchAndSubscribe.valueType);
852             if (instr->fetchAndSubscribe.valueType >= FirstCleanupType)
853                 MARK_REGISTER(instr->fetchAndSubscribe.reg);
854             QDeclarativeV4Compiler::fastPropertyAccessor()->accessor(instr->fetchAndSubscribe.function)(object, reg.typeDataPtr(), sub);
855         }
856     }
857     QML_V4_END_INSTR(FetchAndSubscribe, fetchAndSubscribe)
858
859     QML_V4_BEGIN_INSTR(LoadId, load)
860         registers[instr->load.reg].setQObject(context->idValues[instr->load.index].data());
861     QML_V4_END_INSTR(LoadId, load)
862
863     QML_V4_BEGIN_INSTR(LoadScope, load)
864         registers[instr->load.reg].setQObject(scope);
865     QML_V4_END_INSTR(LoadScope, load)
866
867     QML_V4_BEGIN_INSTR(LoadRoot, load)
868         registers[instr->load.reg].setQObject(context->contextObject);
869     QML_V4_END_INSTR(LoadRoot, load)
870
871     QML_V4_BEGIN_INSTR(LoadAttached, attached)
872     {
873         const Register &input = registers[instr->attached.reg];
874         Register &output = registers[instr->attached.output];
875         if (input.isUndefined()) 
876             THROW_EXCEPTION(instr->attached.exceptionId);
877
878         QObject *object = registers[instr->attached.reg].getQObject();
879         if (!object) {
880             output.setUndefined();
881         } else {
882             QObject *attached = qmlAttachedPropertiesObjectById(instr->attached.id, input.getQObject(), true);
883             Q_ASSERT(attached);
884             output.setQObject(attached);
885         }
886     }
887     QML_V4_END_INSTR(LoadAttached, attached)
888
889     QML_V4_BEGIN_INSTR(UnaryNot, unaryop)
890     {
891         registers[instr->unaryop.output].setbool(!registers[instr->unaryop.src].getbool());
892     }
893     QML_V4_END_INSTR(UnaryNot, unaryop)
894
895     QML_V4_BEGIN_INSTR(UnaryMinusReal, unaryop)
896     {
897         registers[instr->unaryop.output].setqreal(-registers[instr->unaryop.src].getqreal());
898     }
899     QML_V4_END_INSTR(UnaryMinusReal, unaryop)
900
901     QML_V4_BEGIN_INSTR(UnaryMinusInt, unaryop)
902     {
903         registers[instr->unaryop.output].setint(-registers[instr->unaryop.src].getint());
904     }
905     QML_V4_END_INSTR(UnaryMinusInt, unaryop)
906
907     QML_V4_BEGIN_INSTR(UnaryPlusReal, unaryop)
908     {
909         registers[instr->unaryop.output].setqreal(+registers[instr->unaryop.src].getqreal());
910     }
911     QML_V4_END_INSTR(UnaryPlusReal, unaryop)
912
913     QML_V4_BEGIN_INSTR(UnaryPlusInt, unaryop)
914     {
915         registers[instr->unaryop.output].setint(+registers[instr->unaryop.src].getint());
916     }
917     QML_V4_END_INSTR(UnaryPlusInt, unaryop)
918
919     QML_V4_BEGIN_INSTR(ConvertBoolToInt, unaryop)
920     {
921         const Register &src = registers[instr->unaryop.src];
922         Register &output = registers[instr->unaryop.output];
923         if (src.isUndefined()) output.setUndefined();
924         else output.setint(src.getbool());
925     }
926     QML_V4_END_INSTR(ConvertBoolToInt, unaryop)
927
928     QML_V4_BEGIN_INSTR(ConvertBoolToReal, unaryop)
929     {
930         const Register &src = registers[instr->unaryop.src];
931         Register &output = registers[instr->unaryop.output];
932         if (src.isUndefined()) output.setUndefined();
933         else output.setqreal(src.getbool());
934     }
935     QML_V4_END_INSTR(ConvertBoolToReal, unaryop)
936
937     QML_V4_BEGIN_INSTR(ConvertBoolToString, unaryop)
938     {
939         const Register &src = registers[instr->unaryop.src];
940         Register &output = registers[instr->unaryop.output];
941         if (src.isUndefined()) {
942             output.setUndefined();
943         } else { 
944             new (output.getstringptr()) QString(QLatin1String(src.getbool() ? "true" : "false"));
945             STRING_REGISTER(instr->unaryop.output);
946         }
947     }
948     QML_V4_END_INSTR(ConvertBoolToString, unaryop)
949
950     QML_V4_BEGIN_INSTR(ConvertIntToBool, unaryop)
951     {
952         const Register &src = registers[instr->unaryop.src];
953         Register &output = registers[instr->unaryop.output];
954         if (src.isUndefined()) output.setUndefined();
955         else output.setbool(src.getint());
956     }
957     QML_V4_END_INSTR(ConvertIntToBool, unaryop)
958
959     QML_V4_BEGIN_INSTR(ConvertIntToReal, unaryop)
960     {
961         const Register &src = registers[instr->unaryop.src];
962         Register &output = registers[instr->unaryop.output];
963         if (src.isUndefined()) output.setUndefined();
964         else output.setqreal(qreal(src.getint()));
965     }
966     QML_V4_END_INSTR(ConvertIntToReal, unaryop)
967
968     QML_V4_BEGIN_INSTR(ConvertIntToString, unaryop)
969     {
970         const Register &src = registers[instr->unaryop.src];
971         Register &output = registers[instr->unaryop.output];
972         if (src.isUndefined()) {
973             output.setUndefined();
974         } else { 
975             new (output.getstringptr()) QString(QString::number(src.getint()));
976             STRING_REGISTER(instr->unaryop.output);
977         }
978     }
979     QML_V4_END_INSTR(ConvertIntToString, unaryop)
980
981     QML_V4_BEGIN_INSTR(ConvertRealToBool, unaryop)
982     {
983         const Register &src = registers[instr->unaryop.src];
984         Register &output = registers[instr->unaryop.output];
985         if (src.isUndefined()) output.setUndefined();
986         else output.setbool(src.getqreal() != 0);
987     }
988     QML_V4_END_INSTR(ConvertRealToBool, unaryop)
989
990     QML_V4_BEGIN_INSTR(ConvertRealToInt, unaryop)
991     {
992         const Register &src = registers[instr->unaryop.src];
993         Register &output = registers[instr->unaryop.output];
994         if (src.isUndefined()) output.setUndefined();
995         else output.setint(toInt32(src.getqreal()));
996     }
997     QML_V4_END_INSTR(ConvertRealToInt, unaryop)
998
999     QML_V4_BEGIN_INSTR(ConvertRealToString, unaryop)
1000     {
1001         const Register &src = registers[instr->unaryop.src];
1002         Register &output = registers[instr->unaryop.output];
1003         // ### NaN
1004         if (src.isUndefined()) {
1005             output.setUndefined();
1006         } else {
1007             new (output.getstringptr()) QString(QString::number(src.getqreal()));
1008             STRING_REGISTER(instr->unaryop.output);
1009         }
1010     }
1011     QML_V4_END_INSTR(ConvertRealToString, unaryop)
1012
1013     QML_V4_BEGIN_INSTR(ConvertStringToBool, unaryop)
1014     {
1015         const Register &src = registers[instr->unaryop.src];
1016         Register &output = registers[instr->unaryop.output];
1017         // ### NaN
1018         if (src.isUndefined()) {
1019             output.setUndefined();
1020         } else {
1021             // Delegate the conversion. This is pretty fast and it doesn't require a QScriptEngine.
1022             // Ideally we should just call the methods in the QScript namespace directly.
1023             QScriptValue tmp(*src.getstringptr());
1024             if (instr->unaryop.src == instr->unaryop.output) {
1025                 output.cleanupString();
1026                 MARK_CLEAN_REGISTER(instr->unaryop.output);
1027             }
1028             output.setbool(tmp.toBool());
1029         }
1030     }
1031     QML_V4_END_INSTR(ConvertStringToBool, unaryop)
1032
1033     QML_V4_BEGIN_INSTR(ConvertStringToInt, unaryop)
1034     {
1035         const Register &src = registers[instr->unaryop.src];
1036         Register &output = registers[instr->unaryop.output];
1037         // ### NaN
1038         if (src.isUndefined()) {
1039             output.setUndefined();
1040         } else {
1041             // Delegate the conversion. This is pretty fast and it doesn't require a QScriptEngine.
1042             // Ideally we should just call the methods in the QScript namespace directly.
1043             QScriptValue tmp(*src.getstringptr());
1044             if (instr->unaryop.src == instr->unaryop.output) {
1045                 output.cleanupString();
1046                 MARK_CLEAN_REGISTER(instr->unaryop.output);
1047             }
1048             output.setint(tmp.toInt32());
1049         }
1050     }
1051     QML_V4_END_INSTR(ConvertStringToInt, unaryop)
1052
1053     QML_V4_BEGIN_INSTR(ConvertStringToReal, unaryop)
1054     {
1055         const Register &src = registers[instr->unaryop.src];
1056         Register &output = registers[instr->unaryop.output];
1057         // ### NaN
1058         if (src.isUndefined()) {
1059             output.setUndefined();
1060         } else {
1061             // Delegate the conversion. This is pretty fast and it doesn't require a QScriptEngine.
1062             // Ideally we should just call the methods in the QScript namespace directly.
1063             QScriptValue tmp(*src.getstringptr());
1064             if (instr->unaryop.src == instr->unaryop.output) {
1065                 output.cleanupString();
1066                 MARK_CLEAN_REGISTER(instr->unaryop.output);
1067             }
1068             output.setqreal(tmp.toNumber());
1069         }
1070     }
1071     QML_V4_END_INSTR(ConvertStringToReal, unaryop)
1072
1073     QML_V4_BEGIN_INSTR(MathSinReal, unaryop)
1074     {
1075         const Register &src = registers[instr->unaryop.src];
1076         Register &output = registers[instr->unaryop.output];
1077         if (src.isUndefined()) output.setUndefined();
1078         else output.setqreal(qSin(src.getqreal()));
1079     }
1080     QML_V4_END_INSTR(MathSinReal, unaryop)
1081
1082     QML_V4_BEGIN_INSTR(MathCosReal, unaryop)
1083     {
1084         const Register &src = registers[instr->unaryop.src];
1085         Register &output = registers[instr->unaryop.output];
1086         if (src.isUndefined()) output.setUndefined();
1087         else output.setqreal(qCos(src.getqreal()));
1088     }
1089     QML_V4_END_INSTR(MathCosReal, unaryop)
1090
1091     QML_V4_BEGIN_INSTR(MathRoundReal, unaryop)
1092     {
1093         const Register &src = registers[instr->unaryop.src];
1094         Register &output = registers[instr->unaryop.output];
1095         if (src.isUndefined()) output.setUndefined();
1096         else output.setint(qRound(src.getqreal()));
1097     }
1098     QML_V4_END_INSTR(MathRoundReal, unaryop)
1099
1100     QML_V4_BEGIN_INSTR(MathFloorReal, unaryop)
1101     {
1102         const Register &src = registers[instr->unaryop.src];
1103         Register &output = registers[instr->unaryop.output];
1104         if (src.isUndefined()) output.setUndefined();
1105         else output.setint(qFloor(src.getqreal()));
1106     }
1107     QML_V4_END_INSTR(MathFloorReal, unaryop)
1108
1109     QML_V4_BEGIN_INSTR(MathPIReal, unaryop)
1110     {
1111         static const qsreal qmlPI = 2.0 * qAsin(1.0);
1112         Register &output = registers[instr->unaryop.output];
1113         output.setqreal(qmlPI);
1114     }
1115     QML_V4_END_INSTR(MathPIReal, unaryop)
1116
1117     QML_V4_BEGIN_INSTR(Real, real_value)
1118         registers[instr->real_value.reg].setqreal(instr->real_value.value);
1119     QML_V4_END_INSTR(Real, real_value)
1120
1121     QML_V4_BEGIN_INSTR(Int, int_value)
1122         registers[instr->int_value.reg].setint(instr->int_value.value);
1123     QML_V4_END_INSTR(Int, int_value)
1124
1125     QML_V4_BEGIN_INSTR(Bool, bool_value)
1126         registers[instr->bool_value.reg].setbool(instr->bool_value.value);
1127     QML_V4_END_INSTR(Bool, bool_value)
1128
1129     QML_V4_BEGIN_INSTR(String, string_value)
1130     {
1131         Register &output = registers[instr->string_value.reg];
1132         QChar *string = (QChar *)(data + instr->string_value.offset);
1133         new (output.getstringptr()) QString(string, instr->string_value.length);
1134         STRING_REGISTER(instr->string_value.reg);
1135     }
1136     QML_V4_END_INSTR(String, string_value)
1137
1138     QML_V4_BEGIN_INSTR(EnableV4Test, string_value)
1139     {
1140         testBindingSource = new QString((QChar *)(data + instr->string_value.offset), instr->string_value.length);
1141         testBinding = true;
1142     }
1143     QML_V4_END_INSTR(String, string_value)
1144
1145     QML_V4_BEGIN_INSTR(BitAndInt, binaryop)
1146     {
1147         registers[instr->binaryop.output].setint(registers[instr->binaryop.left].getint() & 
1148                                                  registers[instr->binaryop.right].getint());
1149     }
1150     QML_V4_END_INSTR(BitAndInt, binaryop)
1151
1152     QML_V4_BEGIN_INSTR(BitOrInt, binaryop)
1153     {
1154         registers[instr->binaryop.output].setint(registers[instr->binaryop.left].getint() | 
1155                                                  registers[instr->binaryop.right].getint());
1156     }
1157     QML_V4_END_INSTR(BitAndInt, binaryop)
1158
1159     QML_V4_BEGIN_INSTR(BitXorInt, binaryop)
1160     {
1161         registers[instr->binaryop.output].setint(registers[instr->binaryop.left].getint() ^ 
1162                                                  registers[instr->binaryop.right].getint());
1163     }
1164     QML_V4_END_INSTR(BitXorInt, binaryop)
1165
1166     QML_V4_BEGIN_INSTR(AddReal, binaryop)
1167     {
1168         registers[instr->binaryop.output].setqreal(registers[instr->binaryop.left].getqreal() + 
1169                                                    registers[instr->binaryop.right].getqreal());
1170     }
1171     QML_V4_END_INSTR(AddReal, binaryop)
1172
1173     QML_V4_BEGIN_INSTR(AddString, binaryop)
1174     {
1175         QString &string = *registers[instr->binaryop.output].getstringptr();
1176         if (instr->binaryop.output == instr->binaryop.left) {
1177             string += registers[instr->binaryop.right].getstringptr();
1178         } else {
1179             string = *registers[instr->binaryop.left].getstringptr() + 
1180                      *registers[instr->binaryop.right].getstringptr();
1181         }
1182     }
1183     QML_V4_END_INSTR(AddString, binaryop)
1184
1185     QML_V4_BEGIN_INSTR(SubReal, binaryop)
1186     {
1187         registers[instr->binaryop.output].setqreal(registers[instr->binaryop.left].getqreal() - 
1188                                                    registers[instr->binaryop.right].getqreal());
1189     }
1190     QML_V4_END_INSTR(SubReal, binaryop)
1191
1192     QML_V4_BEGIN_INSTR(MulReal, binaryop)
1193     {
1194         registers[instr->binaryop.output].setqreal(registers[instr->binaryop.left].getqreal() * 
1195                                                    registers[instr->binaryop.right].getqreal());
1196     }
1197     QML_V4_END_INSTR(MulReal, binaryop)
1198
1199     QML_V4_BEGIN_INSTR(DivReal, binaryop)
1200     {
1201         registers[instr->binaryop.output].setqreal(registers[instr->binaryop.left].getqreal() / 
1202                                                    registers[instr->binaryop.right].getqreal());
1203     }
1204     QML_V4_END_INSTR(DivReal, binaryop)
1205
1206     QML_V4_BEGIN_INSTR(ModReal, binaryop)
1207     {
1208         Register &target = registers[instr->binaryop.output];
1209         const Register &left = registers[instr->binaryop.left];
1210         const Register &right = registers[instr->binaryop.right];
1211         if (QMetaType::QReal == QMetaType::Float)
1212             target.setqreal(::fmodf(left.getqreal(), right.getqreal()));
1213         else
1214             target.setqreal(::fmod(left.getqreal(), right.getqreal()));
1215     }
1216     QML_V4_END_INSTR(ModInt, binaryop)
1217
1218     QML_V4_BEGIN_INSTR(LShiftInt, binaryop)
1219     {
1220         registers[instr->binaryop.output].setint(registers[instr->binaryop.left].getint() << 
1221                                                  registers[instr->binaryop.right].getint());
1222     }
1223     QML_V4_END_INSTR(LShiftInt, binaryop)
1224
1225     QML_V4_BEGIN_INSTR(RShiftInt, binaryop)
1226     {
1227         registers[instr->binaryop.output].setint(registers[instr->binaryop.left].getint() >> 
1228                                                  registers[instr->binaryop.right].getint());
1229     }
1230     QML_V4_END_INSTR(RShiftInt, binaryop)
1231
1232     QML_V4_BEGIN_INSTR(URShiftInt, binaryop)
1233     {
1234         registers[instr->binaryop.output].setint((unsigned)registers[instr->binaryop.left].getint() >> 
1235                                                  registers[instr->binaryop.right].getint());
1236     }
1237     QML_V4_END_INSTR(URShiftInt, binaryop)
1238
1239     QML_V4_BEGIN_INSTR(GtReal, binaryop)
1240     {
1241         registers[instr->binaryop.output].setbool(registers[instr->binaryop.left].getqreal() > 
1242                                                   registers[instr->binaryop.right].getqreal());
1243     }
1244     QML_V4_END_INSTR(GtReal, binaryop)
1245
1246     QML_V4_BEGIN_INSTR(LtReal, binaryop)
1247     {
1248         registers[instr->binaryop.output].setbool(registers[instr->binaryop.left].getqreal() < 
1249                                                   registers[instr->binaryop.right].getqreal());
1250     }
1251     QML_V4_END_INSTR(LtReal, binaryop)
1252
1253     QML_V4_BEGIN_INSTR(GeReal, binaryop)
1254     {
1255         registers[instr->binaryop.output].setbool(registers[instr->binaryop.left].getqreal() >= 
1256                                                   registers[instr->binaryop.right].getqreal());
1257     }
1258     QML_V4_END_INSTR(GeReal, binaryop)
1259
1260     QML_V4_BEGIN_INSTR(LeReal, binaryop)
1261     {
1262         registers[instr->binaryop.output].setbool(registers[instr->binaryop.left].getqreal() <= 
1263                                                   registers[instr->binaryop.right].getqreal());
1264     }
1265     QML_V4_END_INSTR(LeReal, binaryop)
1266
1267     QML_V4_BEGIN_INSTR(EqualReal, binaryop)
1268     {
1269         registers[instr->binaryop.output].setbool(registers[instr->binaryop.left].getqreal() == 
1270                                                   registers[instr->binaryop.right].getqreal());
1271     }
1272     QML_V4_END_INSTR(EqualReal, binaryop)
1273
1274     QML_V4_BEGIN_INSTR(NotEqualReal, binaryop)
1275     {
1276         registers[instr->binaryop.output].setbool(registers[instr->binaryop.left].getqreal() != 
1277                                                   registers[instr->binaryop.right].getqreal());
1278     }
1279     QML_V4_END_INSTR(NotEqualReal, binaryop)
1280
1281     QML_V4_BEGIN_INSTR(StrictEqualReal, binaryop)
1282     {
1283         registers[instr->binaryop.output].setbool(registers[instr->binaryop.left].getqreal() == 
1284                                                   registers[instr->binaryop.right].getqreal());
1285     }
1286     QML_V4_END_INSTR(StrictEqualReal, binaryop)
1287
1288     QML_V4_BEGIN_INSTR(StrictNotEqualReal, binaryop)
1289     {
1290         registers[instr->binaryop.output].setbool(registers[instr->binaryop.left].getqreal() != 
1291                                                   registers[instr->binaryop.right].getqreal());
1292     }
1293     QML_V4_END_INSTR(StrictNotEqualReal, binaryop)
1294
1295     QML_V4_BEGIN_INSTR(GtString, binaryop)
1296     {
1297         const QString &a = *registers[instr->binaryop.left].getstringptr();
1298         const QString &b = *registers[instr->binaryop.right].getstringptr();
1299         bool result = a > b;
1300         if (instr->binaryop.left == instr->binaryop.output) {
1301             registers[instr->binaryop.output].cleanupString();
1302             MARK_CLEAN_REGISTER(instr->binaryop.output);
1303         }
1304         registers[instr->binaryop.output].setbool(result);
1305     }
1306     QML_V4_END_INSTR(GtString, binaryop)
1307
1308     QML_V4_BEGIN_INSTR(LtString, binaryop)
1309     {
1310         const QString &a = *registers[instr->binaryop.left].getstringptr();
1311         const QString &b = *registers[instr->binaryop.right].getstringptr();
1312         bool result = a < b;
1313         if (instr->binaryop.left == instr->binaryop.output) {
1314             registers[instr->binaryop.output].cleanupString();
1315             MARK_CLEAN_REGISTER(instr->binaryop.output);
1316         }
1317         registers[instr->binaryop.output].setbool(result);
1318     }
1319     QML_V4_END_INSTR(LtString, binaryop)
1320
1321     QML_V4_BEGIN_INSTR(GeString, binaryop)
1322     {
1323         const QString &a = *registers[instr->binaryop.left].getstringptr();
1324         const QString &b = *registers[instr->binaryop.right].getstringptr();
1325         bool result = a >= b;
1326         if (instr->binaryop.left == instr->binaryop.output) {
1327             registers[instr->binaryop.output].cleanupString();
1328             MARK_CLEAN_REGISTER(instr->binaryop.output);
1329         }
1330         registers[instr->binaryop.output].setbool(result);
1331     }
1332     QML_V4_END_INSTR(GeString, binaryop)
1333
1334     QML_V4_BEGIN_INSTR(LeString, binaryop)
1335     {
1336         const QString &a = *registers[instr->binaryop.left].getstringptr();
1337         const QString &b = *registers[instr->binaryop.right].getstringptr();
1338         bool result = a <= b;
1339         if (instr->binaryop.left == instr->binaryop.output) {
1340             registers[instr->binaryop.output].cleanupString();
1341             MARK_CLEAN_REGISTER(instr->binaryop.output);
1342         }
1343         registers[instr->binaryop.output].setbool(result);
1344     }
1345     QML_V4_END_INSTR(LeString, binaryop)
1346
1347     QML_V4_BEGIN_INSTR(EqualString, binaryop)
1348     {
1349         const QString &a = *registers[instr->binaryop.left].getstringptr();
1350         const QString &b = *registers[instr->binaryop.right].getstringptr();
1351         bool result = a == b;
1352         if (instr->binaryop.left == instr->binaryop.output) {
1353             registers[instr->binaryop.output].cleanupString();
1354             MARK_CLEAN_REGISTER(instr->binaryop.output);
1355         }
1356         registers[instr->binaryop.output].setbool(result);
1357     }
1358     QML_V4_END_INSTR(EqualString, binaryop)
1359
1360     QML_V4_BEGIN_INSTR(NotEqualString, binaryop)
1361     {
1362         const QString &a = *registers[instr->binaryop.left].getstringptr();
1363         const QString &b = *registers[instr->binaryop.right].getstringptr();
1364         bool result = a != b;
1365         if (instr->binaryop.left == instr->binaryop.output) {
1366             registers[instr->binaryop.output].cleanupString();
1367             MARK_CLEAN_REGISTER(instr->binaryop.output);
1368         }
1369         registers[instr->binaryop.output].setbool(result);
1370     }
1371     QML_V4_END_INSTR(NotEqualString, binaryop)
1372
1373     QML_V4_BEGIN_INSTR(StrictEqualString, binaryop)
1374     {
1375         const QString &a = *registers[instr->binaryop.left].getstringptr();
1376         const QString &b = *registers[instr->binaryop.right].getstringptr();
1377         bool result = a == b;
1378         if (instr->binaryop.left == instr->binaryop.output) {
1379             registers[instr->binaryop.output].cleanupString();
1380             MARK_CLEAN_REGISTER(instr->binaryop.output);
1381         }
1382         registers[instr->binaryop.output].setbool(result);
1383     }
1384     QML_V4_END_INSTR(StrictEqualString, binaryop)
1385
1386     QML_V4_BEGIN_INSTR(StrictNotEqualString, binaryop)
1387     {
1388         const QString &a = *registers[instr->binaryop.left].getstringptr();
1389         const QString &b = *registers[instr->binaryop.right].getstringptr();
1390         bool result = a != b;
1391         if (instr->binaryop.left == instr->binaryop.output) {
1392             registers[instr->binaryop.output].cleanupString();
1393             MARK_CLEAN_REGISTER(instr->binaryop.output);
1394         }
1395         registers[instr->binaryop.output].setbool(result);
1396     }
1397     QML_V4_END_INSTR(StrictNotEqualString, binaryop)
1398
1399     QML_V4_BEGIN_INSTR(NewString, construct)
1400     {
1401         Register &output = registers[instr->construct.reg];
1402         new (output.getstringptr()) QString;
1403         STRING_REGISTER(instr->construct.reg);
1404     }
1405     QML_V4_END_INSTR(NewString, construct)
1406
1407     QML_V4_BEGIN_INSTR(NewUrl, construct)
1408     {
1409         Register &output = registers[instr->construct.reg];
1410         new (output.geturlptr()) QUrl;
1411         URL_REGISTER(instr->construct.reg);
1412     }
1413     QML_V4_END_INSTR(NewUrl, construct)
1414
1415     QML_V4_BEGIN_INSTR(Fetch, fetch)
1416     {
1417         Register &reg = registers[instr->fetch.reg];
1418
1419         if (reg.isUndefined()) 
1420             THROW_EXCEPTION(instr->fetch.exceptionId);
1421
1422         QObject *object = reg.getQObject();
1423         if (!object) {
1424             THROW_EXCEPTION(instr->fetch.exceptionId);
1425         } else {
1426             reg.init((Register::Type)instr->fetch.valueType);
1427             if (instr->fetch.valueType >= FirstCleanupType)
1428                 MARK_REGISTER(instr->fetch.reg);
1429             void *argv[] = { reg.typeDataPtr(), 0 };
1430             QMetaObject::metacall(object, QMetaObject::ReadProperty, instr->fetch.index, argv);
1431         }
1432     }
1433     QML_V4_END_INSTR(Fetch, fetch)
1434
1435     QML_V4_BEGIN_INSTR(TestV4Store, storetest)
1436     {
1437         Register &data = registers[instr->storetest.reg];
1438         testBindingResult(*testBindingSource, bindingLine, bindingColumn, context, 
1439                           scope, data, instr->storetest.regType);
1440     }
1441     QML_V4_END_INSTR(TestV4Store, storetest)
1442
1443     QML_V4_BEGIN_INSTR(Store, store)
1444     {
1445         Register &data = registers[instr->store.reg];
1446
1447         if (data.isUndefined()) 
1448             THROW_EXCEPTION_STR(instr->store.exceptionId, QLatin1String("Unable to assign undefined value"));
1449
1450         int status = -1;
1451         void *argv[] = { data.typeDataPtr(), 0, &status, &storeFlags };
1452         QMetaObject::metacall(output, QMetaObject::WriteProperty,
1453                               instr->store.index, argv);
1454
1455         goto programExit;
1456     }
1457     QML_V4_END_INSTR(Store, store)
1458
1459     QML_V4_BEGIN_INSTR(Copy, copy)
1460         registers[instr->copy.reg].copy(registers[instr->copy.src]);
1461         if (registers[instr->copy.reg].gettype() >= FirstCleanupType)
1462             MARK_REGISTER(instr->copy.reg);
1463     QML_V4_END_INSTR(Copy, copy)
1464
1465     QML_V4_BEGIN_INSTR(Jump, jump)
1466         if (instr->jump.reg == -1 || !registers[instr->jump.reg].getbool())
1467             code += instr->jump.count;
1468     QML_V4_END_INSTR(Jump, jump)
1469
1470     QML_V4_BEGIN_INSTR(BranchTrue, branchop)
1471         if (registers[instr->branchop.reg].getbool())
1472             code += instr->branchop.offset;
1473     QML_V4_END_INSTR(BranchTrue, branchop)
1474
1475     QML_V4_BEGIN_INSTR(BranchFalse, branchop)
1476         if (! registers[instr->branchop.reg].getbool())
1477             code += instr->branchop.offset;
1478     QML_V4_END_INSTR(BranchFalse, branchop)
1479
1480     QML_V4_BEGIN_INSTR(Branch, branchop)
1481         code += instr->branchop.offset;
1482     QML_V4_END_INSTR(Branch, branchop)
1483
1484     QML_V4_BEGIN_INSTR(Block, blockop)
1485         executedBlocks |= instr->blockop.block;
1486     QML_V4_END_INSTR(Block, blockop)
1487
1488     QML_V4_BEGIN_INSTR(InitString, initstring)
1489         if (!identifiers[instr->initstring.offset].identifier) {
1490             quint32 len = *(quint32 *)(data + instr->initstring.dataIdx);
1491             QChar *strdata = (QChar *)(data + instr->initstring.dataIdx + sizeof(quint32));
1492
1493             QString str = QString::fromRawData(strdata, len);
1494
1495             identifiers[instr->initstring.offset] = engine->objectClass->createPersistentIdentifier(str);
1496         }
1497     QML_V4_END_INSTR(InitString, initstring)
1498
1499     QML_V4_BEGIN_INSTR(CleanupRegister, cleanup)
1500         registers[instr->cleanup.reg].cleanup();
1501     QML_V4_END_INSTR(CleanupRegister, cleanup)
1502
1503 #ifdef QML_THREADED_INTERPRETER
1504     // nothing to do
1505 #else
1506     default:
1507         qFatal("QDeclarativeV4: Unknown instruction %d encountered.", instr->common.type);
1508         break;
1509     } // switch
1510
1511     } // while
1512 #endif
1513
1514     Q_ASSERT(!"Unreachable code reached");
1515
1516 programExit:
1517 exceptionExit:
1518     delete testBindingSource;
1519
1520     int reg = 0;
1521     while (cleanupRegisterMask) {
1522         if (cleanupRegisterMask & 0x1) 
1523             registers[reg].cleanup();
1524
1525         reg++;
1526         cleanupRegisterMask >>= 1;
1527     }
1528 }
1529
1530 QT_END_NAMESPACE