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