fb9f8920dde5812db36020e5c04b34ba949908e0
[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: http://www.qt-project.org/
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             // Preserve any valid percent-encoded octets supplied by the source
424             base.setEncodedUrl(var->toByteArray(), QUrl::TolerantMode);
425         } else if (vt == QVariant::String) {
426             base.setEncodedUrl(var->toString().toUtf8(), QUrl::TolerantMode);
427         } else {
428             if (ok) *ok = false;
429             return QUrl();
430         }
431     } else if (type == QMetaType::QString) {
432         base.setEncodedUrl(reg->getstringptr()->toUtf8(), QUrl::TolerantMode);
433     } else {
434         if (ok) *ok = false;
435         return QUrl();
436     }
437
438     if (!base.isEmpty() && base.isRelative())
439         return context->url.resolved(base);
440     else
441         return base;
442 }
443
444 static bool testCompareVariants(const QVariant &qtscriptRaw, const QVariant &v4)
445 {
446     QVariant qtscript = qtscriptRaw;
447
448     if (qtscript.userType() == v4.userType()) {
449     } else if (qtscript.canConvert((QVariant::Type)v4.userType())) {
450         qtscript.convert((QVariant::Type)v4.userType());
451     } else if (qtscript.userType() == QVariant::Invalid && v4.userType() == QMetaType::QObjectStar) {
452         qtscript = qVariantFromValue<QObject *>(0);
453     } else {
454         return false;
455     }
456
457     int type = qtscript.userType();
458
459     if (type == qMetaTypeId<QDeclarative1AnchorLine>()) {
460         QDeclarative1AnchorLine la = qvariant_cast<QDeclarative1AnchorLine>(qtscript);
461         QDeclarative1AnchorLine ra = qvariant_cast<QDeclarative1AnchorLine>(v4);
462
463         return la == ra;
464     } else if (type == QDeclarativeMetaType::QQuickAnchorLineMetaTypeId()) {
465         return QDeclarativeMetaType::QQuickAnchorLineCompare(qtscript.constData(), v4.constData());
466     } else if (type == QMetaType::Double) {
467
468         double la = qvariant_cast<double>(qtscript);
469         double lr = qvariant_cast<double>(v4);
470
471         return la == lr || (qIsNaN(la) && qIsNaN(lr));
472
473     } else if (type == QMetaType::Float) {
474
475         float la = qvariant_cast<float>(qtscript);
476         float lr = qvariant_cast<float>(v4);
477
478         return la == lr || (qIsNaN(la) && qIsNaN(lr));
479
480     } else {
481         return qtscript == v4;
482     }
483 }
484
485 QByteArray testResultToString(const QVariant &result, bool undefined)
486 {
487     if (undefined) {
488         return "undefined";
489     } else {
490         QString rv;
491         QDebug d(&rv);
492         d << result;
493         return rv.toUtf8();
494     }
495 }
496
497 static void testBindingResult(const QString &binding, int line, int column, 
498                               QDeclarativeContextData *context, QObject *scope, 
499                               const Register &result, int resultType)
500 {
501     QDeclarativeExpression expression(context->asQDeclarativeContext(), scope, binding);
502     bool isUndefined = false;
503     QVariant value = expression.evaluate(&isUndefined);
504
505     bool iserror = false;
506     QByteArray qtscriptResult;
507     QByteArray v4Result;
508
509     if (expression.hasError()) {
510         iserror = true;
511         qtscriptResult = "exception";
512     } else {
513         qtscriptResult = testResultToString(value, isUndefined);
514     }
515
516     if (isUndefined && result.isUndefined()) {
517         return;
518     } else if(isUndefined != result.isUndefined()) {
519         iserror = true;
520     } 
521     
522     QVariant v4value;
523     if (!result.isUndefined()) {
524         switch (resultType) {
525         case QMetaType::QString:
526             v4value = *result.getstringptr();
527             break;
528         case QMetaType::QUrl:
529             v4value = *result.geturlptr();
530             break;
531         case QMetaType::QObjectStar:
532             v4value = qVariantFromValue<QObject *>(result.getQObject());
533             break;
534         case QMetaType::Bool:
535             v4value = result.getbool();
536             break;
537         case QMetaType::Int:
538             v4value = result.getint();
539             break;
540         case QMetaType::QReal:
541             v4value = result.getqreal();
542             break;
543         default:
544             if (resultType == qMetaTypeId<QDeclarative1AnchorLine>()) {
545                 v4value = qVariantFromValue<QDeclarative1AnchorLine>(*(QDeclarative1AnchorLine *)result.typeDataPtr());
546             } else if (resultType == QDeclarativeMetaType::QQuickAnchorLineMetaTypeId()) {
547                 v4value = QVariant(QDeclarativeMetaType::QQuickAnchorLineMetaTypeId(), result.typeDataPtr());
548             } else {
549                 iserror = true;
550                 v4Result = "Unknown V4 type";
551             }
552         }
553     }
554     if (v4Result.isEmpty())
555         v4Result = testResultToString(v4value, result.isUndefined());
556
557     if (!testCompareVariants(value, v4value)) 
558         iserror = true;
559
560     if (iserror) {
561         qWarning().nospace() << "QV4: Optimization error @" << context->url.toString().toUtf8().constData() << ":" << line << ":" << column;
562
563         qWarning().nospace() << "    Binding:  " << binding;
564         qWarning().nospace() << "    QtScript: " << qtscriptResult.constData();
565         qWarning().nospace() << "    V4:       " << v4Result.constData();
566     }
567 }
568
569 static void testBindingException(const QString &binding, int line, int column, 
570                                  QDeclarativeContextData *context, QObject *scope)
571 {
572     QDeclarativeExpression expression(context->asQDeclarativeContext(), scope, binding);
573     bool isUndefined = false;
574     QVariant value = expression.evaluate(&isUndefined);
575
576     if (!expression.hasError()) {
577         QByteArray qtscriptResult = testResultToString(value, isUndefined);
578         qWarning().nospace() << "QV4: Optimization error @" << context->url.toString().toUtf8().constData() << ":" << line << ":" << column;
579         qWarning().nospace() << "    Binding:  " << binding;
580         qWarning().nospace() << "    QtScript: " << qtscriptResult.constData();
581         qWarning().nospace() << "    V4:       exception";
582     }
583 }
584
585 static void throwException(int id, QDeclarativeDelayedError *error, 
586                            QV4Program *program, QDeclarativeContextData *context,
587                            const QString &description = QString())
588 {
589     error->error.setUrl(context->url);
590     if (description.isEmpty())
591         error->error.setDescription(QLatin1String("TypeError: Result of expression is not an object"));
592     else
593         error->error.setDescription(description);
594     if (id != 0xFF) {
595         quint64 e = *((quint64 *)(program->data() + program->exceptionDataOffset) + id); 
596         error->error.setLine((e >> 32) & 0xFFFFFFFF);
597         error->error.setColumn(e & 0xFFFFFFFF); 
598     } else {
599         error->error.setLine(-1);
600         error->error.setColumn(-1);
601     }
602     if (!context->engine || !error->addError(QDeclarativeEnginePrivate::get(context->engine)))
603         QDeclarativeEnginePrivate::warning(context->engine, error->error);
604 }
605
606 const qreal QV4Bindings::D32 = 4294967296.0;
607
608 qint32 QV4Bindings::toInt32(qreal n)
609 {
610     if (qIsNaN(n) || qIsInf(n) || (n == 0))
611         return 0;
612
613     double sign = (n < 0) ? -1.0 : 1.0;
614     qreal abs_n = fabs(n);
615
616     n = ::fmod(sign * ::floor(abs_n), D32);
617     const double D31 = D32 / 2.0;
618
619     if (sign == -1 && n < -D31)
620         n += D32;
621
622     else if (sign != -1 && n >= D31)
623         n -= D32;
624
625     return qint32 (n);
626 }
627
628 inline quint32 QV4Bindings::toUint32(qreal n)
629 {
630     if (qIsNaN(n) || qIsInf(n) || (n == 0))
631         return 0;
632
633     double sign = (n < 0) ? -1.0 : 1.0;
634     qreal abs_n = fabs(n);
635
636     n = ::fmod(sign * ::floor(abs_n), D32);
637
638     if (n < 0)
639         n += D32;
640
641     return quint32 (n);
642 }
643
644 #define THROW_EXCEPTION_STR(id, str) { \
645     if (testBinding) testBindingException(*testBindingSource, bindingLine, bindingColumn, context, scope); \
646     throwException((id), error, program, context, (str)); \
647     goto exceptionExit; \
648
649
650 #define THROW_EXCEPTION(id) THROW_EXCEPTION_STR(id, QString())
651
652 #define MARK_REGISTER(reg) cleanupRegisterMask |= (1 << (reg))
653 #define MARK_CLEAN_REGISTER(reg) cleanupRegisterMask &= ~(1 << (reg))
654
655 #define STRING_REGISTER(reg) { \
656     registers[(reg)].settype(QStringType); \
657     MARK_REGISTER(reg); \
658 }
659
660 #define URL_REGISTER(reg) { \
661     registers[(reg)].settype(QUrlType); \
662     MARK_REGISTER(reg); \
663 }
664
665 #define VARIANT_REGISTER(reg) { \
666     registers[(reg)].settype(QVariantType); \
667     MARK_REGISTER(reg); \
668 }
669
670 #ifdef QML_THREADED_INTERPRETER
671 void **QV4Bindings::getDecodeInstrTable()
672 {
673     static void **decode_instr;
674     if (!decode_instr) {
675         QV4Bindings *dummy = new QV4Bindings(0, 0, 0);
676         quint32 executedBlocks = 0;
677         dummy->run(0, executedBlocks, 0, 0, 0, 0, 
678                    QDeclarativePropertyPrivate::BypassInterceptor, 
679                    &decode_instr);
680         dummy->release();
681     }
682     return decode_instr;
683 }
684 #endif
685
686 void QV4Bindings::run(int instrIndex, quint32 &executedBlocks,
687                                  QDeclarativeContextData *context, QDeclarativeDelayedError *error,
688                                  QObject *scope, QObject *output, 
689                                  QDeclarativePropertyPrivate::WriteFlags storeFlags
690 #ifdef QML_THREADED_INTERPRETER
691                                  ,void ***table
692 #endif
693                                  )
694 {
695 #ifdef QML_THREADED_INTERPRETER
696     if (table) {
697         static void *decode_instr[] = {
698             FOR_EACH_V4_INSTR(QML_V4_INSTR_ADDR)
699         };
700
701         *table = decode_instr;
702         return;
703     }
704 #endif
705
706
707     error->removeError();
708
709     Register registers[32];
710     quint32 cleanupRegisterMask = 0;
711
712     executedBlocks = 0;
713
714     const char *code = program->instructions();
715     code += instrIndex * QML_V4_INSTR_SIZE(Jump, jump);
716     const V4Instr *instr = reinterpret_cast<const V4Instr *>(code);
717
718     const char *data = program->data();
719
720     QString *testBindingSource = 0;
721     bool testBinding = false;
722     int bindingLine = 0;
723     int bindingColumn = 0;
724
725 #ifdef QML_THREADED_INTERPRETER
726     goto *instr->common.code;
727 #else
728     for (;;) {
729         switch (instr->common.type) {
730 #endif
731
732     QML_V4_BEGIN_INSTR(Noop, common)
733     QML_V4_END_INSTR(Noop, common)
734
735     QML_V4_BEGIN_INSTR(BindingId, id)
736         bindingLine = instr->id.line;
737         bindingColumn = instr->id.column;
738     QML_V4_END_INSTR(BindingId, id)
739
740     QML_V4_BEGIN_INSTR(SubscribeId, subscribeop)
741         subscribeId(context, instr->subscribeop.index, instr->subscribeop.offset);
742     QML_V4_END_INSTR(SubscribeId, subscribeop)
743
744     QML_V4_BEGIN_INSTR(Subscribe, subscribeop)
745     {
746         QObject *o = 0;
747         const Register &object = registers[instr->subscribeop.reg];
748         if (!object.isUndefined()) o = object.getQObject();
749         subscribe(o, instr->subscribeop.index, instr->subscribeop.offset);
750     }
751     QML_V4_END_INSTR(Subscribe, subscribeop)
752
753     QML_V4_BEGIN_INSTR(FetchAndSubscribe, fetchAndSubscribe)
754     {
755         Register &reg = registers[instr->fetchAndSubscribe.reg];
756
757         if (reg.isUndefined()) 
758             THROW_EXCEPTION(instr->fetchAndSubscribe.exceptionId);
759
760         QObject *object = reg.getQObject();
761         if (!object) {
762             reg.setUndefined();
763         } else {
764             int subIdx = instr->fetchAndSubscribe.subscription;
765             Subscription *sub = 0;
766             if (subIdx != -1) {
767                 sub = (subscriptions + subIdx);
768                 sub->bindings = this;
769                 sub->method = subIdx;
770             }
771             reg.init((Register::Type)instr->fetchAndSubscribe.valueType);
772             if (instr->fetchAndSubscribe.valueType >= FirstCleanupType)
773                 MARK_REGISTER(instr->fetchAndSubscribe.reg);
774             QDeclarativeAccessors *accessors = instr->fetchAndSubscribe.property.accessors;
775             accessors->read(object, instr->fetchAndSubscribe.property.accessorData,
776                             reg.typeDataPtr());
777
778             if (accessors->notifier) {
779                 QDeclarativeNotifier *notifier = 0;
780                 accessors->notifier(object, instr->fetchAndSubscribe.property.accessorData, &notifier);
781                 if (notifier) sub->connect(notifier);
782             } else if (instr->fetchAndSubscribe.property.notifyIndex != -1) {
783                 sub->connect(object, instr->fetchAndSubscribe.property.notifyIndex);
784             }
785         }
786     }
787     QML_V4_END_INSTR(FetchAndSubscribe, fetchAndSubscribe)
788
789     QML_V4_BEGIN_INSTR(LoadId, load)
790         registers[instr->load.reg].setQObject(context->idValues[instr->load.index].data());
791     QML_V4_END_INSTR(LoadId, load)
792
793     QML_V4_BEGIN_INSTR(LoadScope, load)
794         registers[instr->load.reg].setQObject(scope);
795     QML_V4_END_INSTR(LoadScope, load)
796
797     QML_V4_BEGIN_INSTR(LoadRoot, load)
798         registers[instr->load.reg].setQObject(context->contextObject);
799     QML_V4_END_INSTR(LoadRoot, load)
800
801     QML_V4_BEGIN_INSTR(LoadAttached, attached)
802     {
803         const Register &input = registers[instr->attached.reg];
804         Register &output = registers[instr->attached.output];
805         if (input.isUndefined()) 
806             THROW_EXCEPTION(instr->attached.exceptionId);
807
808         QObject *object = registers[instr->attached.reg].getQObject();
809         if (!object) {
810             output.setUndefined();
811         } else {
812             QObject *attached = qmlAttachedPropertiesObjectById(instr->attached.id, input.getQObject(), true);
813             Q_ASSERT(attached);
814             output.setQObject(attached);
815         }
816     }
817     QML_V4_END_INSTR(LoadAttached, attached)
818
819     QML_V4_BEGIN_INSTR(UnaryNot, unaryop)
820     {
821         registers[instr->unaryop.output].setbool(!registers[instr->unaryop.src].getbool());
822     }
823     QML_V4_END_INSTR(UnaryNot, unaryop)
824
825     QML_V4_BEGIN_INSTR(UnaryMinusReal, unaryop)
826     {
827         registers[instr->unaryop.output].setqreal(-registers[instr->unaryop.src].getqreal());
828     }
829     QML_V4_END_INSTR(UnaryMinusReal, unaryop)
830
831     QML_V4_BEGIN_INSTR(UnaryMinusInt, unaryop)
832     {
833         registers[instr->unaryop.output].setint(-registers[instr->unaryop.src].getint());
834     }
835     QML_V4_END_INSTR(UnaryMinusInt, unaryop)
836
837     QML_V4_BEGIN_INSTR(UnaryPlusReal, unaryop)
838     {
839         registers[instr->unaryop.output].setqreal(+registers[instr->unaryop.src].getqreal());
840     }
841     QML_V4_END_INSTR(UnaryPlusReal, unaryop)
842
843     QML_V4_BEGIN_INSTR(UnaryPlusInt, unaryop)
844     {
845         registers[instr->unaryop.output].setint(+registers[instr->unaryop.src].getint());
846     }
847     QML_V4_END_INSTR(UnaryPlusInt, unaryop)
848
849     QML_V4_BEGIN_INSTR(ConvertBoolToInt, unaryop)
850     {
851         const Register &src = registers[instr->unaryop.src];
852         Register &output = registers[instr->unaryop.output];
853         if (src.isUndefined()) output.setUndefined();
854         else output.setint(src.getbool());
855     }
856     QML_V4_END_INSTR(ConvertBoolToInt, unaryop)
857
858     QML_V4_BEGIN_INSTR(ConvertBoolToReal, unaryop)
859     {
860         const Register &src = registers[instr->unaryop.src];
861         Register &output = registers[instr->unaryop.output];
862         if (src.isUndefined()) output.setUndefined();
863         else output.setqreal(src.getbool());
864     }
865     QML_V4_END_INSTR(ConvertBoolToReal, unaryop)
866
867     QML_V4_BEGIN_INSTR(ConvertBoolToString, unaryop)
868     {
869         const Register &src = registers[instr->unaryop.src];
870         Register &output = registers[instr->unaryop.output];
871         if (src.isUndefined()) {
872             output.setUndefined();
873         } else { 
874             new (output.getstringptr()) QString(QLatin1String(src.getbool() ? "true" : "false"));
875             STRING_REGISTER(instr->unaryop.output);
876         }
877     }
878     QML_V4_END_INSTR(ConvertBoolToString, unaryop)
879
880     QML_V4_BEGIN_INSTR(ConvertIntToBool, unaryop)
881     {
882         const Register &src = registers[instr->unaryop.src];
883         Register &output = registers[instr->unaryop.output];
884         if (src.isUndefined()) output.setUndefined();
885         else output.setbool(src.getint());
886     }
887     QML_V4_END_INSTR(ConvertIntToBool, unaryop)
888
889     QML_V4_BEGIN_INSTR(ConvertIntToReal, unaryop)
890     {
891         const Register &src = registers[instr->unaryop.src];
892         Register &output = registers[instr->unaryop.output];
893         if (src.isUndefined()) output.setUndefined();
894         else output.setqreal(qreal(src.getint()));
895     }
896     QML_V4_END_INSTR(ConvertIntToReal, unaryop)
897
898     QML_V4_BEGIN_INSTR(ConvertIntToString, unaryop)
899     {
900         const Register &src = registers[instr->unaryop.src];
901         Register &output = registers[instr->unaryop.output];
902         if (src.isUndefined()) {
903             output.setUndefined();
904         } else { 
905             new (output.getstringptr()) QString(QString::number(src.getint()));
906             STRING_REGISTER(instr->unaryop.output);
907         }
908     }
909     QML_V4_END_INSTR(ConvertIntToString, unaryop)
910
911     QML_V4_BEGIN_INSTR(ConvertRealToBool, unaryop)
912     {
913         const Register &src = registers[instr->unaryop.src];
914         Register &output = registers[instr->unaryop.output];
915         if (src.isUndefined()) output.setUndefined();
916         else output.setbool(src.getqreal() != 0);
917     }
918     QML_V4_END_INSTR(ConvertRealToBool, unaryop)
919
920     QML_V4_BEGIN_INSTR(ConvertRealToInt, unaryop)
921     {
922         const Register &src = registers[instr->unaryop.src];
923         Register &output = registers[instr->unaryop.output];
924         if (src.isUndefined()) output.setUndefined();
925         else output.setint(toInt32(src.getqreal()));
926     }
927     QML_V4_END_INSTR(ConvertRealToInt, unaryop)
928
929     QML_V4_BEGIN_INSTR(ConvertRealToString, unaryop)
930     {
931         const Register &src = registers[instr->unaryop.src];
932         Register &output = registers[instr->unaryop.output];
933         // ### NaN
934         if (src.isUndefined()) {
935             output.setUndefined();
936         } else {
937             new (output.getstringptr()) QString(QString::number(src.getqreal()));
938             STRING_REGISTER(instr->unaryop.output);
939         }
940     }
941     QML_V4_END_INSTR(ConvertRealToString, unaryop)
942
943     QML_V4_BEGIN_INSTR(ConvertStringToBool, unaryop)
944     {
945         const Register &src = registers[instr->unaryop.src];
946         Register &output = registers[instr->unaryop.output];
947         // ### NaN
948         if (src.isUndefined()) {
949             output.setUndefined();
950         } else {
951             // Delegate the conversion. This is pretty fast and it doesn't require a QScriptEngine.
952             // Ideally we should just call the methods in the QScript namespace directly.
953             QJSValue tmp(*src.getstringptr());
954             if (instr->unaryop.src == instr->unaryop.output) {
955                 output.cleanupString();
956                 MARK_CLEAN_REGISTER(instr->unaryop.output);
957             }
958             output.setbool(tmp.toBool());
959         }
960     }
961     QML_V4_END_INSTR(ConvertStringToBool, unaryop)
962
963     QML_V4_BEGIN_INSTR(ConvertStringToInt, unaryop)
964     {
965         const Register &src = registers[instr->unaryop.src];
966         Register &output = registers[instr->unaryop.output];
967         // ### NaN
968         if (src.isUndefined()) {
969             output.setUndefined();
970         } else {
971             // Delegate the conversion. This is pretty fast and it doesn't require a QScriptEngine.
972             // Ideally we should just call the methods in the QScript namespace directly.
973             QJSValue tmp(*src.getstringptr());
974             if (instr->unaryop.src == instr->unaryop.output) {
975                 output.cleanupString();
976                 MARK_CLEAN_REGISTER(instr->unaryop.output);
977             }
978             output.setint(tmp.toInt());
979         }
980     }
981     QML_V4_END_INSTR(ConvertStringToInt, unaryop)
982
983     QML_V4_BEGIN_INSTR(ConvertStringToReal, unaryop)
984     {
985         const Register &src = registers[instr->unaryop.src];
986         Register &output = registers[instr->unaryop.output];
987         // ### NaN
988         if (src.isUndefined()) {
989             output.setUndefined();
990         } else {
991             // Delegate the conversion. This is pretty fast and it doesn't require a QScriptEngine.
992             // Ideally we should just call the methods in the QScript namespace directly.
993             QJSValue tmp(*src.getstringptr());
994             if (instr->unaryop.src == instr->unaryop.output) {
995                 output.cleanupString();
996                 MARK_CLEAN_REGISTER(instr->unaryop.output);
997             }
998             output.setqreal(tmp.toNumber());
999         }
1000     }
1001     QML_V4_END_INSTR(ConvertStringToReal, unaryop)
1002
1003     QML_V4_BEGIN_INSTR(ConvertStringToUrl, unaryop)
1004     {
1005         const Register &src = registers[instr->unaryop.src];
1006         Register &output = registers[instr->unaryop.output];
1007         // ### NaN
1008         if (src.isUndefined()) {
1009             output.setUndefined();
1010         } else {
1011             const QString tmp(*src.getstringptr());
1012             if (instr->unaryop.src == instr->unaryop.output) {
1013                 output.cleanupString();
1014                 MARK_CLEAN_REGISTER(instr->unaryop.output);
1015             }
1016             QUrl *urlPtr = output.geturlptr();
1017             new (urlPtr) QUrl();
1018             urlPtr->setEncodedUrl(tmp.toUtf8(), QUrl::TolerantMode);
1019
1020             URL_REGISTER(instr->unaryop.output);
1021         }
1022     }
1023     QML_V4_END_INSTR(ConvertStringToUrl, unaryop)
1024
1025     QML_V4_BEGIN_INSTR(ConvertUrlToBool, unaryop)
1026     {
1027         const Register &src = registers[instr->unaryop.src];
1028         Register &output = registers[instr->unaryop.output];
1029         // ### NaN
1030         if (src.isUndefined()) {
1031             output.setUndefined();
1032         } else {
1033             const QUrl tmp(*src.geturlptr());
1034             if (instr->unaryop.src == instr->unaryop.output) {
1035                 output.cleanupUrl();
1036                 MARK_CLEAN_REGISTER(instr->unaryop.output);
1037             }
1038             output.setbool(!tmp.isEmpty());
1039         }
1040     }
1041     QML_V4_END_INSTR(ConvertUrlToBool, unaryop)
1042
1043     QML_V4_BEGIN_INSTR(ConvertUrlToString, unaryop)
1044     {
1045         const Register &src = registers[instr->unaryop.src];
1046         Register &output = registers[instr->unaryop.output];
1047         // ### NaN
1048         if (src.isUndefined()) {
1049             output.setUndefined();
1050         } else {
1051             const QUrl tmp(*src.geturlptr());
1052             if (instr->unaryop.src == instr->unaryop.output) {
1053                 output.cleanupUrl();
1054                 MARK_CLEAN_REGISTER(instr->unaryop.output);
1055             }
1056             new (output.getstringptr()) QString(tmp.toString());
1057             STRING_REGISTER(instr->unaryop.output);
1058         }
1059     }
1060     QML_V4_END_INSTR(ConvertUrlToString, unaryop)
1061
1062     QML_V4_BEGIN_INSTR(ResolveUrl, unaryop)
1063     {
1064         const Register &src = registers[instr->unaryop.src];
1065         Register &output = registers[instr->unaryop.output];
1066         if (src.isUndefined()) {
1067             output.setUndefined();
1068         } else {
1069             const QUrl tmp(*src.geturlptr());
1070             if (instr->unaryop.src == instr->unaryop.output) {
1071                 *output.geturlptr() = context->resolvedUrl(tmp);
1072             } else {
1073                 new (output.geturlptr()) QUrl(context->resolvedUrl(tmp));
1074                 URL_REGISTER(instr->unaryop.output);
1075             }
1076         }
1077     }
1078     QML_V4_END_INSTR(ResolveUrl, unaryop)
1079
1080     QML_V4_BEGIN_INSTR(MathSinReal, unaryop)
1081     {
1082         const Register &src = registers[instr->unaryop.src];
1083         Register &output = registers[instr->unaryop.output];
1084         if (src.isUndefined()) output.setUndefined();
1085         else output.setqreal(qSin(src.getqreal()));
1086     }
1087     QML_V4_END_INSTR(MathSinReal, unaryop)
1088
1089     QML_V4_BEGIN_INSTR(MathCosReal, unaryop)
1090     {
1091         const Register &src = registers[instr->unaryop.src];
1092         Register &output = registers[instr->unaryop.output];
1093         if (src.isUndefined()) output.setUndefined();
1094         else output.setqreal(qCos(src.getqreal()));
1095     }
1096     QML_V4_END_INSTR(MathCosReal, unaryop)
1097
1098     QML_V4_BEGIN_INSTR(MathRoundReal, unaryop)
1099     {
1100         const Register &src = registers[instr->unaryop.src];
1101         Register &output = registers[instr->unaryop.output];
1102         if (src.isUndefined()) output.setUndefined();
1103         else output.setint(qRound(src.getqreal()));
1104     }
1105     QML_V4_END_INSTR(MathRoundReal, unaryop)
1106
1107     QML_V4_BEGIN_INSTR(MathFloorReal, unaryop)
1108     {
1109         const Register &src = registers[instr->unaryop.src];
1110         Register &output = registers[instr->unaryop.output];
1111         if (src.isUndefined()) output.setUndefined();
1112         else output.setint(qFloor(src.getqreal()));
1113     }
1114     QML_V4_END_INSTR(MathFloorReal, unaryop)
1115
1116     QML_V4_BEGIN_INSTR(MathPIReal, unaryop)
1117     {
1118         static const qreal qmlPI = 2.0 * qAsin(1.0);
1119         Register &output = registers[instr->unaryop.output];
1120         output.setqreal(qmlPI);
1121     }
1122     QML_V4_END_INSTR(MathPIReal, unaryop)
1123
1124     QML_V4_BEGIN_INSTR(LoadReal, real_value)
1125         registers[instr->real_value.reg].setqreal(instr->real_value.value);
1126     QML_V4_END_INSTR(LoadReal, real_value)
1127
1128     QML_V4_BEGIN_INSTR(LoadInt, int_value)
1129         registers[instr->int_value.reg].setint(instr->int_value.value);
1130     QML_V4_END_INSTR(LoadInt, int_value)
1131
1132     QML_V4_BEGIN_INSTR(LoadBool, bool_value)
1133         registers[instr->bool_value.reg].setbool(instr->bool_value.value);
1134     QML_V4_END_INSTR(LoadBool, bool_value)
1135
1136     QML_V4_BEGIN_INSTR(LoadString, string_value)
1137     {
1138         Register &output = registers[instr->string_value.reg];
1139         QChar *string = (QChar *)(data + instr->string_value.offset);
1140         new (output.getstringptr()) QString(string, instr->string_value.length);
1141         STRING_REGISTER(instr->string_value.reg);
1142     }
1143     QML_V4_END_INSTR(LoadString, string_value)
1144
1145     QML_V4_BEGIN_INSTR(EnableV4Test, string_value)
1146     {
1147         testBindingSource = new QString((QChar *)(data + instr->string_value.offset), instr->string_value.length);
1148         testBinding = true;
1149     }
1150     QML_V4_END_INSTR(String, string_value)
1151
1152     QML_V4_BEGIN_INSTR(BitAndInt, binaryop)
1153     {
1154         registers[instr->binaryop.output].setint(registers[instr->binaryop.left].getint() & 
1155                                                  registers[instr->binaryop.right].getint());
1156     }
1157     QML_V4_END_INSTR(BitAndInt, binaryop)
1158
1159     QML_V4_BEGIN_INSTR(BitOrInt, binaryop)
1160     {
1161         registers[instr->binaryop.output].setint(registers[instr->binaryop.left].getint() | 
1162                                                  registers[instr->binaryop.right].getint());
1163     }
1164     QML_V4_END_INSTR(BitAndInt, binaryop)
1165
1166     QML_V4_BEGIN_INSTR(BitXorInt, binaryop)
1167     {
1168         registers[instr->binaryop.output].setint(registers[instr->binaryop.left].getint() ^ 
1169                                                  registers[instr->binaryop.right].getint());
1170     }
1171     QML_V4_END_INSTR(BitXorInt, binaryop)
1172
1173     QML_V4_BEGIN_INSTR(AddReal, binaryop)
1174     {
1175         registers[instr->binaryop.output].setqreal(registers[instr->binaryop.left].getqreal() + 
1176                                                    registers[instr->binaryop.right].getqreal());
1177     }
1178     QML_V4_END_INSTR(AddReal, binaryop)
1179
1180     QML_V4_BEGIN_INSTR(AddString, binaryop)
1181     {
1182         QString &string = *registers[instr->binaryop.output].getstringptr();
1183         if (instr->binaryop.output == instr->binaryop.left) {
1184             string += registers[instr->binaryop.right].getstringptr();
1185         } else {
1186             string = *registers[instr->binaryop.left].getstringptr() + 
1187                      *registers[instr->binaryop.right].getstringptr();
1188         }
1189     }
1190     QML_V4_END_INSTR(AddString, binaryop)
1191
1192     QML_V4_BEGIN_INSTR(SubReal, binaryop)
1193     {
1194         registers[instr->binaryop.output].setqreal(registers[instr->binaryop.left].getqreal() - 
1195                                                    registers[instr->binaryop.right].getqreal());
1196     }
1197     QML_V4_END_INSTR(SubReal, binaryop)
1198
1199     QML_V4_BEGIN_INSTR(MulReal, binaryop)
1200     {
1201         registers[instr->binaryop.output].setqreal(registers[instr->binaryop.left].getqreal() * 
1202                                                    registers[instr->binaryop.right].getqreal());
1203     }
1204     QML_V4_END_INSTR(MulReal, binaryop)
1205
1206     QML_V4_BEGIN_INSTR(DivReal, binaryop)
1207     {
1208         registers[instr->binaryop.output].setqreal(registers[instr->binaryop.left].getqreal() / 
1209                                                    registers[instr->binaryop.right].getqreal());
1210     }
1211     QML_V4_END_INSTR(DivReal, binaryop)
1212
1213     QML_V4_BEGIN_INSTR(ModReal, binaryop)
1214     {
1215         Register &target = registers[instr->binaryop.output];
1216         const Register &left = registers[instr->binaryop.left];
1217         const Register &right = registers[instr->binaryop.right];
1218         if (QMetaType::QReal == QMetaType::Float)
1219             target.setqreal(::fmodf(left.getqreal(), right.getqreal()));
1220         else
1221             target.setqreal(::fmod(left.getqreal(), right.getqreal()));
1222     }
1223     QML_V4_END_INSTR(ModInt, binaryop)
1224
1225     QML_V4_BEGIN_INSTR(LShiftInt, binaryop)
1226     {
1227         registers[instr->binaryop.output].setint(registers[instr->binaryop.left].getint() << 
1228                                                  registers[instr->binaryop.right].getint());
1229     }
1230     QML_V4_END_INSTR(LShiftInt, binaryop)
1231
1232     QML_V4_BEGIN_INSTR(RShiftInt, binaryop)
1233     {
1234         registers[instr->binaryop.output].setint(registers[instr->binaryop.left].getint() >> 
1235                                                  registers[instr->binaryop.right].getint());
1236     }
1237     QML_V4_END_INSTR(RShiftInt, binaryop)
1238
1239     QML_V4_BEGIN_INSTR(URShiftInt, binaryop)
1240     {
1241         registers[instr->binaryop.output].setint((unsigned)registers[instr->binaryop.left].getint() >> 
1242                                                  registers[instr->binaryop.right].getint());
1243     }
1244     QML_V4_END_INSTR(URShiftInt, binaryop)
1245
1246     QML_V4_BEGIN_INSTR(GtReal, binaryop)
1247     {
1248         registers[instr->binaryop.output].setbool(registers[instr->binaryop.left].getqreal() > 
1249                                                   registers[instr->binaryop.right].getqreal());
1250     }
1251     QML_V4_END_INSTR(GtReal, binaryop)
1252
1253     QML_V4_BEGIN_INSTR(LtReal, binaryop)
1254     {
1255         registers[instr->binaryop.output].setbool(registers[instr->binaryop.left].getqreal() < 
1256                                                   registers[instr->binaryop.right].getqreal());
1257     }
1258     QML_V4_END_INSTR(LtReal, binaryop)
1259
1260     QML_V4_BEGIN_INSTR(GeReal, binaryop)
1261     {
1262         registers[instr->binaryop.output].setbool(registers[instr->binaryop.left].getqreal() >= 
1263                                                   registers[instr->binaryop.right].getqreal());
1264     }
1265     QML_V4_END_INSTR(GeReal, binaryop)
1266
1267     QML_V4_BEGIN_INSTR(LeReal, binaryop)
1268     {
1269         registers[instr->binaryop.output].setbool(registers[instr->binaryop.left].getqreal() <= 
1270                                                   registers[instr->binaryop.right].getqreal());
1271     }
1272     QML_V4_END_INSTR(LeReal, binaryop)
1273
1274     QML_V4_BEGIN_INSTR(EqualReal, binaryop)
1275     {
1276         registers[instr->binaryop.output].setbool(registers[instr->binaryop.left].getqreal() == 
1277                                                   registers[instr->binaryop.right].getqreal());
1278     }
1279     QML_V4_END_INSTR(EqualReal, binaryop)
1280
1281     QML_V4_BEGIN_INSTR(NotEqualReal, binaryop)
1282     {
1283         registers[instr->binaryop.output].setbool(registers[instr->binaryop.left].getqreal() != 
1284                                                   registers[instr->binaryop.right].getqreal());
1285     }
1286     QML_V4_END_INSTR(NotEqualReal, binaryop)
1287
1288     QML_V4_BEGIN_INSTR(StrictEqualReal, binaryop)
1289     {
1290         registers[instr->binaryop.output].setbool(registers[instr->binaryop.left].getqreal() == 
1291                                                   registers[instr->binaryop.right].getqreal());
1292     }
1293     QML_V4_END_INSTR(StrictEqualReal, binaryop)
1294
1295     QML_V4_BEGIN_INSTR(StrictNotEqualReal, binaryop)
1296     {
1297         registers[instr->binaryop.output].setbool(registers[instr->binaryop.left].getqreal() != 
1298                                                   registers[instr->binaryop.right].getqreal());
1299     }
1300     QML_V4_END_INSTR(StrictNotEqualReal, binaryop)
1301
1302     QML_V4_BEGIN_INSTR(GtString, binaryop)
1303     {
1304         const QString &a = *registers[instr->binaryop.left].getstringptr();
1305         const QString &b = *registers[instr->binaryop.right].getstringptr();
1306         bool result = a > b;
1307         if (instr->binaryop.left == instr->binaryop.output) {
1308             registers[instr->binaryop.output].cleanupString();
1309             MARK_CLEAN_REGISTER(instr->binaryop.output);
1310         }
1311         registers[instr->binaryop.output].setbool(result);
1312     }
1313     QML_V4_END_INSTR(GtString, binaryop)
1314
1315     QML_V4_BEGIN_INSTR(LtString, binaryop)
1316     {
1317         const QString &a = *registers[instr->binaryop.left].getstringptr();
1318         const QString &b = *registers[instr->binaryop.right].getstringptr();
1319         bool result = a < b;
1320         if (instr->binaryop.left == instr->binaryop.output) {
1321             registers[instr->binaryop.output].cleanupString();
1322             MARK_CLEAN_REGISTER(instr->binaryop.output);
1323         }
1324         registers[instr->binaryop.output].setbool(result);
1325     }
1326     QML_V4_END_INSTR(LtString, binaryop)
1327
1328     QML_V4_BEGIN_INSTR(GeString, binaryop)
1329     {
1330         const QString &a = *registers[instr->binaryop.left].getstringptr();
1331         const QString &b = *registers[instr->binaryop.right].getstringptr();
1332         bool result = a >= b;
1333         if (instr->binaryop.left == instr->binaryop.output) {
1334             registers[instr->binaryop.output].cleanupString();
1335             MARK_CLEAN_REGISTER(instr->binaryop.output);
1336         }
1337         registers[instr->binaryop.output].setbool(result);
1338     }
1339     QML_V4_END_INSTR(GeString, binaryop)
1340
1341     QML_V4_BEGIN_INSTR(LeString, binaryop)
1342     {
1343         const QString &a = *registers[instr->binaryop.left].getstringptr();
1344         const QString &b = *registers[instr->binaryop.right].getstringptr();
1345         bool result = a <= b;
1346         if (instr->binaryop.left == instr->binaryop.output) {
1347             registers[instr->binaryop.output].cleanupString();
1348             MARK_CLEAN_REGISTER(instr->binaryop.output);
1349         }
1350         registers[instr->binaryop.output].setbool(result);
1351     }
1352     QML_V4_END_INSTR(LeString, binaryop)
1353
1354     QML_V4_BEGIN_INSTR(EqualString, binaryop)
1355     {
1356         const QString &a = *registers[instr->binaryop.left].getstringptr();
1357         const QString &b = *registers[instr->binaryop.right].getstringptr();
1358         bool result = a == b;
1359         if (instr->binaryop.left == instr->binaryop.output) {
1360             registers[instr->binaryop.output].cleanupString();
1361             MARK_CLEAN_REGISTER(instr->binaryop.output);
1362         }
1363         registers[instr->binaryop.output].setbool(result);
1364     }
1365     QML_V4_END_INSTR(EqualString, binaryop)
1366
1367     QML_V4_BEGIN_INSTR(NotEqualString, binaryop)
1368     {
1369         const QString &a = *registers[instr->binaryop.left].getstringptr();
1370         const QString &b = *registers[instr->binaryop.right].getstringptr();
1371         bool result = a != b;
1372         if (instr->binaryop.left == instr->binaryop.output) {
1373             registers[instr->binaryop.output].cleanupString();
1374             MARK_CLEAN_REGISTER(instr->binaryop.output);
1375         }
1376         registers[instr->binaryop.output].setbool(result);
1377     }
1378     QML_V4_END_INSTR(NotEqualString, binaryop)
1379
1380     QML_V4_BEGIN_INSTR(StrictEqualString, binaryop)
1381     {
1382         const QString &a = *registers[instr->binaryop.left].getstringptr();
1383         const QString &b = *registers[instr->binaryop.right].getstringptr();
1384         bool result = a == b;
1385         if (instr->binaryop.left == instr->binaryop.output) {
1386             registers[instr->binaryop.output].cleanupString();
1387             MARK_CLEAN_REGISTER(instr->binaryop.output);
1388         }
1389         registers[instr->binaryop.output].setbool(result);
1390     }
1391     QML_V4_END_INSTR(StrictEqualString, binaryop)
1392
1393     QML_V4_BEGIN_INSTR(StrictNotEqualString, binaryop)
1394     {
1395         const QString &a = *registers[instr->binaryop.left].getstringptr();
1396         const QString &b = *registers[instr->binaryop.right].getstringptr();
1397         bool result = a != b;
1398         if (instr->binaryop.left == instr->binaryop.output) {
1399             registers[instr->binaryop.output].cleanupString();
1400             MARK_CLEAN_REGISTER(instr->binaryop.output);
1401         }
1402         registers[instr->binaryop.output].setbool(result);
1403     }
1404     QML_V4_END_INSTR(StrictNotEqualString, binaryop)
1405
1406     QML_V4_BEGIN_INSTR(NewString, construct)
1407     {
1408         Register &output = registers[instr->construct.reg];
1409         new (output.getstringptr()) QString;
1410         STRING_REGISTER(instr->construct.reg);
1411     }
1412     QML_V4_END_INSTR(NewString, construct)
1413
1414     QML_V4_BEGIN_INSTR(NewUrl, construct)
1415     {
1416         Register &output = registers[instr->construct.reg];
1417         new (output.geturlptr()) QUrl;
1418         URL_REGISTER(instr->construct.reg);
1419     }
1420     QML_V4_END_INSTR(NewUrl, construct)
1421
1422     QML_V4_BEGIN_INSTR(Fetch, fetch)
1423     {
1424         Register &reg = registers[instr->fetch.reg];
1425
1426         if (reg.isUndefined()) 
1427             THROW_EXCEPTION(instr->fetch.exceptionId);
1428
1429         QObject *object = reg.getQObject();
1430         if (!object) {
1431             THROW_EXCEPTION(instr->fetch.exceptionId);
1432         } else {
1433             reg.init((Register::Type)instr->fetch.valueType);
1434             if (instr->fetch.valueType >= FirstCleanupType)
1435                 MARK_REGISTER(instr->fetch.reg);
1436             void *argv[] = { reg.typeDataPtr(), 0 };
1437             QMetaObject::metacall(object, QMetaObject::ReadProperty, instr->fetch.index, argv);
1438         }
1439     }
1440     QML_V4_END_INSTR(Fetch, fetch)
1441
1442     QML_V4_BEGIN_INSTR(TestV4Store, storetest)
1443     {
1444         Register &data = registers[instr->storetest.reg];
1445         testBindingResult(*testBindingSource, bindingLine, bindingColumn, context, 
1446                           scope, data, instr->storetest.regType);
1447     }
1448     QML_V4_END_INSTR(TestV4Store, storetest)
1449
1450     QML_V4_BEGIN_INSTR(Store, store)
1451     {
1452         Register &data = registers[instr->store.reg];
1453
1454         if (data.isUndefined()) 
1455             THROW_EXCEPTION_STR(instr->store.exceptionId, QLatin1String("Unable to assign undefined value"));
1456
1457         int status = -1;
1458         void *argv[] = { data.typeDataPtr(), 0, &status, &storeFlags };
1459         QMetaObject::metacall(output, QMetaObject::WriteProperty,
1460                               instr->store.index, argv);
1461
1462         goto programExit;
1463     }
1464     QML_V4_END_INSTR(Store, store)
1465
1466     QML_V4_BEGIN_INSTR(Copy, copy)
1467         registers[instr->copy.reg].copy(registers[instr->copy.src]);
1468         if (registers[instr->copy.reg].gettype() >= FirstCleanupType)
1469             MARK_REGISTER(instr->copy.reg);
1470     QML_V4_END_INSTR(Copy, copy)
1471
1472     QML_V4_BEGIN_INSTR(Jump, jump)
1473         if (instr->jump.reg == -1 || !registers[instr->jump.reg].getbool())
1474             code += instr->jump.count;
1475     QML_V4_END_INSTR(Jump, jump)
1476
1477     QML_V4_BEGIN_INSTR(BranchTrue, branchop)
1478         if (registers[instr->branchop.reg].getbool())
1479             code += instr->branchop.offset;
1480     QML_V4_END_INSTR(BranchTrue, branchop)
1481
1482     QML_V4_BEGIN_INSTR(BranchFalse, branchop)
1483         if (! registers[instr->branchop.reg].getbool())
1484             code += instr->branchop.offset;
1485     QML_V4_END_INSTR(BranchFalse, branchop)
1486
1487     QML_V4_BEGIN_INSTR(Branch, branchop)
1488         code += instr->branchop.offset;
1489     QML_V4_END_INSTR(Branch, branchop)
1490
1491     QML_V4_BEGIN_INSTR(Block, blockop)
1492         executedBlocks |= instr->blockop.block;
1493     QML_V4_END_INSTR(Block, blockop)
1494
1495     // XXX not applicable in v8
1496     QML_V4_BEGIN_INSTR(InitString, initstring)
1497 //        if (!identifiers[instr->initstring.offset].identifier) {
1498 //            quint32 len = *(quint32 *)(data + instr->initstring.dataIdx);
1499 //            QChar *strdata = (QChar *)(data + instr->initstring.dataIdx + sizeof(quint32));
1500
1501 //            QString str = QString::fromRawData(strdata, len);
1502
1503 //            // identifiers[instr->initstring.offset] = engine->objectClass->createPersistentIdentifier(str);
1504 //        }
1505     QML_V4_END_INSTR(InitString, initstring)
1506
1507     QML_V4_BEGIN_INSTR(CleanupRegister, cleanup)
1508         registers[instr->cleanup.reg].cleanup();
1509     QML_V4_END_INSTR(CleanupRegister, cleanup)
1510
1511 #ifdef QML_THREADED_INTERPRETER
1512     // nothing to do
1513 #else
1514     default:
1515         qFatal("QV4: Unknown instruction %d encountered.", instr->common.type);
1516         break;
1517     } // switch
1518
1519     } // while
1520 #endif
1521
1522     Q_ASSERT(!"Unreachable code reached");
1523
1524 programExit:
1525 exceptionExit:
1526     delete testBindingSource;
1527
1528     int reg = 0;
1529     while (cleanupRegisterMask) {
1530         if (cleanupRegisterMask & 0x1) 
1531             registers[reg].cleanup();
1532
1533         reg++;
1534         cleanupRegisterMask >>= 1;
1535     }
1536 }
1537
1538 QT_END_NAMESPACE