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