Support and use parameters in QQmlNotifierEndpoint.
[profile/ivi/qtdeclarative.git] / src / qml / qml / v4 / qv4bindings.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
5 **
6 ** This file is part of the QtQml module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
16 **
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
20 **
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
28 **
29 ** Other Usage
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
32 **
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/qqmlglobal_p.h>
50 #include <private/qqmlaccessors_p.h>
51 #include <private/qqmlprofilerservice_p.h>
52 #include <private/qqmlmetatype_p.h>
53 #include <private/qqmltrace_p.h>
54 #include <private/qqmlstringconverters_p.h>
55 #include <private/qqmlproperty_p.h>
56
57 #include <QtQml/qqmlinfo.h>
58 #include <QtCore/qnumeric.h>
59 #include <QtCore/qmath.h>
60 #include <math.h> // ::fmod
61
62 QT_BEGIN_NAMESPACE
63
64 using namespace QQmlJS;
65
66 namespace {
67 struct Register {
68     typedef QQmlRegisterType Type;
69
70     inline void setUndefined() { dataType = UndefinedType; }
71     inline void setNull() { dataType = NullType; }
72     inline void setNaN() { setnumber(qSNaN()); }
73     inline bool isUndefined() const { return dataType == UndefinedType; }
74
75     inline void setQObject(QObject *o) { qobjectValue = o; dataType = QObjectStarType; }
76     inline QObject *getQObject() const { return qobjectValue; }
77
78     inline void setnumber(double v) { numberValue = v; dataType = NumberType; }
79     inline double getnumber() const { return numberValue; }
80     inline double &getnumberref() { return numberValue; }
81
82     inline void setfloat(float v) { floatValue = v; dataType = FloatType; }
83     inline float getfloat() const { return floatValue; }
84     inline float &getfloatref() { return floatValue; }
85
86     inline void setint(int v) { intValue = v; dataType = IntType; }
87     inline int getint() const { return intValue; }
88     inline int &getintref() { return intValue; }
89
90     inline void setbool(bool v) { boolValue = v; dataType = BoolType; }
91     inline bool getbool() const { return boolValue; }
92     inline bool &getboolref() { return boolValue; }
93
94     inline QVariant *getvariantptr() { return (QVariant *)typeDataPtr(); }
95     inline QString *getstringptr() { return (QString *)typeDataPtr(); }
96     inline QUrl *geturlptr() { return (QUrl *)typeDataPtr(); }
97     inline const QVariant *getvariantptr() const { return (QVariant *)typeDataPtr(); }
98     inline const QString *getstringptr() const { return (QString *)typeDataPtr(); }
99     inline const QUrl *geturlptr() const { return (QUrl *)typeDataPtr(); }
100
101     size_t dataSize() { return sizeof(data); }
102     inline void *typeDataPtr() { return (void *)&data; }
103     inline void *typeMemory() { return (void *)data; }
104     inline const void *typeDataPtr() const { return (void *)&data; }
105     inline const void *typeMemory() const { return (void *)data; }
106
107     inline Type gettype() const { return dataType; }
108     inline void settype(Type t) { dataType = t; }
109
110     Type dataType;     // Type of data
111     union {
112         QObject *qobjectValue;
113         double numberValue;
114         float floatValue;
115         int intValue;
116         bool boolValue;
117         void *data[sizeof(QVariant)];
118         qint64 q_for_alignment_1;
119         double q_for_alignment_2;
120     };
121
122     inline void cleanup();
123     inline void cleanupString();
124     inline void cleanupUrl();
125     inline void cleanupColor();
126     inline void cleanupVariant();
127
128     inline void copy(const Register &other);
129     inline void init(Type type);
130 #ifdef REGISTER_CLEANUP_DEBUG
131     Register() {
132         type = 0;
133     }
134
135     ~Register() {
136         if (dataType >= FirstCleanupType)
137             qWarning("Register leaked of type %d", dataType);
138     }
139 #endif
140 };
141
142 void Register::cleanup()
143 {
144     if (dataType >= FirstCleanupType) {
145         if (dataType == QStringType) {
146             getstringptr()->~QString();
147         } else if (dataType == QUrlType) {
148             geturlptr()->~QUrl();
149         } else if (dataType == QColorType) {
150             QQml_valueTypeProvider()->destroyValueType(QMetaType::QColor, typeDataPtr(), dataSize());
151         } else if (dataType == QVariantType) {
152             getvariantptr()->~QVariant();
153         }
154     }
155     setUndefined();
156 }
157
158 void Register::cleanupString()
159 {
160     getstringptr()->~QString();
161     setUndefined();
162 }
163
164 void Register::cleanupUrl()
165 {
166     geturlptr()->~QUrl();
167     setUndefined();
168 }
169
170 void Register::cleanupColor()
171 {
172     QQml_valueTypeProvider()->destroyValueType(QMetaType::QColor, typeDataPtr(), dataSize());
173     setUndefined();
174 }
175
176 void Register::cleanupVariant()
177 {
178     getvariantptr()->~QVariant();
179     setUndefined();
180 }
181
182 void Register::copy(const Register &other)
183 {
184     *this = other;
185     if (other.dataType >= FirstCleanupType) {
186         if (other.dataType == QStringType) 
187             new (getstringptr()) QString(*other.getstringptr());
188         else if (other.dataType == QUrlType)
189             new (geturlptr()) QUrl(*other.geturlptr());
190         else if (other.dataType == QColorType)
191             QQml_valueTypeProvider()->copyValueType(QMetaType::QColor, other.typeDataPtr(), typeDataPtr(), dataSize());
192         else if (other.dataType == QVariantType)
193             new (getvariantptr()) QVariant(*other.getvariantptr());
194     } 
195 }
196
197 void Register::init(Type type)
198 {
199     dataType = type;
200     if (dataType >= FirstCleanupType) {
201         if (dataType == QStringType) 
202             new (getstringptr()) QString();
203         else if (dataType == QUrlType)
204             new (geturlptr()) QUrl();
205         else if (dataType == QColorType)
206             QQml_valueTypeProvider()->initValueType(QMetaType::QColor, typeDataPtr(), dataSize());
207         else if (dataType == QVariantType)
208             new (getvariantptr()) QVariant();
209     }
210 }
211
212 } // end of anonymous namespace
213
214 QV4Bindings::QV4Bindings(const char *programData, 
215                                                QQmlContextData *context, 
216                                                QQmlRefCount *ref)
217 : subscriptions(0), program(0), dataRef(0), bindings(0)
218 {
219     program = (QV4Program *)programData;
220     dataRef = ref;
221     if (dataRef) dataRef->addref();
222
223     if (program) {
224         subscriptions = new Subscription[program->subscriptions];
225         bindings = new Binding[program->bindings];
226
227         QQmlAbstractExpression::setContext(context);
228     }
229 }
230
231 QV4Bindings::~QV4Bindings()
232 {
233     delete [] bindings;
234     delete [] subscriptions; subscriptions = 0;
235     if (dataRef) dataRef->release();
236 }
237
238 QQmlAbstractBinding *QV4Bindings::configBinding(int index, QObject *target, 
239                                                         QObject *scope, int property,
240                                                         int line, int column)
241 {
242     Binding *rv = bindings + index;
243
244     rv->index = index;
245     rv->property = property;
246     rv->target = target;
247     rv->scope = scope;
248     rv->line = line;
249     rv->column = column;
250     rv->parent = this;
251
252     addref(); // This is decremented in Binding::destroy()
253
254     return rv;
255 }
256
257 void QV4Bindings::Binding::setEnabled(bool e, QQmlPropertyPrivate::WriteFlags flags)
258 {
259     if (enabled != e) {
260         enabled = e;
261
262         if (e) update(flags);
263     }
264 }
265
266 void QV4Bindings::Binding::update(QQmlPropertyPrivate::WriteFlags flags)
267 {
268     parent->run(this, flags);
269 }
270
271 void QV4Bindings::Binding::destroy()
272 {
273     enabled = false;
274     removeFromObject();
275     clear();
276     removeError();
277     parent->release();
278 }
279
280 int QV4Bindings::Binding::propertyIndex() const
281 {
282     //mask out the type information set for value types
283     return property & 0xFF00FFFF;
284 }
285
286 QObject *QV4Bindings::Binding::object() const
287 {
288     return target;
289 }
290
291 void QV4Bindings::Subscription::subscriptionCallback(QQmlNotifierEndpoint *e, void **)
292 {
293     Subscription *s = static_cast<Subscription *>(e);
294     s->bindings->subscriptionNotify(s->method);
295 }
296
297 void QV4Bindings::subscriptionNotify(int id)
298 {
299     QV4Program::BindingReferenceList *list = program->signalTable(id);
300
301     for (quint32 ii = 0; ii < list->count; ++ii) {
302         QV4Program::BindingReference *bindingRef = list->bindings + ii;
303
304         Binding *binding = bindings + bindingRef->binding;
305
306         if (binding->executedBlocks & bindingRef->blockMask) {
307             run(binding, QQmlPropertyPrivate::DontRemoveBinding);
308         }
309     }
310 }
311
312 void QV4Bindings::run(Binding *binding, QQmlPropertyPrivate::WriteFlags flags)
313 {
314     if (!binding->enabled)
315         return;
316
317     QQmlContextData *context = QQmlAbstractExpression::context();
318     if (!context || !context->isValid()) 
319         return;
320
321     QQmlTrace trace("V4 Binding Update");
322     trace.addDetail("URL", context->url);
323     trace.addDetail("Line", binding->line);
324     trace.addDetail("Column", binding->column);
325
326     QQmlBindingProfiler prof(context->urlString, binding->line, binding->column);
327
328     if (binding->updating) {
329         QString name;
330         if (binding->property & 0xFFFF0000) {
331             QQmlEnginePrivate *ep = QQmlEnginePrivate::get(context->engine);
332
333             QQmlValueType *vt = ep->valueTypes[(binding->property >> 16) & 0xFF];
334             Q_ASSERT(vt);
335
336             name = QLatin1String(binding->target->metaObject()->property(binding->property & 0xFFFF).name());
337             name.append(QLatin1String("."));
338             name.append(QLatin1String(vt->metaObject()->property(binding->property >> 24).name()));
339         } else {
340             name = QLatin1String(binding->target->metaObject()->property(binding->property).name());
341         }
342         qmlInfo(binding->target) << tr("Binding loop detected for property \"%1\"").arg(name);
343         return;
344     }
345
346     binding->updating = true;
347     if (binding->property & 0xFFFF0000) {
348         QQmlEnginePrivate *ep = QQmlEnginePrivate::get(context->engine);
349
350         QQmlValueType *vt = ep->valueTypes[(binding->property >> 16) & 0xFF];
351         Q_ASSERT(vt);
352         vt->read(binding->target, binding->property & 0xFFFF);
353
354         QObject *target = vt;
355         run(binding->index, binding->executedBlocks, context, binding, binding->scope, target, flags);
356
357         vt->write(binding->target, binding->property & 0xFFFF, flags);
358     } else {
359         run(binding->index, binding->executedBlocks, context, binding, binding->scope, binding->target, flags);
360     }
361     binding->updating = false;
362 }
363
364
365 void QV4Bindings::unsubscribe(int subIndex)
366 {
367     Subscription *sub = (subscriptions + subIndex);
368     sub->disconnect();
369 }
370
371 void QV4Bindings::subscribeId(QQmlContextData *p, int idIndex, int subIndex)
372 {
373     unsubscribe(subIndex);
374
375     if (p->idValues[idIndex]) {
376         Subscription *sub = (subscriptions + subIndex);
377         sub->bindings = this;
378         sub->method = subIndex;
379         sub->connect(&p->idValues[idIndex].bindings);
380     }
381 }
382  
383 void QV4Bindings::subscribe(QObject *o, int notifyIndex, int subIndex)
384 {
385     Subscription *sub = (subscriptions + subIndex);
386     if (sub->isConnected(o, notifyIndex))
387         return;
388     sub->bindings = this;
389     sub->method = subIndex; 
390     if (o)
391         sub->connect(o, notifyIndex);
392     else
393         sub->disconnect();
394 }
395
396 static bool testCompareVariants(const QVariant &qtscriptRaw, const QVariant &v4)
397 {
398     QVariant qtscript = qtscriptRaw;
399
400     if (qtscript.userType() == v4.userType()) {
401     } else if (qtscript.canConvert((QVariant::Type)v4.userType())) {
402         qtscript.convert((QVariant::Type)v4.userType());
403     } else if (qtscript.userType() == QVariant::Invalid && v4.userType() == QMetaType::QObjectStar) {
404         qtscript = qVariantFromValue<QObject *>(0);
405     } else {
406         return false;
407     }
408
409     int type = qtscript.userType();
410
411     if (type == QQmlMetaType::QQuickAnchorLineMetaTypeId()) {
412         return QQmlMetaType::QQuickAnchorLineCompare(qtscript.constData(), v4.constData());
413     } else if (type == QMetaType::Double) {
414
415         double la = qvariant_cast<double>(qtscript);
416         double lr = qvariant_cast<double>(v4);
417
418         return la == lr || (qIsNaN(la) && qIsNaN(lr));
419
420     } else if (type == QMetaType::Float) {
421
422         float la = qvariant_cast<float>(qtscript);
423         float lr = qvariant_cast<float>(v4);
424
425         return la == lr || (qIsNaN(la) && qIsNaN(lr));
426
427     } else {
428         return qtscript == v4;
429     }
430 }
431
432 QByteArray testResultToString(const QVariant &result, bool undefined)
433 {
434     if (undefined) {
435         return "undefined";
436     } else {
437         QString rv;
438         QDebug d(&rv);
439         d << result;
440         return rv.toUtf8();
441     }
442 }
443
444 static void testBindingResult(const QString &binding, int line, int column, 
445                               QQmlContextData *context, QObject *scope, 
446                               const Register &result, int resultType)
447 {
448     QQmlExpression expression(context->asQQmlContext(), scope, binding);
449     bool isUndefined = false;
450     QVariant value = expression.evaluate(&isUndefined);
451
452     bool iserror = false;
453     QByteArray qtscriptResult;
454     QByteArray v4Result;
455
456     if (expression.hasError()) {
457         iserror = true;
458         qtscriptResult = "exception";
459     } else if ((value.userType() != resultType) && (resultType != QMetaType::QVariant)) {
460         // Override the QMetaType conversions to make them more JS friendly.
461         if (value.userType() == QMetaType::Double && (resultType == QMetaType::QString ||
462                                                         resultType == QMetaType::QUrl)) {
463             // number to string-like conversion.
464             value = QVariant::fromValue<QString>(QString::number(value.toDouble(), 'g', 16));
465         } else if (value.userType() == QMetaType::QUrl && resultType == QMetaType::Bool) {
466             // url to bool conversion
467             value = QVariant::fromValue<bool>(!value.toUrl().isEmpty());
468         }
469
470         if (!value.isNull() && !value.convert(resultType)) {
471             iserror = true;
472             qtscriptResult = "exception";
473         } else if (resultType == QMetaType::QUrl) {
474             // a V8 value was converted to QUrl.
475             value = QVariant::fromValue<QUrl>(context->resolvedUrl(value.toUrl()));
476         }
477     }
478
479     if (! iserror)
480         qtscriptResult = testResultToString(value, isUndefined);
481
482     if (isUndefined && result.isUndefined()) {
483         return;
484     } else if(isUndefined != result.isUndefined()) {
485         iserror = true;
486     } 
487     
488     QVariant v4value;
489     if (!result.isUndefined()) {
490         switch (resultType) {
491         case QMetaType::QString:
492             v4value = *result.getstringptr();
493             break;
494         case QMetaType::QUrl:
495             v4value = *result.geturlptr();
496             break;
497         case QMetaType::QObjectStar:
498             v4value = qVariantFromValue<QObject *>(result.getQObject());
499             break;
500         case QMetaType::Bool:
501             v4value = result.getbool();
502             break;
503         case QMetaType::Int:
504             v4value = result.getint();
505             break;
506         case QMetaType::Double:
507             v4value = result.getnumber();
508             break;
509         case QMetaType::QColor:
510             v4value = QVariant(QMetaType::QColor, result.typeDataPtr());
511             break;
512         case QMetaType::QVariant:
513             v4value = *result.getvariantptr();
514             break;
515         default:
516             if (resultType == QQmlMetaType::QQuickAnchorLineMetaTypeId()) {
517                 v4value = QVariant(QQmlMetaType::QQuickAnchorLineMetaTypeId(), result.typeDataPtr());
518             } else {
519                 iserror = true;
520                 v4Result = "Unknown V4 type";
521             }
522         }
523     }
524     if (v4Result.isEmpty())
525         v4Result = testResultToString(v4value, result.isUndefined());
526
527     if (!testCompareVariants(value, v4value)) 
528         iserror = true;
529
530     if (iserror) {
531         qWarning().nospace() << "QV4: Optimization error @" << context->url.toString().toUtf8().constData() << ":" << line << ":" << column;
532
533         qWarning().nospace() << "    Binding:  " << binding;
534         qWarning().nospace() << "    QtScript: " << qtscriptResult.constData();
535         qWarning().nospace() << "    V4:       " << v4Result.constData();
536     }
537 }
538
539 static void testBindingException(const QString &binding, int line, int column, 
540                                  QQmlContextData *context, QObject *scope)
541 {
542     QQmlExpression expression(context->asQQmlContext(), scope, binding);
543     bool isUndefined = false;
544     QVariant value = expression.evaluate(&isUndefined);
545
546     if (!expression.hasError()) {
547         QByteArray qtscriptResult = testResultToString(value, isUndefined);
548         qWarning().nospace() << "QV4: Optimization error @" << context->url.toString().toUtf8().constData() << ":" << line << ":" << column;
549         qWarning().nospace() << "    Binding:  " << binding;
550         qWarning().nospace() << "    QtScript: " << qtscriptResult.constData();
551         qWarning().nospace() << "    V4:       exception";
552     }
553 }
554
555 static void throwException(int id, QQmlDelayedError *error, 
556                            QV4Program *program, QQmlContextData *context,
557                            const QString &description = QString())
558 {
559     error->error.setUrl(context->url);
560     if (description.isEmpty())
561         error->error.setDescription(QLatin1String("TypeError: Result of expression is not an object"));
562     else
563         error->error.setDescription(description);
564     if (id != 0xFF) {
565         quint64 e = *((quint64 *)(program->data() + program->exceptionDataOffset) + id); 
566         error->error.setLine((e >> 32) & 0xFFFFFFFF);
567         error->error.setColumn(e & 0xFFFFFFFF); 
568     } else {
569         error->error.setLine(-1);
570         error->error.setColumn(-1);
571     }
572     if (!context->engine || !error->addError(QQmlEnginePrivate::get(context->engine)))
573         QQmlEnginePrivate::warning(context->engine, error->error);
574 }
575
576 const double QV4Bindings::D32 = 4294967296.0;
577
578 qint32 QV4Bindings::toInt32(double n)
579 {
580     if (qIsNaN(n) || qIsInf(n) || (n == 0))
581         return 0;
582
583     double sign = (n < 0) ? -1.0 : 1.0;
584     double abs_n = fabs(n);
585
586     n = ::fmod(sign * ::floor(abs_n), D32);
587     const double D31 = D32 / 2.0;
588
589     if (sign == -1 && n < -D31)
590         n += D32;
591
592     else if (sign != -1 && n >= D31)
593         n -= D32;
594
595     return qint32 (n);
596 }
597
598 inline quint32 QV4Bindings::toUint32(double n)
599 {
600     if (qIsNaN(n) || qIsInf(n) || (n == 0))
601         return 0;
602
603     double sign = (n < 0) ? -1.0 : 1.0;
604     double abs_n = fabs(n);
605
606     n = ::fmod(sign * ::floor(abs_n), D32);
607
608     if (n < 0)
609         n += D32;
610
611     return quint32 (n);
612 }
613
614 #define THROW_EXCEPTION_STR(id, str) { \
615     if (testBinding) testBindingException(*testBindingSource, bindingLine, bindingColumn, context, scope); \
616     throwException((id), error, program, context, (str)); \
617     goto exceptionExit; \
618
619
620 #define THROW_VALUE_EXCEPTION_STR(id, str) { \
621     throwException((id), error, program, context, (str)); \
622     goto exceptionExit; \
623 }
624
625 #define THROW_EXCEPTION(id) THROW_EXCEPTION_STR(id, QString())
626
627 #define MARK_REGISTER(reg) cleanupRegisterMask |= (1 << (reg))
628 #define MARK_CLEAN_REGISTER(reg) cleanupRegisterMask &= ~(1 << (reg))
629
630 #define STRING_REGISTER(reg) { \
631     registers[(reg)].settype(QStringType); \
632     MARK_REGISTER(reg); \
633 }
634
635 #define URL_REGISTER(reg) { \
636     registers[(reg)].settype(QUrlType); \
637     MARK_REGISTER(reg); \
638 }
639
640 #define COLOR_REGISTER(reg) { \
641     registers[(reg)].settype(QColorType); \
642     MARK_REGISTER(reg); \
643 }
644
645 #define VARIANT_REGISTER(reg) { \
646     registers[(reg)].settype(QVariantType); \
647     MARK_REGISTER(reg); \
648 }
649
650 #ifdef QML_THREADED_INTERPRETER
651 void **QV4Bindings::getDecodeInstrTable()
652 {
653     static void **decode_instr;
654     if (!decode_instr) {
655         QV4Bindings *dummy = new QV4Bindings(0, 0, 0);
656         quint32 executedBlocks = 0;
657         dummy->run(0, executedBlocks, 0, 0, 0, 0, 
658                    QQmlPropertyPrivate::BypassInterceptor, 
659                    &decode_instr);
660         dummy->release();
661     }
662     return decode_instr;
663 }
664 #endif
665
666 void QV4Bindings::run(int instrIndex, quint32 &executedBlocks,
667                                  QQmlContextData *context, QQmlDelayedError *error,
668                                  QObject *scope, QObject *output, 
669                                  QQmlPropertyPrivate::WriteFlags storeFlags
670 #ifdef QML_THREADED_INTERPRETER
671                                  ,void ***table
672 #endif
673                                  )
674 {
675 #ifdef QML_THREADED_INTERPRETER
676     if (table) {
677         static void *decode_instr[] = {
678             FOR_EACH_V4_INSTR(QML_V4_INSTR_ADDR)
679         };
680
681         *table = decode_instr;
682         return;
683     }
684 #endif
685
686
687     error->removeError();
688
689     Register registers[32];
690     quint32 cleanupRegisterMask = 0;
691
692     executedBlocks = 0;
693
694     const char *code = program->instructions();
695     code += instrIndex * QML_V4_INSTR_SIZE(Jump, jump);
696     const V4Instr *instr = reinterpret_cast<const V4Instr *>(code);
697
698     const char *data = program->data();
699
700     QString *testBindingSource = 0;
701     bool testBinding = false;
702     int bindingLine = 0;
703     int bindingColumn = 0;
704
705 #ifdef QML_THREADED_INTERPRETER
706     goto *instr->common.code;
707 #else
708     for (;;) {
709         switch (instr->common.type) {
710 #endif
711
712     QML_V4_BEGIN_INSTR(Noop, common)
713     QML_V4_END_INSTR(Noop, common)
714
715     QML_V4_BEGIN_INSTR(BindingId, id)
716         bindingLine = instr->id.line;
717         bindingColumn = instr->id.column;
718     QML_V4_END_INSTR(BindingId, id)
719
720     QML_V4_BEGIN_INSTR(SubscribeId, subscribeop)
721         subscribeId(context, instr->subscribeop.index, instr->subscribeop.offset);
722     QML_V4_END_INSTR(SubscribeId, subscribeop)
723
724     QML_V4_BEGIN_INSTR(Subscribe, subscribeop)
725     {
726         QObject *o = 0;
727         const Register &object = registers[instr->subscribeop.reg];
728         if (!object.isUndefined()) o = object.getQObject();
729         subscribe(o, instr->subscribeop.index, instr->subscribeop.offset);
730     }
731     QML_V4_END_INSTR(Subscribe, subscribeop)
732
733     QML_V4_BEGIN_INSTR(FetchAndSubscribe, fetchAndSubscribe)
734     {
735         Register &reg = registers[instr->fetchAndSubscribe.reg];
736
737         if (reg.isUndefined()) 
738             THROW_EXCEPTION(instr->fetchAndSubscribe.exceptionId);
739
740         QObject *object = reg.getQObject();
741         if (!object) {
742             reg.setUndefined();
743         } else {
744             int subIdx = instr->fetchAndSubscribe.subscription;
745             Subscription *sub = 0;
746             if (subIdx != -1) {
747                 sub = (subscriptions + subIdx);
748                 sub->bindings = this;
749                 sub->method = subIdx;
750             }
751
752             const Register::Type valueType = (Register::Type)instr->fetchAndSubscribe.valueType;
753             reg.init(valueType);
754             if (instr->fetchAndSubscribe.valueType >= FirstCleanupType)
755                 MARK_REGISTER(instr->fetchAndSubscribe.reg);
756             QQmlAccessors *accessors = instr->fetchAndSubscribe.property.accessors;
757             accessors->read(object, instr->fetchAndSubscribe.property.accessorData,
758                             reg.typeDataPtr());
759
760             if (valueType == FloatType) {
761                 // promote floats
762                 const double v = reg.getfloat();
763                 reg.setnumber(v);
764             }
765
766             if (accessors->notifier) {
767                 QQmlNotifier *notifier = 0;
768                 accessors->notifier(object, instr->fetchAndSubscribe.property.accessorData, &notifier);
769                 if (notifier) sub->connect(notifier);
770             } else if (instr->fetchAndSubscribe.property.notifyIndex != -1) {
771                 sub->connect(object, instr->fetchAndSubscribe.property.notifyIndex);
772             }
773         }
774     }
775     QML_V4_END_INSTR(FetchAndSubscribe, fetchAndSubscribe)
776
777     QML_V4_BEGIN_INSTR(LoadId, load)
778         registers[instr->load.reg].setQObject(context->idValues[instr->load.index].data());
779     QML_V4_END_INSTR(LoadId, load)
780
781     QML_V4_BEGIN_INSTR(LoadScope, load)
782         registers[instr->load.reg].setQObject(scope);
783     QML_V4_END_INSTR(LoadScope, load)
784
785     QML_V4_BEGIN_INSTR(LoadRoot, load)
786         registers[instr->load.reg].setQObject(context->contextObject);
787     QML_V4_END_INSTR(LoadRoot, load)
788
789     QML_V4_BEGIN_INSTR(LoadModuleObject, load)
790     {
791         Register &reg = registers[instr->load.reg];
792
793         const QString *name = reg.getstringptr();
794         QQmlTypeNameCache::Result r = context->imports->query(*name);
795         reg.cleanupString();
796
797         if (r.isValid() && r.importNamespace) {
798             QQmlMetaType::ModuleApiInstance *moduleApi = context->imports->moduleApi(r.importNamespace);
799             if (moduleApi) {
800                 if (moduleApi->qobjectCallback) {
801                     moduleApi->qobjectApi = moduleApi->qobjectCallback(context->engine, context->engine);
802                     moduleApi->qobjectCallback = 0;
803                     moduleApi->scriptCallback = 0;
804                 }
805                 if (moduleApi->qobjectApi)
806                     reg.setQObject(moduleApi->qobjectApi);
807             }
808         }
809     }
810     QML_V4_END_INSTR(LoadModuleObject, load)
811
812     QML_V4_BEGIN_INSTR(LoadAttached, attached)
813     {
814         const Register &input = registers[instr->attached.reg];
815         Register &output = registers[instr->attached.output];
816         if (input.isUndefined()) 
817             THROW_EXCEPTION(instr->attached.exceptionId);
818
819         QObject *object = registers[instr->attached.reg].getQObject();
820         if (!object) {
821             output.setUndefined();
822         } else {
823             QObject *attached = qmlAttachedPropertiesObjectById(instr->attached.id, input.getQObject(), true);
824             Q_ASSERT(attached);
825             output.setQObject(attached);
826         }
827     }
828     QML_V4_END_INSTR(LoadAttached, attached)
829
830     QML_V4_BEGIN_INSTR(UnaryNot, unaryop)
831     {
832         registers[instr->unaryop.output].setbool(!registers[instr->unaryop.src].getbool());
833     }
834     QML_V4_END_INSTR(UnaryNot, unaryop)
835
836     QML_V4_BEGIN_INSTR(UnaryMinusNumber, unaryop)
837     {
838         registers[instr->unaryop.output].setnumber(-registers[instr->unaryop.src].getnumber());
839     }
840     QML_V4_END_INSTR(UnaryMinusNumber, unaryop)
841
842     QML_V4_BEGIN_INSTR(UnaryMinusInt, unaryop)
843     {
844         registers[instr->unaryop.output].setint(-registers[instr->unaryop.src].getint());
845     }
846     QML_V4_END_INSTR(UnaryMinusInt, unaryop)
847
848     QML_V4_BEGIN_INSTR(UnaryPlusNumber, unaryop)
849     {
850         registers[instr->unaryop.output].setnumber(+registers[instr->unaryop.src].getnumber());
851     }
852     QML_V4_END_INSTR(UnaryPlusNumber, unaryop)
853
854     QML_V4_BEGIN_INSTR(UnaryPlusInt, unaryop)
855     {
856         registers[instr->unaryop.output].setint(+registers[instr->unaryop.src].getint());
857     }
858     QML_V4_END_INSTR(UnaryPlusInt, unaryop)
859
860     QML_V4_BEGIN_INSTR(ConvertBoolToInt, unaryop)
861     {
862         const Register &src = registers[instr->unaryop.src];
863         Register &output = registers[instr->unaryop.output];
864         if (src.isUndefined()) output.setUndefined();
865         else output.setint(src.getbool());
866     }
867     QML_V4_END_INSTR(ConvertBoolToInt, unaryop)
868
869     QML_V4_BEGIN_INSTR(ConvertBoolToNumber, unaryop)
870     {
871         const Register &src = registers[instr->unaryop.src];
872         Register &output = registers[instr->unaryop.output];
873         if (src.isUndefined()) output.setUndefined();
874         else output.setnumber(src.getbool());
875     }
876     QML_V4_END_INSTR(ConvertBoolToNumber, unaryop)
877
878     QML_V4_BEGIN_INSTR(ConvertBoolToString, unaryop)
879     {
880         const Register &src = registers[instr->unaryop.src];
881         Register &output = registers[instr->unaryop.output];
882         if (src.isUndefined()) {
883             output.setUndefined();
884         } else { 
885             new (output.getstringptr()) QString(QLatin1String(src.getbool() ? "true" : "false"));
886             STRING_REGISTER(instr->unaryop.output);
887         }
888     }
889     QML_V4_END_INSTR(ConvertBoolToString, unaryop)
890
891     QML_V4_BEGIN_INSTR(ConvertBoolToVariant, unaryop)
892     {
893         const Register &src = registers[instr->unaryop.src];
894         Register &output = registers[instr->unaryop.output];
895         if (src.isUndefined()) {
896             output.setUndefined();
897         } else {
898             new (output.getvariantptr()) QVariant(src.getbool());
899             VARIANT_REGISTER(instr->unaryop.output);
900         }
901     }
902     QML_V4_END_INSTR(ConvertBoolToVariant, unaryop)
903
904     QML_V4_BEGIN_INSTR(ConvertIntToBool, unaryop)
905     {
906         const Register &src = registers[instr->unaryop.src];
907         Register &output = registers[instr->unaryop.output];
908         if (src.isUndefined()) output.setUndefined();
909         else output.setbool(src.getint());
910     }
911     QML_V4_END_INSTR(ConvertIntToBool, unaryop)
912
913     QML_V4_BEGIN_INSTR(ConvertIntToNumber, unaryop)
914     {
915         const Register &src = registers[instr->unaryop.src];
916         Register &output = registers[instr->unaryop.output];
917         if (src.isUndefined()) output.setUndefined();
918         else output.setnumber(double(src.getint()));
919     }
920     QML_V4_END_INSTR(ConvertIntToNumber, unaryop)
921
922     QML_V4_BEGIN_INSTR(ConvertIntToString, unaryop)
923     {
924         const Register &src = registers[instr->unaryop.src];
925         Register &output = registers[instr->unaryop.output];
926         if (src.isUndefined()) {
927             output.setUndefined();
928         } else {
929             new (output.getstringptr()) QString(QString::number(src.getint()));
930             STRING_REGISTER(instr->unaryop.output);
931         }
932     }
933     QML_V4_END_INSTR(ConvertIntToString, unaryop)
934
935     QML_V4_BEGIN_INSTR(ConvertIntToVariant, unaryop)
936     {
937         const Register &src = registers[instr->unaryop.src];
938         Register &output = registers[instr->unaryop.output];
939         if (src.isUndefined()) {
940             output.setUndefined();
941         } else {
942             new (output.getvariantptr()) QVariant(src.getint());
943             VARIANT_REGISTER(instr->unaryop.output);
944         }
945     }
946     QML_V4_END_INSTR(ConvertIntToVariant, unaryop)
947
948     QML_V4_BEGIN_INSTR(ConvertNumberToBool, unaryop)
949     {
950         const Register &src = registers[instr->unaryop.src];
951         Register &output = registers[instr->unaryop.output];
952         if (src.isUndefined()) output.setUndefined();
953         else output.setbool(src.getnumber() != 0);
954     }
955     QML_V4_END_INSTR(ConvertNumberToBool, unaryop)
956
957     QML_V4_BEGIN_INSTR(ConvertNumberToInt, unaryop)
958     {
959         const Register &src = registers[instr->unaryop.src];
960         Register &output = registers[instr->unaryop.output];
961         if (src.isUndefined()) output.setUndefined();
962         else output.setint(toInt32(src.getnumber()));
963     }
964     QML_V4_END_INSTR(ConvertNumberToInt, unaryop)
965
966     QML_V4_BEGIN_INSTR(ConvertNumberToString, unaryop)
967     {
968         const Register &src = registers[instr->unaryop.src];
969         Register &output = registers[instr->unaryop.output];
970         // ### NaN
971         if (src.isUndefined()) {
972             output.setUndefined();
973         } else {
974             new (output.getstringptr()) QString(QString::number(src.getnumber(), 'g', 16));
975             STRING_REGISTER(instr->unaryop.output);
976         }
977     }
978     QML_V4_END_INSTR(ConvertNumberToString, unaryop)
979
980     QML_V4_BEGIN_INSTR(ConvertNumberToVariant, unaryop)
981     {
982         const Register &src = registers[instr->unaryop.src];
983         Register &output = registers[instr->unaryop.output];
984         if (src.isUndefined()) {
985             output.setUndefined();
986         } else {
987             new (output.getvariantptr()) QVariant(src.getnumber());
988             VARIANT_REGISTER(instr->unaryop.output);
989         }
990     }
991     QML_V4_END_INSTR(ConvertNumberToVariant, unaryop)
992
993     QML_V4_BEGIN_INSTR(ConvertStringToBool, unaryop)
994     {
995         const Register &src = registers[instr->unaryop.src];
996         Register &output = registers[instr->unaryop.output];
997         // ### NaN
998         if (src.isUndefined()) {
999             output.setUndefined();
1000         } else {
1001             // Delegate the conversion. This is pretty fast and it doesn't require a QScriptEngine.
1002             // Ideally we should just call the methods in the QScript namespace directly.
1003             QJSValue tmp(*src.getstringptr());
1004             if (instr->unaryop.src == instr->unaryop.output) {
1005                 output.cleanupString();
1006                 MARK_CLEAN_REGISTER(instr->unaryop.output);
1007             }
1008             output.setbool(tmp.toBool());
1009         }
1010     }
1011     QML_V4_END_INSTR(ConvertStringToBool, unaryop)
1012
1013     QML_V4_BEGIN_INSTR(ConvertStringToInt, unaryop)
1014     {
1015         const Register &src = registers[instr->unaryop.src];
1016         Register &output = registers[instr->unaryop.output];
1017         // ### NaN
1018         if (src.isUndefined()) {
1019             output.setUndefined();
1020         } else {
1021             // Delegate the conversion. This is pretty fast and it doesn't require a QScriptEngine.
1022             // Ideally we should just call the methods in the QScript namespace directly.
1023             QJSValue tmp(*src.getstringptr());
1024             if (instr->unaryop.src == instr->unaryop.output) {
1025                 output.cleanupString();
1026                 MARK_CLEAN_REGISTER(instr->unaryop.output);
1027             }
1028             output.setint(tmp.toInt());
1029         }
1030     }
1031     QML_V4_END_INSTR(ConvertStringToInt, unaryop)
1032
1033     QML_V4_BEGIN_INSTR(ConvertStringToNumber, unaryop)
1034     {
1035         const Register &src = registers[instr->unaryop.src];
1036         Register &output = registers[instr->unaryop.output];
1037         // ### NaN
1038         if (src.isUndefined()) {
1039             output.setUndefined();
1040         } else {
1041             // Delegate the conversion. This is pretty fast and it doesn't require a QScriptEngine.
1042             // Ideally we should just call the methods in the QScript namespace directly.
1043             QJSValue tmp(*src.getstringptr());
1044             if (instr->unaryop.src == instr->unaryop.output) {
1045                 output.cleanupString();
1046                 MARK_CLEAN_REGISTER(instr->unaryop.output);
1047             }
1048             output.setnumber(tmp.toNumber());
1049         }
1050     }
1051     QML_V4_END_INSTR(ConvertStringToNumber, unaryop)
1052
1053     QML_V4_BEGIN_INSTR(ConvertStringToUrl, unaryop)
1054     {
1055         const Register &src = registers[instr->unaryop.src];
1056         Register &output = registers[instr->unaryop.output];
1057         // ### NaN
1058         if (src.isUndefined()) {
1059             output.setUndefined();
1060         } else {
1061             const QString tmp(*src.getstringptr());
1062             if (instr->unaryop.src == instr->unaryop.output) {
1063                 output.cleanupString();
1064                 MARK_CLEAN_REGISTER(instr->unaryop.output);
1065             }
1066             new (output.geturlptr()) QUrl(tmp);
1067
1068             URL_REGISTER(instr->unaryop.output);
1069         }
1070     }
1071     QML_V4_END_INSTR(ConvertStringToUrl, unaryop)
1072
1073     QML_V4_BEGIN_INSTR(ConvertStringToColor, unaryop)
1074     {
1075         const Register &src = registers[instr->unaryop.src];
1076         Register &output = registers[instr->unaryop.output];
1077         // ### NaN
1078         if (src.isUndefined()) {
1079             output.setUndefined();
1080         } else {
1081             const QString tmp(*src.getstringptr());
1082             if (instr->unaryop.src == instr->unaryop.output) {
1083                 output.cleanupString();
1084                 MARK_CLEAN_REGISTER(instr->unaryop.output);
1085             }
1086             QQml_valueTypeProvider()->createValueFromString(QMetaType::QColor, tmp, output.typeDataPtr(), output.dataSize());
1087
1088             COLOR_REGISTER(instr->unaryop.output);
1089         }
1090     }
1091     QML_V4_END_INSTR(ConvertStringToUrl, unaryop)
1092
1093     QML_V4_BEGIN_INSTR(ConvertStringToVariant, unaryop)
1094     {
1095         const Register &src = registers[instr->unaryop.src];
1096         Register &output = registers[instr->unaryop.output];
1097         if (src.isUndefined()) {
1098             output.setUndefined();
1099         } else {
1100             const QString tmp(*src.getstringptr());
1101             if (instr->unaryop.src == instr->unaryop.output) {
1102                 output.cleanupString();
1103                 MARK_CLEAN_REGISTER(instr->unaryop.output);
1104             }
1105             new (output.getvariantptr()) QVariant(tmp);
1106
1107             VARIANT_REGISTER(instr->unaryop.output);
1108         }
1109     }
1110     QML_V4_END_INSTR(ConvertStringToVariant, unaryop)
1111
1112     QML_V4_BEGIN_INSTR(ConvertUrlToBool, unaryop)
1113     {
1114         const Register &src = registers[instr->unaryop.src];
1115         Register &output = registers[instr->unaryop.output];
1116         // ### NaN
1117         if (src.isUndefined()) {
1118             output.setUndefined();
1119         } else {
1120             const QUrl tmp(*src.geturlptr());
1121             if (instr->unaryop.src == instr->unaryop.output) {
1122                 output.cleanupUrl();
1123                 MARK_CLEAN_REGISTER(instr->unaryop.output);
1124             }
1125             output.setbool(!tmp.isEmpty());
1126         }
1127     }
1128     QML_V4_END_INSTR(ConvertUrlToBool, unaryop)
1129
1130     QML_V4_BEGIN_INSTR(ConvertUrlToString, unaryop)
1131     {
1132         const Register &src = registers[instr->unaryop.src];
1133         Register &output = registers[instr->unaryop.output];
1134         // ### NaN
1135         if (src.isUndefined()) {
1136             output.setUndefined();
1137         } else {
1138             const QUrl tmp(*src.geturlptr());
1139             if (instr->unaryop.src == instr->unaryop.output) {
1140                 output.cleanupUrl();
1141                 MARK_CLEAN_REGISTER(instr->unaryop.output);
1142             }
1143             new (output.getstringptr()) QString(tmp.toString());
1144             STRING_REGISTER(instr->unaryop.output);
1145         }
1146     }
1147     QML_V4_END_INSTR(ConvertUrlToString, unaryop)
1148
1149     QML_V4_BEGIN_INSTR(ConvertUrlToVariant, unaryop)
1150     {
1151         const Register &src = registers[instr->unaryop.src];
1152         Register &output = registers[instr->unaryop.output];
1153         // ### NaN
1154         if (src.isUndefined()) {
1155             output.setUndefined();
1156         } else {
1157             const QUrl tmp(*src.geturlptr());
1158             if (instr->unaryop.src == instr->unaryop.output) {
1159                 output.cleanupUrl();
1160                 MARK_CLEAN_REGISTER(instr->unaryop.output);
1161             }
1162             new (output.getvariantptr()) QVariant(tmp);
1163             VARIANT_REGISTER(instr->unaryop.output);
1164         }
1165     }
1166     QML_V4_END_INSTR(ConvertUrlToVariant, unaryop)
1167
1168     QML_V4_BEGIN_INSTR(ConvertColorToBool, unaryop)
1169     {
1170         const Register &src = registers[instr->unaryop.src];
1171         Register &output = registers[instr->unaryop.output];
1172         // ### NaN
1173         if (src.isUndefined()) {
1174             output.setUndefined();
1175         } else {
1176             // for compatibility with color behavior in v8, always true
1177             output.setbool(true);
1178         }
1179     }
1180     QML_V4_END_INSTR(ConvertColorToBool, unaryop)
1181
1182     QML_V4_BEGIN_INSTR(ConvertColorToString, unaryop)
1183     {
1184         const Register &src = registers[instr->unaryop.src];
1185         Register &output = registers[instr->unaryop.output];
1186         // ### NaN
1187         if (src.isUndefined()) {
1188             output.setUndefined();
1189         } else {
1190             QQml_valueTypeProvider()->createStringFromValue(QMetaType::QColor, src.typeDataPtr(), output.getstringptr());
1191             STRING_REGISTER(instr->unaryop.output);
1192         }
1193     }
1194     QML_V4_END_INSTR(ConvertColorToString, unaryop)
1195
1196     QML_V4_BEGIN_INSTR(ConvertColorToVariant, unaryop)
1197     {
1198         const Register &src = registers[instr->unaryop.src];
1199         Register &output = registers[instr->unaryop.output];
1200         // ### NaN
1201         if (src.isUndefined()) {
1202             output.setUndefined();
1203         } else {
1204             QVariant tmp(QMetaType::QColor, src.typeDataPtr());
1205             if (instr->unaryop.src == instr->unaryop.output) {
1206                 output.cleanupColor();
1207                 MARK_CLEAN_REGISTER(instr->unaryop.output);
1208             }
1209             new (output.getvariantptr()) QVariant(tmp);
1210             VARIANT_REGISTER(instr->unaryop.output);
1211         }
1212     }
1213     QML_V4_END_INSTR(ConvertColorToVariant, unaryop)
1214
1215     QML_V4_BEGIN_INSTR(ConvertObjectToBool, unaryop)
1216     {
1217         const Register &src = registers[instr->unaryop.src];
1218         Register &output = registers[instr->unaryop.output];
1219         // ### NaN
1220         if (src.isUndefined())
1221             output.setUndefined();
1222         else
1223             output.setbool(src.getQObject() != 0);
1224     }
1225     QML_V4_END_INSTR(ConvertObjectToBool, unaryop)
1226
1227     QML_V4_BEGIN_INSTR(ConvertObjectToVariant, unaryop)
1228     {
1229         const Register &src = registers[instr->unaryop.src];
1230         Register &output = registers[instr->unaryop.output];
1231         // ### NaN
1232         if (src.isUndefined())
1233             output.setUndefined();
1234         else {
1235             new (output.getvariantptr()) QVariant(qVariantFromValue<QObject *>(src.getQObject()));
1236             VARIANT_REGISTER(instr->unaryop.output);
1237         }
1238     }
1239     QML_V4_END_INSTR(ConvertObjectToVariant, unaryop)
1240
1241     QML_V4_BEGIN_INSTR(ConvertNullToObject, unaryop)
1242     {
1243         Register &output = registers[instr->unaryop.output];
1244         output.setQObject(0);
1245     }
1246     QML_V4_END_INSTR(ConvertNullToObject, unaryop)
1247
1248     QML_V4_BEGIN_INSTR(ConvertNullToVariant, unaryop)
1249     {
1250         Register &output = registers[instr->unaryop.output];
1251         new (output.getvariantptr()) QVariant();
1252         VARIANT_REGISTER(instr->unaryop.output);
1253     }
1254     QML_V4_END_INSTR(ConvertNullToVariant, unaryop)
1255
1256     QML_V4_BEGIN_INSTR(ResolveUrl, unaryop)
1257     {
1258         const Register &src = registers[instr->unaryop.src];
1259         Register &output = registers[instr->unaryop.output];
1260         if (src.isUndefined()) {
1261             output.setUndefined();
1262         } else {
1263             const QUrl tmp(*src.geturlptr());
1264             if (instr->unaryop.src == instr->unaryop.output) {
1265                 *output.geturlptr() = context->resolvedUrl(tmp);
1266             } else {
1267                 new (output.geturlptr()) QUrl(context->resolvedUrl(tmp));
1268                 URL_REGISTER(instr->unaryop.output);
1269             }
1270         }
1271     }
1272     QML_V4_END_INSTR(ResolveUrl, unaryop)
1273
1274     QML_V4_BEGIN_INSTR(MathSinNumber, unaryop)
1275     {
1276         const Register &src = registers[instr->unaryop.src];
1277         Register &output = registers[instr->unaryop.output];
1278         if (src.isUndefined()) output.setUndefined();
1279         else output.setnumber(qSin(src.getnumber()));
1280     }
1281     QML_V4_END_INSTR(MathSinNumber, unaryop)
1282
1283     QML_V4_BEGIN_INSTR(MathCosNumber, unaryop)
1284     {
1285         const Register &src = registers[instr->unaryop.src];
1286         Register &output = registers[instr->unaryop.output];
1287         if (src.isUndefined()) output.setUndefined();
1288         else output.setnumber(qCos(src.getnumber()));
1289     }
1290     QML_V4_END_INSTR(MathCosNumber, unaryop)
1291
1292     QML_V4_BEGIN_INSTR(MathAbsNumber, unaryop)
1293     {
1294         const Register &src = registers[instr->unaryop.src];
1295         Register &output = registers[instr->unaryop.output];
1296         if (src.isUndefined()) output.setUndefined();
1297         else output.setnumber(qAbs(src.getnumber()));
1298     }
1299     QML_V4_END_INSTR(MathAbsNumber, unaryop)
1300
1301     QML_V4_BEGIN_INSTR(MathRoundNumber, unaryop)
1302     {
1303         const Register &src = registers[instr->unaryop.src];
1304         Register &output = registers[instr->unaryop.output];
1305         if (src.isUndefined()) output.setUndefined();
1306         else output.setint(qRound(src.getnumber()));
1307     }
1308     QML_V4_END_INSTR(MathRoundNumber, unaryop)
1309
1310     QML_V4_BEGIN_INSTR(MathFloorNumber, unaryop)
1311     {
1312         const Register &src = registers[instr->unaryop.src];
1313         Register &output = registers[instr->unaryop.output];
1314         if (src.isUndefined()) output.setUndefined();
1315         else output.setint(qFloor(src.getnumber()));
1316     }
1317     QML_V4_END_INSTR(MathFloorNumber, unaryop)
1318
1319     QML_V4_BEGIN_INSTR(MathCeilNumber, unaryop)
1320     {
1321         const Register &src = registers[instr->unaryop.src];
1322         Register &output = registers[instr->unaryop.output];
1323         if (src.isUndefined()) output.setUndefined();
1324         else output.setint(qCeil(src.getnumber()));
1325     }
1326     QML_V4_END_INSTR(MathCeilNumber, unaryop)
1327
1328     QML_V4_BEGIN_INSTR(MathPINumber, unaryop)
1329     {
1330         static const double qmlPI = 2.0 * qAsin(1.0);
1331         Register &output = registers[instr->unaryop.output];
1332         output.setnumber(qmlPI);
1333     }
1334     QML_V4_END_INSTR(MathPINumber, unaryop)
1335
1336     QML_V4_BEGIN_INSTR(LoadNull, null_value)
1337         registers[instr->null_value.reg].setNull();
1338     QML_V4_END_INSTR(LoadNull, null_value)
1339
1340     QML_V4_BEGIN_INSTR(LoadNumber, number_value)
1341         registers[instr->number_value.reg].setnumber(instr->number_value.value);
1342     QML_V4_END_INSTR(LoadNumber, number_value)
1343
1344     QML_V4_BEGIN_INSTR(LoadInt, int_value)
1345         registers[instr->int_value.reg].setint(instr->int_value.value);
1346     QML_V4_END_INSTR(LoadInt, int_value)
1347
1348     QML_V4_BEGIN_INSTR(LoadBool, bool_value)
1349         registers[instr->bool_value.reg].setbool(instr->bool_value.value);
1350     QML_V4_END_INSTR(LoadBool, bool_value)
1351
1352     QML_V4_BEGIN_INSTR(LoadString, string_value)
1353     {
1354         Register &output = registers[instr->string_value.reg];
1355         QChar *string = (QChar *)(data + instr->string_value.offset);
1356         new (output.getstringptr()) QString(string, instr->string_value.length);
1357         STRING_REGISTER(instr->string_value.reg);
1358     }
1359     QML_V4_END_INSTR(LoadString, string_value)
1360
1361     QML_V4_BEGIN_INSTR(EnableV4Test, string_value)
1362     {
1363         testBindingSource = new QString((QChar *)(data + instr->string_value.offset), instr->string_value.length);
1364         testBinding = true;
1365     }
1366     QML_V4_END_INSTR(String, string_value)
1367
1368     QML_V4_BEGIN_INSTR(BitAndInt, binaryop)
1369     {
1370         registers[instr->binaryop.output].setint(registers[instr->binaryop.left].getint() & 
1371                                                  registers[instr->binaryop.right].getint());
1372     }
1373     QML_V4_END_INSTR(BitAndInt, binaryop)
1374
1375     QML_V4_BEGIN_INSTR(BitOrInt, binaryop)
1376     {
1377         registers[instr->binaryop.output].setint(registers[instr->binaryop.left].getint() | 
1378                                                  registers[instr->binaryop.right].getint());
1379     }
1380     QML_V4_END_INSTR(BitAndInt, binaryop)
1381
1382     QML_V4_BEGIN_INSTR(BitXorInt, binaryop)
1383     {
1384         registers[instr->binaryop.output].setint(registers[instr->binaryop.left].getint() ^ 
1385                                                  registers[instr->binaryop.right].getint());
1386     }
1387     QML_V4_END_INSTR(BitXorInt, binaryop)
1388
1389     QML_V4_BEGIN_INSTR(AddNumber, binaryop)
1390     {
1391         registers[instr->binaryop.output].setnumber(registers[instr->binaryop.left].getnumber() +
1392                                                    registers[instr->binaryop.right].getnumber());
1393     }
1394     QML_V4_END_INSTR(AddNumber, binaryop)
1395
1396     QML_V4_BEGIN_INSTR(AddString, binaryop)
1397     {
1398         QString &string = *registers[instr->binaryop.output].getstringptr();
1399         if (instr->binaryop.output == instr->binaryop.left) {
1400             string += registers[instr->binaryop.right].getstringptr();
1401         } else {
1402             string = *registers[instr->binaryop.left].getstringptr() + 
1403                      *registers[instr->binaryop.right].getstringptr();
1404         }
1405     }
1406     QML_V4_END_INSTR(AddString, binaryop)
1407
1408     QML_V4_BEGIN_INSTR(SubNumber, binaryop)
1409     {
1410         registers[instr->binaryop.output].setnumber(registers[instr->binaryop.left].getnumber() -
1411                                                    registers[instr->binaryop.right].getnumber());
1412     }
1413     QML_V4_END_INSTR(SubNumber, binaryop)
1414
1415     QML_V4_BEGIN_INSTR(MulNumber, binaryop)
1416     {
1417         registers[instr->binaryop.output].setnumber(registers[instr->binaryop.left].getnumber() *
1418                                                    registers[instr->binaryop.right].getnumber());
1419     }
1420     QML_V4_END_INSTR(MulNumber, binaryop)
1421
1422     QML_V4_BEGIN_INSTR(DivNumber, binaryop)
1423     {
1424         registers[instr->binaryop.output].setnumber(registers[instr->binaryop.left].getnumber() /
1425                                                    registers[instr->binaryop.right].getnumber());
1426     }
1427     QML_V4_END_INSTR(DivNumber, binaryop)
1428
1429     QML_V4_BEGIN_INSTR(ModNumber, binaryop)
1430     {
1431         Register &target = registers[instr->binaryop.output];
1432         const Register &left = registers[instr->binaryop.left];
1433         const Register &right = registers[instr->binaryop.right];
1434         target.setnumber(::fmod(left.getnumber(), right.getnumber()));
1435     }
1436     QML_V4_END_INSTR(ModInt, binaryop)
1437
1438     QML_V4_BEGIN_INSTR(LShiftInt, binaryop)
1439     {
1440         registers[instr->binaryop.output].setint(registers[instr->binaryop.left].getint() << 
1441                                                  registers[instr->binaryop.right].getint());
1442     }
1443     QML_V4_END_INSTR(LShiftInt, binaryop)
1444
1445     QML_V4_BEGIN_INSTR(RShiftInt, binaryop)
1446     {
1447         registers[instr->binaryop.output].setint(registers[instr->binaryop.left].getint() >> 
1448                                                  registers[instr->binaryop.right].getint());
1449     }
1450     QML_V4_END_INSTR(RShiftInt, binaryop)
1451
1452     QML_V4_BEGIN_INSTR(URShiftInt, binaryop)
1453     {
1454         registers[instr->binaryop.output].setint((unsigned)registers[instr->binaryop.left].getint() >> 
1455                                                  registers[instr->binaryop.right].getint());
1456     }
1457     QML_V4_END_INSTR(URShiftInt, binaryop)
1458
1459     QML_V4_BEGIN_INSTR(GtNumber, binaryop)
1460     {
1461         registers[instr->binaryop.output].setbool(registers[instr->binaryop.left].getnumber() >
1462                                                   registers[instr->binaryop.right].getnumber());
1463     }
1464     QML_V4_END_INSTR(GtNumber, binaryop)
1465
1466     QML_V4_BEGIN_INSTR(LtNumber, binaryop)
1467     {
1468         registers[instr->binaryop.output].setbool(registers[instr->binaryop.left].getnumber() <
1469                                                   registers[instr->binaryop.right].getnumber());
1470     }
1471     QML_V4_END_INSTR(LtNumber, binaryop)
1472
1473     QML_V4_BEGIN_INSTR(GeNumber, binaryop)
1474     {
1475         registers[instr->binaryop.output].setbool(registers[instr->binaryop.left].getnumber() >=
1476                                                   registers[instr->binaryop.right].getnumber());
1477     }
1478     QML_V4_END_INSTR(GeNumber, binaryop)
1479
1480     QML_V4_BEGIN_INSTR(LeNumber, binaryop)
1481     {
1482         registers[instr->binaryop.output].setbool(registers[instr->binaryop.left].getnumber() <=
1483                                                   registers[instr->binaryop.right].getnumber());
1484     }
1485     QML_V4_END_INSTR(LeNumber, binaryop)
1486
1487     QML_V4_BEGIN_INSTR(EqualNumber, binaryop)
1488     {
1489         registers[instr->binaryop.output].setbool(registers[instr->binaryop.left].getnumber() ==
1490                                                   registers[instr->binaryop.right].getnumber());
1491     }
1492     QML_V4_END_INSTR(EqualNumber, binaryop)
1493
1494     QML_V4_BEGIN_INSTR(NotEqualNumber, binaryop)
1495     {
1496         registers[instr->binaryop.output].setbool(registers[instr->binaryop.left].getnumber() !=
1497                                                   registers[instr->binaryop.right].getnumber());
1498     }
1499     QML_V4_END_INSTR(NotEqualNumber, binaryop)
1500
1501     QML_V4_BEGIN_INSTR(StrictEqualNumber, binaryop)
1502     {
1503         registers[instr->binaryop.output].setbool(registers[instr->binaryop.left].getnumber() ==
1504                                                   registers[instr->binaryop.right].getnumber());
1505     }
1506     QML_V4_END_INSTR(StrictEqualNumber, binaryop)
1507
1508     QML_V4_BEGIN_INSTR(StrictNotEqualNumber, binaryop)
1509     {
1510         registers[instr->binaryop.output].setbool(registers[instr->binaryop.left].getnumber() !=
1511                                                   registers[instr->binaryop.right].getnumber());
1512     }
1513     QML_V4_END_INSTR(StrictNotEqualNumber, binaryop)
1514
1515     QML_V4_BEGIN_INSTR(GtString, binaryop)
1516     {
1517         const QString &a = *registers[instr->binaryop.left].getstringptr();
1518         const QString &b = *registers[instr->binaryop.right].getstringptr();
1519         bool result = a > b;
1520         if (instr->binaryop.left == instr->binaryop.output) {
1521             registers[instr->binaryop.output].cleanupString();
1522             MARK_CLEAN_REGISTER(instr->binaryop.output);
1523         }
1524         registers[instr->binaryop.output].setbool(result);
1525     }
1526     QML_V4_END_INSTR(GtString, binaryop)
1527
1528     QML_V4_BEGIN_INSTR(LtString, binaryop)
1529     {
1530         const QString &a = *registers[instr->binaryop.left].getstringptr();
1531         const QString &b = *registers[instr->binaryop.right].getstringptr();
1532         bool result = a < b;
1533         if (instr->binaryop.left == instr->binaryop.output) {
1534             registers[instr->binaryop.output].cleanupString();
1535             MARK_CLEAN_REGISTER(instr->binaryop.output);
1536         }
1537         registers[instr->binaryop.output].setbool(result);
1538     }
1539     QML_V4_END_INSTR(LtString, binaryop)
1540
1541     QML_V4_BEGIN_INSTR(GeString, binaryop)
1542     {
1543         const QString &a = *registers[instr->binaryop.left].getstringptr();
1544         const QString &b = *registers[instr->binaryop.right].getstringptr();
1545         bool result = a >= b;
1546         if (instr->binaryop.left == instr->binaryop.output) {
1547             registers[instr->binaryop.output].cleanupString();
1548             MARK_CLEAN_REGISTER(instr->binaryop.output);
1549         }
1550         registers[instr->binaryop.output].setbool(result);
1551     }
1552     QML_V4_END_INSTR(GeString, binaryop)
1553
1554     QML_V4_BEGIN_INSTR(LeString, binaryop)
1555     {
1556         const QString &a = *registers[instr->binaryop.left].getstringptr();
1557         const QString &b = *registers[instr->binaryop.right].getstringptr();
1558         bool result = a <= b;
1559         if (instr->binaryop.left == instr->binaryop.output) {
1560             registers[instr->binaryop.output].cleanupString();
1561             MARK_CLEAN_REGISTER(instr->binaryop.output);
1562         }
1563         registers[instr->binaryop.output].setbool(result);
1564     }
1565     QML_V4_END_INSTR(LeString, binaryop)
1566
1567     QML_V4_BEGIN_INSTR(EqualString, binaryop)
1568     {
1569         const QString &a = *registers[instr->binaryop.left].getstringptr();
1570         const QString &b = *registers[instr->binaryop.right].getstringptr();
1571         bool result = a == b;
1572         if (instr->binaryop.left == instr->binaryop.output) {
1573             registers[instr->binaryop.output].cleanupString();
1574             MARK_CLEAN_REGISTER(instr->binaryop.output);
1575         }
1576         registers[instr->binaryop.output].setbool(result);
1577     }
1578     QML_V4_END_INSTR(EqualString, binaryop)
1579
1580     QML_V4_BEGIN_INSTR(NotEqualString, binaryop)
1581     {
1582         const QString &a = *registers[instr->binaryop.left].getstringptr();
1583         const QString &b = *registers[instr->binaryop.right].getstringptr();
1584         bool result = a != b;
1585         if (instr->binaryop.left == instr->binaryop.output) {
1586             registers[instr->binaryop.output].cleanupString();
1587             MARK_CLEAN_REGISTER(instr->binaryop.output);
1588         }
1589         registers[instr->binaryop.output].setbool(result);
1590     }
1591     QML_V4_END_INSTR(NotEqualString, binaryop)
1592
1593     QML_V4_BEGIN_INSTR(StrictEqualString, binaryop)
1594     {
1595         const QString &a = *registers[instr->binaryop.left].getstringptr();
1596         const QString &b = *registers[instr->binaryop.right].getstringptr();
1597         bool result = a == b;
1598         if (instr->binaryop.left == instr->binaryop.output) {
1599             registers[instr->binaryop.output].cleanupString();
1600             MARK_CLEAN_REGISTER(instr->binaryop.output);
1601         }
1602         registers[instr->binaryop.output].setbool(result);
1603     }
1604     QML_V4_END_INSTR(StrictEqualString, binaryop)
1605
1606     QML_V4_BEGIN_INSTR(StrictNotEqualString, binaryop)
1607     {
1608         const QString &a = *registers[instr->binaryop.left].getstringptr();
1609         const QString &b = *registers[instr->binaryop.right].getstringptr();
1610         bool result = a != b;
1611         if (instr->binaryop.left == instr->binaryop.output) {
1612             registers[instr->binaryop.output].cleanupString();
1613             MARK_CLEAN_REGISTER(instr->binaryop.output);
1614         }
1615         registers[instr->binaryop.output].setbool(result);
1616     }
1617     QML_V4_END_INSTR(StrictNotEqualString, binaryop)
1618
1619     QML_V4_BEGIN_INSTR(EqualObject, binaryop)
1620     {
1621         const Register &left = registers[instr->binaryop.left];
1622         const Register &right = registers[instr->binaryop.right];
1623         QObject *leftobj = (left.gettype() == NullType) ? 0 : left.getQObject();
1624         QObject *rightobj = (right.gettype() == NullType) ? 0 : right.getQObject();
1625         registers[instr->binaryop.output].setbool(leftobj == rightobj);
1626     }
1627     QML_V4_END_INSTR(EqualObject, binaryop)
1628
1629     QML_V4_BEGIN_INSTR(NotEqualObject, binaryop)
1630     {
1631         const Register &left = registers[instr->binaryop.left];
1632         const Register &right = registers[instr->binaryop.right];
1633         QObject *leftobj = (left.gettype() == NullType) ? 0 : left.getQObject();
1634         QObject *rightobj = (right.gettype() == NullType) ? 0 : right.getQObject();
1635         registers[instr->binaryop.output].setbool(leftobj != rightobj);
1636     }
1637     QML_V4_END_INSTR(NotEqualObject, binaryop)
1638
1639     QML_V4_BEGIN_INSTR(StrictEqualObject, binaryop)
1640     {
1641         const Register &left = registers[instr->binaryop.left];
1642         const Register &right = registers[instr->binaryop.right];
1643         QObject *leftobj = (left.gettype() == NullType) ? 0 : left.getQObject();
1644         QObject *rightobj = (right.gettype() == NullType) ? 0 : right.getQObject();
1645         registers[instr->binaryop.output].setbool(leftobj == rightobj);
1646     }
1647     QML_V4_END_INSTR(StrictEqualObject, binaryop)
1648
1649     QML_V4_BEGIN_INSTR(StrictNotEqualObject, binaryop)
1650     {
1651         const Register &left = registers[instr->binaryop.left];
1652         const Register &right = registers[instr->binaryop.right];
1653         QObject *leftobj = (left.gettype() == NullType) ? 0 : left.getQObject();
1654         QObject *rightobj = (right.gettype() == NullType) ? 0 : right.getQObject();
1655         registers[instr->binaryop.output].setbool(leftobj != rightobj);
1656     }
1657     QML_V4_END_INSTR(StrictNotEqualObject, binaryop)
1658
1659     QML_V4_BEGIN_INSTR(MathMaxNumber, binaryop)
1660     {
1661         const Register &left = registers[instr->binaryop.left];
1662         const Register &right = registers[instr->binaryop.right];
1663         Register &output = registers[instr->binaryop.output];
1664         if (left.isUndefined() || right.isUndefined()) output.setUndefined();
1665         else output.setnumber(qMax(left.getnumber(), right.getnumber()));
1666     }
1667     QML_V4_END_INSTR(MathMaxNumber, binaryop)
1668
1669     QML_V4_BEGIN_INSTR(MathMinNumber, binaryop)
1670     {
1671         const Register &left = registers[instr->binaryop.left];
1672         const Register &right = registers[instr->binaryop.right];
1673         Register &output = registers[instr->binaryop.output];
1674         if (left.isUndefined() || right.isUndefined()) output.setUndefined();
1675         else output.setnumber(qMin(left.getnumber(), right.getnumber()));
1676     }
1677     QML_V4_END_INSTR(MathMinNumber, binaryop)
1678
1679     QML_V4_BEGIN_INSTR(NewString, construct)
1680     {
1681         Register &output = registers[instr->construct.reg];
1682         new (output.getstringptr()) QString;
1683         STRING_REGISTER(instr->construct.reg);
1684     }
1685     QML_V4_END_INSTR(NewString, construct)
1686
1687     QML_V4_BEGIN_INSTR(NewUrl, construct)
1688     {
1689         Register &output = registers[instr->construct.reg];
1690         new (output.geturlptr()) QUrl;
1691         URL_REGISTER(instr->construct.reg);
1692     }
1693     QML_V4_END_INSTR(NewUrl, construct)
1694
1695     QML_V4_BEGIN_INSTR(Fetch, fetch)
1696     {
1697         Register &reg = registers[instr->fetch.reg];
1698
1699         if (reg.isUndefined()) 
1700             THROW_EXCEPTION(instr->fetch.exceptionId);
1701
1702         QObject *object = reg.getQObject();
1703         if (!object) {
1704             THROW_EXCEPTION(instr->fetch.exceptionId);
1705         } else {
1706             const Register::Type valueType = (Register::Type)instr->fetch.valueType;
1707             reg.init(valueType);
1708             if (instr->fetch.valueType >= FirstCleanupType)
1709                 MARK_REGISTER(instr->fetch.reg);
1710             void *argv[] = { reg.typeDataPtr(), 0 };
1711             QMetaObject::metacall(object, QMetaObject::ReadProperty, instr->fetch.index, argv);
1712             if (valueType == FloatType) {
1713                 // promote floats
1714                 const double v = reg.getfloat();
1715                 reg.setnumber(v);
1716             }
1717         }
1718     }
1719     QML_V4_END_INSTR(Fetch, fetch)
1720
1721     QML_V4_BEGIN_INSTR(TestV4Store, storetest)
1722     {
1723         Register &data = registers[instr->storetest.reg];
1724         testBindingResult(*testBindingSource, bindingLine, bindingColumn, context, 
1725                           scope, data, instr->storetest.regType);
1726     }
1727     QML_V4_END_INSTR(TestV4Store, storetest)
1728
1729     QML_V4_BEGIN_INSTR(Store, store)
1730     {
1731         Register &data = registers[instr->store.reg];
1732
1733         if (data.isUndefined()) 
1734             THROW_EXCEPTION_STR(instr->store.exceptionId, QLatin1String("Unable to assign undefined value"));
1735
1736         if (data.gettype() == QObjectStarType) {
1737             if (QObject *dataObject = data.getQObject()) {
1738                 const QMetaObject *dataMo = dataObject->metaObject();
1739
1740                 QQmlEnginePrivate *ep = QQmlEnginePrivate::get(context->engine);
1741                 QMetaProperty receiver = output->metaObject()->property(instr->store.index);
1742                 const QMetaObject *receiverMo = QQmlPropertyPrivate::rawMetaObjectForType(ep, receiver.userType());
1743
1744                 // Verify that these types are compatible
1745                 if (!QQmlPropertyPrivate::canConvert(dataMo, receiverMo)) {
1746                     THROW_EXCEPTION_STR(instr->store.exceptionId, QLatin1String("Unable to assign ") +
1747                                                                   QLatin1String(dataMo->className()) +
1748                                                                   QLatin1String(" to ") +
1749                                                                   QLatin1String(receiverMo->className()));
1750                 }
1751             }
1752         }
1753
1754         if (instr->store.valueType == FloatType) {
1755             // cast numbers to floats
1756             const float v = (float) data.getnumber();
1757             data.setfloat(v);
1758         }
1759
1760         int status = -1;
1761         void *argv[] = { data.typeDataPtr(), 0, &status, &storeFlags };
1762         QMetaObject::metacall(output, QMetaObject::WriteProperty,
1763                               instr->store.index, argv);
1764
1765         goto programExit;
1766     }
1767     QML_V4_END_INSTR(Store, store)
1768
1769     QML_V4_BEGIN_INSTR(Copy, copy)
1770         registers[instr->copy.reg].copy(registers[instr->copy.src]);
1771         if (registers[instr->copy.reg].gettype() >= FirstCleanupType)
1772             MARK_REGISTER(instr->copy.reg);
1773     QML_V4_END_INSTR(Copy, copy)
1774
1775     QML_V4_BEGIN_INSTR(Jump, jump)
1776         if (instr->jump.reg == -1 || !registers[instr->jump.reg].getbool())
1777             code += instr->jump.count;
1778     QML_V4_END_INSTR(Jump, jump)
1779
1780     QML_V4_BEGIN_INSTR(BranchTrue, branchop)
1781         if (registers[instr->branchop.reg].getbool())
1782             code += instr->branchop.offset;
1783     QML_V4_END_INSTR(BranchTrue, branchop)
1784
1785     QML_V4_BEGIN_INSTR(BranchFalse, branchop)
1786         if (! registers[instr->branchop.reg].getbool())
1787             code += instr->branchop.offset;
1788     QML_V4_END_INSTR(BranchFalse, branchop)
1789
1790     QML_V4_BEGIN_INSTR(Branch, branchop)
1791         code += instr->branchop.offset;
1792     QML_V4_END_INSTR(Branch, branchop)
1793
1794     QML_V4_BEGIN_INSTR(Block, blockop)
1795         executedBlocks |= instr->blockop.block;
1796     QML_V4_END_INSTR(Block, blockop)
1797
1798     QML_V4_BEGIN_INSTR(CleanupRegister, cleanup)
1799         registers[instr->cleanup.reg].cleanup();
1800     QML_V4_END_INSTR(CleanupRegister, cleanup)
1801
1802     QML_V4_BEGIN_INSTR(Throw, throwop)
1803         THROW_VALUE_EXCEPTION_STR(instr->throwop.exceptionId, *registers[instr->throwop.message].getstringptr());
1804     QML_V4_END_INSTR(Throw, throwop)
1805
1806 #ifdef QML_THREADED_INTERPRETER
1807     // nothing to do
1808 #else
1809     default:
1810         qFatal("QV4: Unknown instruction %d encountered.", instr->common.type);
1811         break;
1812     } // switch
1813
1814     } // while
1815 #endif
1816
1817     Q_ASSERT(!"Unreachable code reached");
1818
1819 programExit:
1820 exceptionExit:
1821     delete testBindingSource;
1822
1823     int reg = 0;
1824     while (cleanupRegisterMask) {
1825         if (cleanupRegisterMask & 0x1) 
1826             registers[reg].cleanup();
1827
1828         reg++;
1829         cleanupRegisterMask >>= 1;
1830     }
1831 }
1832
1833 QT_END_NAMESPACE