4d6bf9256710bdab2d0b6445385477ab368914b7
[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
51 #include <private/qv8_p.h>
52 #include <private/qjsconverter_p.h>
53 #include <private/qjsconverter_impl_p.h>
54 #include <private/qjsvalue_impl_p.h>
55 #include <private/qjsvalueiterator_impl_p.h>
56 #include <private/qv8engine_impl_p.h>
57
58 #include <private/qqmlaccessors_p.h>
59 #include <private/qqmlprofilerservice_p.h>
60 #include <private/qqmlmetatype_p.h>
61 #include <private/qqmltrace_p.h>
62 #include <private/qqmlstringconverters_p.h>
63 #include <private/qqmlproperty_p.h>
64 #include <private/qqmlvmemetaobject_p.h>
65
66 #include <QtQml/qqmlinfo.h>
67 #include <QtCore/qnumeric.h>
68 #include <QtCore/qmath.h>
69 #include <math.h> // ::fmod
70
71 Q_DECLARE_METATYPE(QJSValue)
72
73 #ifdef Q_CC_MSVC
74 // MSVC2010 warns about 'unreferenced formal parameter', even if it's used in p->~T()
75 #  pragma warning( disable : 4100 )
76 #endif
77
78 QT_BEGIN_NAMESPACE
79
80 using namespace QQmlJS;
81
82 QQmlAbstractBinding::VTable QV4Bindings_Binding_vtable = {
83     QV4Bindings::Binding::destroy,
84     QQmlAbstractBinding::default_expression,
85     QV4Bindings::Binding::propertyIndex,
86     QV4Bindings::Binding::object,
87     QV4Bindings::Binding::setEnabled,
88     QV4Bindings::Binding::update,
89     QV4Bindings::Binding::retargetBinding
90 };
91
92 namespace {
93
94 // The highest bit is the sign bit, in any endianness
95 static const quint64 doubleSignMask = (quint64(0x1) << 63);
96
97 inline bool signBitSet(const double &v)
98 {
99     union { double d; quint64 u; } u;
100     u.d = v;
101     return (u.u & doubleSignMask);
102 }
103
104 inline double setSignBit(const double &v, bool b = true)
105 {
106     union { double d; quint64 u; } u;
107
108     u.d = v;
109     if (b) {
110         u.u |= doubleSignMask;
111     } else {
112         u.u &= ~doubleSignMask;
113     }
114     return u.d;
115 }
116
117 inline double clearSignBit(const double &v, bool b = true)
118 {
119     return setSignBit(v, !b);
120 }
121
122 struct Register {
123     typedef QQmlRegisterType Type;
124
125     enum SpecialNumericValue {
126         NegativeZero = 1,
127         PositiveInfinity = 2,
128         NegativeInfinity = 3,
129         NotANumber = 4
130     };
131
132     inline void setUndefined() { dataType = UndefinedType; }
133     inline bool isUndefined() const { return dataType == UndefinedType; }
134
135     inline void setNull() { dataType = NullType; }
136
137     inline void setNaN() { setnumber(qSNaN()); }
138     inline void setNaNType() { dataType = SpecialNumericType; intValue = NotANumber; } // non-numeric representation of NaN
139     inline bool isNaN() const { return (((dataType == SpecialNumericType) && (intValue == NotANumber)) ||
140                                         ((dataType == NumberType) && qIsNaN(numberValue))); }
141
142     inline void setInf(bool negative) { setnumber(setSignBit(qInf(), negative)); }
143     inline void setInfType(bool negative) { dataType = SpecialNumericType; intValue = (negative ? NegativeInfinity : PositiveInfinity); } // non-numeric representation of Inf
144     inline bool isInf() const { return (((dataType == SpecialNumericType) && ((intValue == NegativeInfinity) || (intValue == PositiveInfinity))) ||
145                                         ((dataType == NumberType) && qIsInf(numberValue))); }
146
147     inline void setNegativeZero() { setnumber(setSignBit(0)); }
148     inline void setNegativeZeroType() { dataType = SpecialNumericType; intValue = NegativeZero; } // non-numeric representation of -0
149     inline bool isNegativeZero() const { return (((dataType == SpecialNumericType) && (intValue == NegativeZero)) ||
150                                                  ((dataType == NumberType) && (numberValue == 0) && signBitSet(numberValue))); }
151
152     inline void setQObject(QObject *o) { qobjectValue = o; dataType = QObjectStarType; }
153     inline QObject *getQObject() const { return qobjectValue; }
154
155     inline void setnumber(double v) { numberValue = v; dataType = NumberType; }
156     inline double getnumber() const { return numberValue; }
157     inline double &getnumberref() { return numberValue; }
158
159     inline void setfloat(float v) { floatValue = v; dataType = FloatType; }
160     inline float getfloat() const { return floatValue; }
161     inline float &getfloatref() { return floatValue; }
162
163     inline void setint(int v) { intValue = v; dataType = IntType; }
164     inline int getint() const { return intValue; }
165     inline int &getintref() { return intValue; }
166
167     inline void setbool(bool v) { boolValue = v; dataType = BoolType; }
168     inline bool getbool() const { return boolValue; }
169     inline bool &getboolref() { return boolValue; }
170
171     inline QVariant *getvariantptr() { return reinterpret_cast<QVariant *>(typeDataPtr()); }
172     inline QString *getstringptr() { return reinterpret_cast<QString *>(typeDataPtr()); }
173     inline QUrl *geturlptr() { return reinterpret_cast<QUrl *>(typeDataPtr()); }
174     inline v8::Handle<v8::Value> *gethandleptr() { return reinterpret_cast<v8::Handle<v8::Value> *>(typeDataPtr()); }
175     inline QJSValue *getjsvalueptr() { return reinterpret_cast<QJSValue *>(typeDataPtr()); }
176
177     inline const QVariant *getvariantptr() const { return reinterpret_cast<const QVariant *>(typeDataPtr()); }
178     inline const QString *getstringptr() const { return reinterpret_cast<const QString *>(typeDataPtr()); }
179     inline const QUrl *geturlptr() const { return reinterpret_cast<const QUrl *>(typeDataPtr()); }
180     inline const v8::Handle<v8::Value> *gethandleptr() const { return reinterpret_cast<const v8::Handle<v8::Value> *>(typeDataPtr()); }
181     inline const QJSValue *getjsvalueptr() const { return reinterpret_cast<const QJSValue *>(typeDataPtr()); }
182
183     size_t dataSize() { return sizeof(data); }
184     inline void *typeDataPtr() { return (void *)&data; }
185     inline void *typeMemory() { return (void *)data; }
186     inline const void *typeDataPtr() const { return (void *)&data; }
187     inline const void *typeMemory() const { return (void *)data; }
188
189     inline Type gettype() const { return dataType; }
190     inline void settype(Type t) { dataType = t; }
191
192     Type dataType;     // Type of data
193     union {
194         QObject *qobjectValue;
195         double numberValue;
196         float floatValue;
197         int intValue;
198         bool boolValue;
199         void *data[sizeof(QVariant)];
200         qint64 q_for_alignment_1;
201         double q_for_alignment_2;
202     };
203
204     inline void cleanup();
205     inline void cleanupString();
206     inline void cleanupUrl();
207     inline void cleanupColor();
208     inline void cleanupVariant();
209     inline void cleanupHandle();
210     inline void cleanupJSValue();
211
212     inline void copy(const Register &other);
213     inline void init(Type type);
214 #ifdef REGISTER_CLEANUP_DEBUG
215     Register() {
216         type = 0;
217     }
218
219     ~Register() {
220         if (dataType >= FirstCleanupType)
221             qWarning("Register leaked of type %d", dataType);
222     }
223 #endif
224
225     template <typename T>
226     inline static void copyConstructPointee(T *p, const T *other)
227     {
228         new (p) T(*other);
229     }
230
231     template <typename T>
232     inline static void defaultConstructPointee(T *p)
233     {
234         new (p) T();
235     }
236
237     template <typename T>
238     inline static void destroyPointee(T *p)
239     {
240         p->~T();
241     }
242 };
243
244 void Register::cleanup()
245 {
246     if (dataType >= FirstCleanupType) {
247         if (dataType == QStringType) {
248             destroyPointee(getstringptr());
249         } else if (dataType == QUrlType) {
250             destroyPointee(geturlptr());
251         } else if (dataType == QColorType) {
252             QQml_valueTypeProvider()->destroyValueType(QMetaType::QColor, typeDataPtr(), dataSize());
253         } else if (dataType == QVariantType) {
254             destroyPointee(getvariantptr());
255         } else if (dataType == qMetaTypeId<v8::Handle<v8::Value> >()) {
256             destroyPointee(gethandleptr());
257         } else if (dataType == qMetaTypeId<QJSValue>()) {
258             destroyPointee(getjsvalueptr());
259         }
260     }
261     setUndefined();
262 }
263
264 void Register::cleanupString()
265 {
266     destroyPointee(getstringptr());
267     setUndefined();
268 }
269
270 void Register::cleanupUrl()
271 {
272     destroyPointee(geturlptr());
273     setUndefined();
274 }
275
276 void Register::cleanupColor()
277 {
278     QQml_valueTypeProvider()->destroyValueType(QMetaType::QColor, typeDataPtr(), dataSize());
279     setUndefined();
280 }
281
282 void Register::cleanupVariant()
283 {
284     destroyPointee(getvariantptr());
285     setUndefined();
286 }
287
288 void Register::cleanupHandle()
289 {
290     destroyPointee(gethandleptr());
291     setUndefined();
292 }
293
294 void Register::cleanupJSValue()
295 {
296     destroyPointee(getjsvalueptr());
297     setUndefined();
298 }
299
300 void Register::copy(const Register &other)
301 {
302     *this = other;
303     if (other.dataType >= FirstCleanupType) {
304         if (other.dataType == QStringType)
305             copyConstructPointee(getstringptr(), other.getstringptr());
306         else if (other.dataType == QUrlType)
307             copyConstructPointee(geturlptr(), other.geturlptr());
308         else if (other.dataType == QColorType)
309             QQml_valueTypeProvider()->copyValueType(QMetaType::QColor, other.typeDataPtr(), typeDataPtr(), dataSize());
310         else if (other.dataType == QVariantType)
311             copyConstructPointee(getvariantptr(), other.getvariantptr());
312         else if (other.dataType == qMetaTypeId<v8::Handle<v8::Value> >())
313             copyConstructPointee(gethandleptr(), other.gethandleptr());
314         else if (other.dataType == qMetaTypeId<QJSValue>())
315             copyConstructPointee(getjsvalueptr(), other.getjsvalueptr());
316     }
317 }
318
319 void Register::init(Type type)
320 {
321     dataType = type;
322     if (dataType >= FirstCleanupType) {
323         if (dataType == QStringType)
324             defaultConstructPointee(getstringptr());
325         else if (dataType == QUrlType)
326             defaultConstructPointee(geturlptr());
327         else if (dataType == QColorType)
328             QQml_valueTypeProvider()->initValueType(QMetaType::QColor, typeDataPtr(), dataSize());
329         else if (dataType == QVariantType)
330             defaultConstructPointee(getvariantptr());
331         else if (dataType == qMetaTypeId<v8::Handle<v8::Value> >())
332             defaultConstructPointee(gethandleptr());
333         else if (dataType == qMetaTypeId<QJSValue>())
334             defaultConstructPointee(getjsvalueptr());
335     }
336 }
337
338 } // end of anonymous namespace
339
340 QV4Bindings::QV4Bindings(const char *programData, QQmlContextData *context)
341 : subscriptions(0), program(0), bindings(0)
342 {
343     program = (QV4Program *)programData;
344     if (program) {
345         subscriptions = new Subscription[program->subscriptions];
346         bindings = new Binding[program->bindings];
347
348         QQmlAbstractExpression::setContext(context);
349     }
350 }
351
352 QV4Bindings::~QV4Bindings()
353 {
354     delete [] bindings; bindings = 0;
355     delete [] subscriptions; subscriptions = 0;
356 }
357
358 QQmlAbstractBinding *QV4Bindings::configBinding(QObject *target, QObject *scope,
359                                                 const QQmlInstruction::instr_assignV4Binding *i)
360 {
361     Binding *rv = bindings + i->value;
362
363     rv->instruction = i;
364     rv->target = target;
365     rv->scope = scope;
366     rv->parent = this;
367
368     addref(); // This is decremented in Binding::destroy()
369
370     return rv;
371 }
372
373 void QV4Bindings::Binding::setEnabled(QQmlAbstractBinding *_This,
374                                       bool e, QQmlPropertyPrivate::WriteFlags flags)
375 {
376     QV4Bindings::Binding *This = static_cast<QV4Bindings::Binding *>(_This);
377
378     if (This->enabledFlag() != e) {
379         This->setEnabledFlag(e);
380
381         if (e) update(_This, flags);
382     }
383 }
384
385 void QV4Bindings::Binding::update(QQmlAbstractBinding *_This, QQmlPropertyPrivate::WriteFlags flags)
386 {
387     QV4Bindings::Binding *This = static_cast<QV4Bindings::Binding *>(_This);
388     This->parent->run(This, flags);
389 }
390
391 void QV4Bindings::Binding::destroy(QQmlAbstractBinding *_This, QQmlAbstractBinding::DestroyMode mode)
392 {
393     QV4Bindings::Binding *This = static_cast<QV4Bindings::Binding *>(_This);
394
395     if (mode == QQmlAbstractBinding::DisconnectBinding)
396         This->disconnect();
397
398     This->setEnabledFlag(false);
399     This->removeFromObject();
400     This->clear();
401     This->removeError();
402     This->parent->release();
403 }
404
405 int QV4Bindings::Binding::propertyIndex(const QQmlAbstractBinding *_This)
406 {
407     const QV4Bindings::Binding *This = static_cast<const QV4Bindings::Binding *>(_This);
408
409     if (This->target.hasValue()) return This->target.constValue()->targetProperty;
410     else return This->instruction->property;
411 }
412
413 QObject *QV4Bindings::Binding::object(const QQmlAbstractBinding *_This)
414 {
415     const QV4Bindings::Binding *This = static_cast<const QV4Bindings::Binding *>(_This);
416
417     if (This->target.hasValue()) return This->target.constValue()->target;
418     return *This->target;
419 }
420
421 void QV4Bindings::Binding::retargetBinding(QQmlAbstractBinding *_This, QObject *t, int i)
422 {
423     QV4Bindings::Binding *This = static_cast<QV4Bindings::Binding *>(_This);
424
425     This->target.value().target = t;
426     This->target.value().targetProperty = i;
427 }
428
429 void QV4Bindings::Binding::disconnect()
430 {
431     // We iterate over the signal table to find all subscriptions associated with this binding.
432     // This is slow, but disconnect() is not called in the common case, only in special cases
433     // like when the binding is overwritten.
434     QV4Program * const program = parent->program;
435     for (quint16 subIndex = 0; subIndex < program->subscriptions; subIndex++) {
436         QV4Program::BindingReferenceList * const list = program->signalTable(subIndex);
437         for (quint32 bindingIndex = 0; bindingIndex < list->count; ++bindingIndex) {
438             QV4Program::BindingReference * const bindingRef = list->bindings + bindingIndex;
439             Binding * const binding = parent->bindings + bindingRef->binding;
440             if (binding == this) {
441                 Subscription * const sub = parent->subscriptions + subIndex;
442                 if (sub->active()) {
443                     sub->setActive(false);
444                     sub->disconnect();
445                 }
446             }
447         }
448     }
449 }
450
451 void QV4Bindings::Binding::dump()
452 {
453     qWarning() << parent->context()->url << instruction->line << instruction->column;
454 }
455
456 QV4Bindings::Subscription::Subscription()
457     : m_bindings(0)
458 {
459     setCallback(QQmlNotifierEndpoint::QV4BindingsSubscription);
460 }
461
462 int QV4Bindings::Subscription::method() const
463 {
464     Q_ASSERT(bindings() != 0);
465     return (this - bindings()->subscriptions);
466 }
467
468 void QV4Bindings::Subscription::setBindings(QV4Bindings *bindings)
469 {
470     m_bindings = bindings;
471 }
472
473 QV4Bindings *QV4Bindings::Subscription::bindings() const
474 {
475     return *m_bindings;
476 }
477
478 bool QV4Bindings::Subscription::active() const
479 {
480     return m_bindings.flag();
481 }
482
483 void QV4Bindings::Subscription::setActive(bool active)
484 {
485     m_bindings.setFlagValue(active);
486 }
487
488 void QV4BindingsSubscription_callback(QQmlNotifierEndpoint *e, void **)
489 {
490     QV4Bindings::Subscription *s = static_cast<QV4Bindings::Subscription *>(e);
491     Q_ASSERT(s->bindings());
492     s->bindings()->subscriptionNotify(s->method());
493 }
494
495 void QV4Bindings::subscriptionNotify(int id)
496 {
497     QV4Program::BindingReferenceList *list = program->signalTable(id);
498
499     for (quint32 ii = 0; ii < list->count; ++ii) {
500         QV4Program::BindingReference *bindingRef = list->bindings + ii;
501
502         Binding *binding = bindings + bindingRef->binding;
503
504         if (binding->executedBlocks & bindingRef->blockMask) {
505             run(binding, QQmlPropertyPrivate::DontRemoveBinding);
506         }
507     }
508 }
509
510 void QV4Bindings::run(Binding *binding, QQmlPropertyPrivate::WriteFlags flags)
511 {
512     if (!binding->enabledFlag())
513         return;
514
515     QQmlContextData *context = QQmlAbstractExpression::context();
516     if (!context || !context->isValid())
517         return;
518
519     // Check that the target has not been deleted
520     if (QQmlData::wasDeleted(*binding->target))
521         return;
522
523     QQmlTrace trace("V4 Binding Update");
524     trace.addDetail("URL", context->url);
525     trace.addDetail("Line", binding->instruction->line);
526     trace.addDetail("Column", binding->instruction->column);
527
528     QQmlBindingProfiler prof(context->urlString, binding->instruction->line, binding->instruction->column, QQmlProfilerService::V4Binding);
529
530     const int propType = binding->instruction->propType;
531     const int property = binding->instruction->property;
532
533     if (binding->updatingFlag()) {
534         QString name;
535         if (propType) {
536             QQmlValueType *vt = QQmlValueTypeFactory::valueType(propType);
537             Q_ASSERT(vt);
538
539             name = QLatin1String(binding->target->metaObject()->property(property & 0x0000FFFF).name());
540             name.append(QLatin1Char('.'));
541             name.append(QLatin1String(vt->metaObject()->property(property >> 16).name()));
542         } else {
543             name = QLatin1String(binding->target->metaObject()->property(property).name());
544         }
545         qmlInfo(*binding->target) << tr("Binding loop detected for property \"%1\"").arg(name);
546         return;
547     }
548
549     int index = binding->instruction->value;
550     int fallbackIndex = binding->instruction->fallbackValue;
551
552     bool invalidated = false;
553     bool *inv = (fallbackIndex != -1) ? &invalidated : 0;
554
555     binding->setUpdatingFlag(true);
556     if (propType) {
557         QQmlValueType *vt = QQmlValueTypeFactory::valueType(propType);
558         Q_ASSERT(vt);
559         vt->read(*binding->target, property & 0x0000FFFF);
560
561         QObject *target = vt;
562         run(index, binding->executedBlocks, context, binding, binding->scope, target, flags, inv);
563
564         if (!invalidated) {
565             vt->write(*binding->target, property & 0x0000FFFF, flags);
566         }
567     } else {
568         QQmlData *data = QQmlData::get(*binding->target);
569         QQmlPropertyData *propertyData = (data && data->propertyCache ? data->propertyCache->property(property) : 0);
570
571         if (propertyData && propertyData->isVarProperty()) {
572             // We will allocate a V8 handle in this conversion/store
573             v8::HandleScope handle_scope;
574             v8::Context::Scope context_scope(QQmlEnginePrivate::get(context->engine)->v8engine()->context());
575
576             run(index, binding->executedBlocks, context, binding, binding->scope, *binding->target, flags, inv);
577         } else {
578             run(index, binding->executedBlocks, context, binding, binding->scope, *binding->target, flags, inv);
579         }
580     }
581     binding->setUpdatingFlag(false);
582
583     if (invalidated) {
584         // This binding is no longer valid - fallback to V8
585         Q_ASSERT(fallbackIndex > -1);
586         QQmlAbstractBinding *b = QQmlPropertyPrivate::activateSharedBinding(context, fallbackIndex, flags);
587         Q_ASSERT(b == binding);
588         b->destroy();
589     }
590 }
591
592 void QV4Bindings::subscribeId(QQmlContextData *p, int idIndex, int subIndex)
593 {
594     Subscription *sub = (subscriptions + subIndex);
595     sub->disconnect();
596
597     if (p->idValues[idIndex]) {
598         sub->setBindings(this);
599         sub->connect(&p->idValues[idIndex].bindings);
600         sub->setActive(true);
601     } else {
602         sub->setActive(false);
603     }
604 }
605
606 void QV4Bindings::subscribe(QObject *o, int notifyIndex, int subIndex, QQmlEngine *e)
607 {
608     Subscription *sub = (subscriptions + subIndex);
609     if (sub->isConnected(o, notifyIndex))
610         return;
611     sub->setBindings(this);
612     if (o) {
613         sub->connect(o, notifyIndex, e);
614         sub->setActive(true);
615     } else {
616         sub->disconnect();
617         sub->setActive(false);
618     }
619 }
620
621 static bool testCompareVariants(const QVariant &qtscriptRaw, const QVariant &v4)
622 {
623     QVariant qtscript = qtscriptRaw;
624
625     if (qtscript.userType() == v4.userType()) {
626     } else if (qtscript.canConvert(v4.userType())) {
627         qtscript.convert(v4.userType());
628     } else if (qtscript.userType() == QVariant::Invalid && v4.userType() == QMetaType::QObjectStar) {
629         qtscript = qVariantFromValue<QObject *>(0);
630     } else {
631         return false;
632     }
633
634     int type = qtscript.userType();
635
636     if (type == QQmlMetaType::QQuickAnchorLineMetaTypeId()) {
637         return QQmlMetaType::QQuickAnchorLineCompare(qtscript.constData(), v4.constData());
638     } else if (type == QMetaType::Double) {
639
640         double la = qvariant_cast<double>(qtscript);
641         double lr = qvariant_cast<double>(v4);
642
643         return la == lr || (qIsNaN(la) && qIsNaN(lr));
644
645     } else if (type == QMetaType::Float) {
646
647         float la = qvariant_cast<float>(qtscript);
648         float lr = qvariant_cast<float>(v4);
649
650         return la == lr || (qIsNaN(la) && qIsNaN(lr));
651
652     } else {
653         return qtscript == v4;
654     }
655 }
656
657 QByteArray testResultToString(const QVariant &result, bool undefined)
658 {
659     if (undefined) {
660         return "undefined";
661     } else {
662         QString rv;
663         QDebug d(&rv);
664         d << result;
665         return rv.toUtf8();
666     }
667 }
668
669 static void testBindingResult(const QString &binding, quint16 line, quint16 column,
670                               QQmlContextData *context, QObject *scope, 
671                               const Register &result, int resultType)
672 {
673     QQmlExpression expression(context->asQQmlContext(), scope, binding);
674     bool isUndefined = false;
675     QVariant value = expression.evaluate(&isUndefined);
676
677     bool iserror = false;
678     QByteArray qtscriptResult;
679     QByteArray v4Result;
680
681     const int handleType = qMetaTypeId<v8::Handle<v8::Value> >();
682
683     if (expression.hasError()) {
684         iserror = true;
685         qtscriptResult = "exception";
686     } else if ((value.userType() != resultType) &&
687                (resultType != QMetaType::QVariant) &&
688                (resultType != qMetaTypeId<QJSValue>()) &&
689                (resultType != handleType)) {
690         // Override the QMetaType conversions to make them more JS friendly.
691         if (value.userType() == QMetaType::Double && (resultType == QMetaType::QString ||
692                                                         resultType == QMetaType::QUrl)) {
693             // number to string-like conversion.
694             value = QVariant::fromValue<QString>(QString::number(value.toDouble(), 'g', 16));
695         } else if (value.userType() == QMetaType::QUrl && resultType == QMetaType::Bool) {
696             // url to bool conversion
697             value = QVariant::fromValue<bool>(!value.toUrl().isEmpty());
698         }
699
700         if (!value.isNull() && !value.convert(resultType)) {
701             iserror = true;
702             qtscriptResult = "exception";
703         } else if (resultType == QMetaType::QUrl) {
704             // a V8 value was converted to QUrl.
705             value = QVariant::fromValue<QUrl>(context->resolvedUrl(value.toUrl()));
706         }
707     }
708
709     if (! iserror)
710         qtscriptResult = testResultToString(value, isUndefined);
711
712     if (isUndefined && result.isUndefined()) {
713         return;
714     } else if(isUndefined != result.isUndefined()) {
715         iserror = true;
716     }
717
718     QVariant v4value;
719     if (!result.isUndefined()) {
720         switch (resultType) {
721         case QMetaType::QString:
722             v4value = *result.getstringptr();
723             break;
724         case QMetaType::QUrl:
725             v4value = *result.geturlptr();
726             break;
727         case QMetaType::QObjectStar:
728             v4value = qVariantFromValue<QObject *>(result.getQObject());
729             break;
730         case QMetaType::Bool:
731             v4value = result.getbool();
732             break;
733         case QMetaType::Int:
734             v4value = result.getint();
735             break;
736         case QMetaType::Double:
737             v4value = result.getnumber();
738             break;
739         case QMetaType::QColor:
740             v4value = QVariant(QMetaType::QColor, result.typeDataPtr());
741             break;
742         case QMetaType::QVariant:
743             v4value = *result.getvariantptr();
744             break;
745         default:
746             if (resultType == QQmlMetaType::QQuickAnchorLineMetaTypeId()) {
747                 v4value = QVariant(QQmlMetaType::QQuickAnchorLineMetaTypeId(), result.typeDataPtr());
748             } else if (resultType == qMetaTypeId<QJSValue>()) {
749                 v4value = result.getjsvalueptr()->toVariant();
750             } else if (resultType == handleType) {
751                 QQmlEnginePrivate *ep = QQmlEnginePrivate::get(context->engine);
752                 v4value = ep->v8engine()->toVariant(*result.gethandleptr(), resultType);
753             } else {
754                 iserror = true;
755                 v4Result = "Unknown V4 type";
756             }
757         }
758     }
759     if (v4Result.isEmpty())
760         v4Result = testResultToString(v4value, result.isUndefined());
761
762     if (!testCompareVariants(value, v4value))
763         iserror = true;
764
765     if (iserror) {
766         qWarning().nospace() << "QV4: Optimization error @" << context->url.toString().toUtf8().constData() << ':' << line << ':' << column;
767
768         qWarning().nospace() << "    Binding:  " << binding;
769         qWarning().nospace() << "    QtScript: " << qtscriptResult.constData();
770         qWarning().nospace() << "    V4:       " << v4Result.constData();
771     }
772 }
773
774 static void testBindingException(const QString &binding, quint16 line, quint16 column,
775                                  QQmlContextData *context, QObject *scope)
776 {
777     QQmlExpression expression(context->asQQmlContext(), scope, binding);
778     bool isUndefined = false;
779     QVariant value = expression.evaluate(&isUndefined);
780
781     if (!expression.hasError()) {
782         QByteArray qtscriptResult = testResultToString(value, isUndefined);
783         qWarning().nospace() << "QV4: Optimization error @" << context->url.toString().toUtf8().constData() << ':' << line << ':' << column;
784         qWarning().nospace() << "    Binding:  " << binding;
785         qWarning().nospace() << "    QtScript: " << qtscriptResult.constData();
786         qWarning().nospace() << "    V4:       exception";
787     }
788 }
789
790 static void throwException(int id, QQmlDelayedError *error,
791                            QV4Program *program, QQmlContextData *context,
792                            const QString &description = QString())
793 {
794     if (description.isEmpty())
795         error->setErrorDescription(QLatin1String("TypeError: Result of expression is not an object"));
796     else
797         error->setErrorDescription(description);
798     if (id != 0xFF) {
799         quint32 e = *((quint32 *)(program->data() + program->exceptionDataOffset) + id);
800         error->setErrorLocation(context->url, (e >> 16), (e & 0xFFFF));
801     } else {
802         error->setErrorLocation(context->url, -1, -1);
803     }
804     if (!context->engine || !error->addError(QQmlEnginePrivate::get(context->engine)))
805         QQmlEnginePrivate::warning(context->engine, error);
806 }
807
808 const double QV4Bindings::D32 = 4294967296.0;
809
810 qint32 QV4Bindings::toInt32(double n)
811 {
812     if (qIsNaN(n) || qIsInf(n) || (n == 0))
813         return 0;
814
815     double sign = (n < 0) ? -1.0 : 1.0;
816     double abs_n = fabs(n);
817
818     n = ::fmod(sign * ::floor(abs_n), D32);
819     const double D31 = D32 / 2.0;
820
821     if (sign == -1 && n < -D31)
822         n += D32;
823
824     else if (sign != -1 && n >= D31)
825         n -= D32;
826
827     return qint32 (n);
828 }
829
830 inline quint32 QV4Bindings::toUint32(double n)
831 {
832     if (qIsNaN(n) || qIsInf(n) || (n == 0))
833         return 0;
834
835     double sign = (n < 0) ? -1.0 : 1.0;
836     double abs_n = fabs(n);
837
838     n = ::fmod(sign * ::floor(abs_n), D32);
839
840     if (n < 0)
841         n += D32;
842
843     return quint32 (n);
844 }
845
846 #define THROW_EXCEPTION_STR(id, str) { \
847     if (testBinding) testBindingException(*testBindingSource, bindingLine, bindingColumn, context, scope); \
848     throwException((id), error, program, context, (str)); \
849     goto exceptionExit; \
850 }
851
852 #define THROW_VALUE_EXCEPTION_STR(id, str) { \
853     throwException((id), error, program, context, (str)); \
854     goto exceptionExit; \
855 }
856
857 #define THROW_EXCEPTION(id) THROW_EXCEPTION_STR(id, QString())
858
859 #define MARK_REGISTER(reg) cleanupRegisterMask |= (1 << (reg))
860 #define MARK_CLEAN_REGISTER(reg) cleanupRegisterMask &= ~(1 << (reg))
861
862 #define STRING_REGISTER(reg) { \
863     registers[(reg)].settype(QStringType); \
864     MARK_REGISTER(reg); \
865 }
866
867 #define URL_REGISTER(reg) { \
868     registers[(reg)].settype(QUrlType); \
869     MARK_REGISTER(reg); \
870 }
871
872 #define COLOR_REGISTER(reg) { \
873     registers[(reg)].settype(QColorType); \
874     MARK_REGISTER(reg); \
875 }
876
877 #define VARIANT_REGISTER(reg) { \
878     registers[(reg)].settype(QVariantType); \
879     MARK_REGISTER(reg); \
880 }
881
882 #define V8HANDLE_REGISTER(reg) { \
883     registers[(reg)].settype(V8HandleType); \
884     MARK_REGISTER(reg); \
885 }
886
887 #define JSVALUE_REGISTER(reg) { \
888     registers[(reg)].settype(QJSValueType); \
889     MARK_REGISTER(reg); \
890 }
891
892 namespace {
893
894 bool bindingInvalidated(bool *invalidated, QObject *obj, QQmlContextData *context, int index)
895 {
896     if (invalidated != 0) {
897         if (QQmlData *data = QQmlData::get(obj, true)) {
898             if (!data->propertyCache) {
899                 data->propertyCache = QQmlEnginePrivate::get(context->engine)->cache(obj);
900                 if (data->propertyCache) data->propertyCache->addref();
901             }
902
903             if (QQmlPropertyData *prop = data->propertyCache ? data->propertyCache->property(index) : 0) {
904                 if (prop->isOverridden()) {
905                     // TODO: avoid construction of name and name-based lookup
906                     int resolvedIndex = data->propertyCache->property(prop->name(obj), obj, context)->coreIndex;
907                     if (index < resolvedIndex) {
908                         *invalidated = true;
909                         return true;
910                     }
911                 }
912             }
913         }
914     }
915
916     return false;
917 }
918
919 }
920
921 #ifdef QML_THREADED_INTERPRETER
922 void **QV4Bindings::getDecodeInstrTable()
923 {
924     static void **decode_instr;
925     if (!decode_instr) {
926         QV4Bindings *dummy = new QV4Bindings(0, 0);
927         quint32 executedBlocks = 0;
928         dummy->run(0, executedBlocks, 0, 0, 0, 0, 
929                    QQmlPropertyPrivate::BypassInterceptor, 
930                    0, &decode_instr);
931         dummy->release();
932     }
933     return decode_instr;
934 }
935 #endif
936
937 void QV4Bindings::run(int instrIndex, quint32 &executedBlocks,
938                                  QQmlContextData *context, QQmlDelayedError *error,
939                                  QObject *scope, QObject *output, 
940                                  QQmlPropertyPrivate::WriteFlags storeFlags,
941                                  bool *invalidated
942 #ifdef QML_THREADED_INTERPRETER
943                                  ,void ***table
944 #endif
945                                  )
946 {
947 #ifdef QML_THREADED_INTERPRETER
948     if (table) {
949         static void *decode_instr[] = {
950             FOR_EACH_V4_INSTR(QML_V4_INSTR_ADDR)
951         };
952
953         *table = decode_instr;
954         return;
955     }
956 #endif
957
958
959     error->removeError();
960
961     Register registers[32];
962     quint32 cleanupRegisterMask = 0;
963
964     executedBlocks = 0;
965
966     const char *code = program->instructions();
967     code += instrIndex * QML_V4_INSTR_SIZE(Jump, jump);
968     const V4Instr *instr = reinterpret_cast<const V4Instr *>(code);
969
970     const char *data = program->data();
971
972     QString *testBindingSource = 0;
973     bool testBinding = false;
974     int bindingLine = 0;
975     int bindingColumn = 0;
976
977 #ifdef QML_THREADED_INTERPRETER
978     goto *instr->common.code;
979 #else
980     for (;;) {
981         switch (instr->common.type) {
982 #endif
983
984     QML_V4_BEGIN_INSTR(Noop, common)
985     QML_V4_END_INSTR(Noop, common)
986
987     QML_V4_BEGIN_INSTR(BindingId, id)
988         bindingLine = instr->id.line;
989         bindingColumn = instr->id.column;
990     QML_V4_END_INSTR(BindingId, id)
991
992     QML_V4_BEGIN_INSTR(SubscribeId, subscribeop)
993         subscribeId(context, instr->subscribeop.index, instr->subscribeop.offset);
994     QML_V4_END_INSTR(SubscribeId, subscribeop)
995
996     QML_V4_BEGIN_INSTR(FetchAndSubscribe, fetchAndSubscribe)
997     {
998         Register &reg = registers[instr->fetchAndSubscribe.reg];
999
1000         if (reg.isUndefined())
1001             THROW_EXCEPTION(instr->fetchAndSubscribe.exceptionId);
1002
1003         QObject *object = reg.getQObject();
1004         if (!object) {
1005             THROW_EXCEPTION(instr->fetchAndSubscribe.exceptionId);
1006         } else {
1007             if (bindingInvalidated(invalidated, object, context, instr->fetchAndSubscribe.property.coreIndex))
1008                 goto programExit;
1009
1010             const Register::Type valueType = (Register::Type)instr->fetchAndSubscribe.valueType;
1011             reg.init(valueType);
1012             if (instr->fetchAndSubscribe.valueType >= FirstCleanupType)
1013                 MARK_REGISTER(instr->fetchAndSubscribe.reg);
1014
1015             QQmlData::flushPendingBinding(object, instr->fetchAndSubscribe.property.coreIndex);
1016
1017             QQmlAccessors *accessors = instr->fetchAndSubscribe.property.accessors;
1018             accessors->read(object, instr->fetchAndSubscribe.property.accessorData,
1019                             reg.typeDataPtr());
1020
1021             if (valueType == FloatType) {
1022                 // promote floats
1023                 const double v = reg.getfloat();
1024                 reg.setnumber(v);
1025             }
1026
1027             if (accessors->notifier) {
1028                 QQmlNotifier *notifier = 0;
1029                 accessors->notifier(object, instr->fetchAndSubscribe.property.accessorData, &notifier);
1030                 if (notifier) {
1031                     int subIdx = instr->fetchAndSubscribe.subscription;
1032                     Subscription *sub = 0;
1033                     if (subIdx != -1) {
1034                         sub = (subscriptions + subIdx);
1035                         sub->setBindings(this);
1036                     }
1037                     sub->connect(notifier);
1038                 }
1039             } else {
1040                 const int notifyIndex = instr->fetchAndSubscribe.property.notifyIndex;
1041                 if (notifyIndex != -1) {
1042                     const int subIdx = instr->fetchAndSubscribe.subscription;
1043                     subscribe(object, notifyIndex, subIdx, context->engine);
1044                 }
1045             }
1046         }
1047     }
1048     QML_V4_END_INSTR(FetchAndSubscribe, fetchAndSubscribe)
1049
1050     QML_V4_BEGIN_INSTR(LoadId, load)
1051         registers[instr->load.reg].setQObject(context->idValues[instr->load.index].data());
1052     QML_V4_END_INSTR(LoadId, load)
1053
1054     QML_V4_BEGIN_INSTR(LoadScope, load)
1055         registers[instr->load.reg].setQObject(scope);
1056     QML_V4_END_INSTR(LoadScope, load)
1057
1058     QML_V4_BEGIN_INSTR(LoadRoot, load)
1059         registers[instr->load.reg].setQObject(context->contextObject);
1060     QML_V4_END_INSTR(LoadRoot, load)
1061
1062     QML_V4_BEGIN_INSTR(LoadSingletonObject, load)
1063     {
1064         Register &reg = registers[instr->load.reg];
1065
1066         const QString *name = reg.getstringptr();
1067         QQmlTypeNameCache::Result r = context->imports->query(*name);
1068         reg.cleanupString();
1069
1070         if (r.isValid() && r.type) {
1071             if (r.type->isSingleton()) {
1072                 QQmlEngine *e = context->engine;
1073                 QQmlType::SingletonInstanceInfo *siinfo = r.type->singletonInstanceInfo();
1074                 siinfo->init(e); // note: this will also create QJSValue singleton, which is not strictly required here.
1075                 QObject *qobjectSingleton = siinfo->qobjectApi(e);
1076                 if (qobjectSingleton)
1077                     reg.setQObject(qobjectSingleton);
1078             }
1079         }
1080     }
1081     QML_V4_END_INSTR(LoadSingletonObject, load)
1082
1083     QML_V4_BEGIN_INSTR(LoadAttached, attached)
1084     {
1085         const Register &input = registers[instr->attached.reg];
1086         Register &output = registers[instr->attached.output];
1087         if (input.isUndefined())
1088             THROW_EXCEPTION(instr->attached.exceptionId);
1089
1090         QObject *object = registers[instr->attached.reg].getQObject();
1091         if (!object) {
1092             output.setUndefined();
1093         } else {
1094             QObject *attached = qmlAttachedPropertiesObjectById(instr->attached.id, input.getQObject(), true);
1095             Q_ASSERT(attached);
1096             output.setQObject(attached);
1097         }
1098     }
1099     QML_V4_END_INSTR(LoadAttached, attached)
1100
1101     QML_V4_BEGIN_INSTR(UnaryNot, unaryop)
1102     {
1103         registers[instr->unaryop.output].setbool(!registers[instr->unaryop.src].getbool());
1104     }
1105     QML_V4_END_INSTR(UnaryNot, unaryop)
1106
1107     QML_V4_BEGIN_INSTR(UnaryMinusNumber, unaryop)
1108     {
1109         registers[instr->unaryop.output].setnumber(-registers[instr->unaryop.src].getnumber());
1110     }
1111     QML_V4_END_INSTR(UnaryMinusNumber, unaryop)
1112
1113     QML_V4_BEGIN_INSTR(UnaryMinusInt, unaryop)
1114     {
1115         registers[instr->unaryop.output].setint(-registers[instr->unaryop.src].getint());
1116     }
1117     QML_V4_END_INSTR(UnaryMinusInt, unaryop)
1118
1119     QML_V4_BEGIN_INSTR(UnaryPlusNumber, unaryop)
1120     {
1121         registers[instr->unaryop.output].setnumber(+registers[instr->unaryop.src].getnumber());
1122     }
1123     QML_V4_END_INSTR(UnaryPlusNumber, unaryop)
1124
1125     QML_V4_BEGIN_INSTR(UnaryPlusInt, unaryop)
1126     {
1127         registers[instr->unaryop.output].setint(+registers[instr->unaryop.src].getint());
1128     }
1129     QML_V4_END_INSTR(UnaryPlusInt, unaryop)
1130
1131     QML_V4_BEGIN_INSTR(ConvertBoolToInt, unaryop)
1132     {
1133         const Register &src = registers[instr->unaryop.src];
1134         Register &output = registers[instr->unaryop.output];
1135         if (src.isUndefined()) output.setUndefined();
1136         else output.setint(src.getbool());
1137     }
1138     QML_V4_END_INSTR(ConvertBoolToInt, unaryop)
1139
1140     QML_V4_BEGIN_INSTR(ConvertBoolToJSValue, unaryop)
1141     {
1142         const Register &src = registers[instr->unaryop.src];
1143         Register &output = registers[instr->unaryop.output];
1144         if (src.isUndefined()) {
1145             output.setUndefined();
1146         } else {
1147             new (output.getjsvalueptr()) QJSValue(src.getbool());
1148             JSVALUE_REGISTER(instr->unaryop.output);
1149         }
1150     }
1151     QML_V4_END_INSTR(ConvertBoolToJSValue, unaryop)
1152
1153     QML_V4_BEGIN_INSTR(ConvertBoolToNumber, unaryop)
1154     {
1155         const Register &src = registers[instr->unaryop.src];
1156         Register &output = registers[instr->unaryop.output];
1157         if (src.isUndefined()) output.setUndefined();
1158         else output.setnumber(src.getbool());
1159     }
1160     QML_V4_END_INSTR(ConvertBoolToNumber, unaryop)
1161
1162     QML_V4_BEGIN_INSTR(ConvertBoolToString, unaryop)
1163     {
1164         const Register &src = registers[instr->unaryop.src];
1165         Register &output = registers[instr->unaryop.output];
1166         if (src.isUndefined()) {
1167             output.setUndefined();
1168         } else {
1169             new (output.getstringptr()) QString(QLatin1String(src.getbool() ? "true" : "false"));
1170             STRING_REGISTER(instr->unaryop.output);
1171         }
1172     }
1173     QML_V4_END_INSTR(ConvertBoolToString, unaryop)
1174
1175     QML_V4_BEGIN_INSTR(ConvertBoolToVariant, unaryop)
1176     {
1177         const Register &src = registers[instr->unaryop.src];
1178         Register &output = registers[instr->unaryop.output];
1179         if (src.isUndefined()) {
1180             output.setUndefined();
1181         } else {
1182             new (output.getvariantptr()) QVariant(src.getbool());
1183             VARIANT_REGISTER(instr->unaryop.output);
1184         }
1185     }
1186     QML_V4_END_INSTR(ConvertBoolToVariant, unaryop)
1187
1188     QML_V4_BEGIN_INSTR(ConvertBoolToVar, unaryop)
1189     {
1190         const Register &src = registers[instr->unaryop.src];
1191         Register &output = registers[instr->unaryop.output];
1192         if (src.isUndefined()) {
1193             output.setUndefined();
1194         } else {
1195             new (output.gethandleptr()) v8::Handle<v8::Value>(v8::Boolean::New(src.getbool()));
1196             V8HANDLE_REGISTER(instr->unaryop.output);
1197         }
1198     }
1199     QML_V4_END_INSTR(ConvertBoolToVar, unaryop)
1200
1201     QML_V4_BEGIN_INSTR(ConvertIntToBool, unaryop)
1202     {
1203         const Register &src = registers[instr->unaryop.src];
1204         Register &output = registers[instr->unaryop.output];
1205         if (src.isUndefined()) output.setUndefined();
1206         else output.setbool(src.getint());
1207     }
1208     QML_V4_END_INSTR(ConvertIntToBool, unaryop)
1209
1210     QML_V4_BEGIN_INSTR(ConvertIntToJSValue, unaryop)
1211     {
1212         const Register &src = registers[instr->unaryop.src];
1213         Register &output = registers[instr->unaryop.output];
1214         if (src.isUndefined()) {
1215             output.setUndefined();
1216         } else {
1217             new (output.getjsvalueptr()) QJSValue(src.getint());
1218             JSVALUE_REGISTER(instr->unaryop.output);
1219         }
1220     }
1221     QML_V4_END_INSTR(ConvertIntToJSValue, unaryop)
1222
1223     QML_V4_BEGIN_INSTR(ConvertIntToNumber, unaryop)
1224     {
1225         const Register &src = registers[instr->unaryop.src];
1226         Register &output = registers[instr->unaryop.output];
1227         if (src.isUndefined()) output.setUndefined();
1228         else if (src.isNaN()) output.setNaN();
1229         else if (src.isInf()) output.setInf(src.getint() == Register::NegativeInfinity);
1230         else if (src.isNegativeZero()) output.setNegativeZero();
1231         else output.setnumber(double(src.getint()));
1232     }
1233     QML_V4_END_INSTR(ConvertIntToNumber, unaryop)
1234
1235     QML_V4_BEGIN_INSTR(ConvertIntToString, unaryop)
1236     {
1237         const Register &src = registers[instr->unaryop.src];
1238         Register &output = registers[instr->unaryop.output];
1239         if (src.isUndefined()) {
1240             output.setUndefined();
1241         } else {
1242             new (output.getstringptr()) QString(QString::number(src.getint()));
1243             STRING_REGISTER(instr->unaryop.output);
1244         }
1245     }
1246     QML_V4_END_INSTR(ConvertIntToString, unaryop)
1247
1248     QML_V4_BEGIN_INSTR(ConvertIntToVariant, unaryop)
1249     {
1250         const Register &src = registers[instr->unaryop.src];
1251         Register &output = registers[instr->unaryop.output];
1252         if (src.isUndefined()) {
1253             output.setUndefined();
1254         } else {
1255             new (output.getvariantptr()) QVariant(src.getint());
1256             VARIANT_REGISTER(instr->unaryop.output);
1257         }
1258     }
1259     QML_V4_END_INSTR(ConvertIntToVariant, unaryop)
1260
1261     QML_V4_BEGIN_INSTR(ConvertIntToVar, unaryop)
1262     {
1263         const Register &src = registers[instr->unaryop.src];
1264         Register &output = registers[instr->unaryop.output];
1265         if (src.isUndefined()) {
1266             output.setUndefined();
1267         } else {
1268             new (output.gethandleptr()) v8::Handle<v8::Value>(v8::Integer::New(src.getint()));
1269             V8HANDLE_REGISTER(instr->unaryop.output);
1270         }
1271     }
1272     QML_V4_END_INSTR(ConvertIntToVar, unaryop)
1273
1274     QML_V4_BEGIN_INSTR(ConvertJSValueToVar, unaryop)
1275     {
1276         const Register &src = registers[instr->unaryop.src];
1277         Register &output = registers[instr->unaryop.output];
1278         if (src.isUndefined()) {
1279             output.setUndefined();
1280         } else {
1281             QJSValue tmp(*src.getjsvalueptr());
1282             if (instr->unaryop.src == instr->unaryop.output) {
1283                 output.cleanupJSValue();
1284                 MARK_CLEAN_REGISTER(instr->unaryop.output);
1285             }
1286             if (tmp.isUndefined()) {
1287                 output.setUndefined();
1288             } else {
1289                 QV8Engine *v8engine = QQmlEnginePrivate::get(context->engine)->v8engine();
1290                 new (output.gethandleptr()) v8::Handle<v8::Value>(
1291                         QJSValuePrivate::get(tmp)->asV8Value(v8engine));
1292                 V8HANDLE_REGISTER(instr->unaryop.output);
1293             }
1294         }
1295     }
1296     QML_V4_END_INSTR(ConvertJSValueToVar, unaryop)
1297
1298     QML_V4_BEGIN_INSTR(ConvertNumberToBool, unaryop)
1299     {
1300         const Register &src = registers[instr->unaryop.src];
1301         Register &output = registers[instr->unaryop.output];
1302         if (src.isUndefined()) output.setUndefined();
1303         else output.setbool(src.getnumber() != 0);
1304     }
1305     QML_V4_END_INSTR(ConvertNumberToBool, unaryop)
1306
1307     QML_V4_BEGIN_INSTR(ConvertNumberToInt, unaryop)
1308     {
1309         const Register &src = registers[instr->unaryop.src];
1310         Register &output = registers[instr->unaryop.output];
1311         if (src.isUndefined()) output.setUndefined();
1312         else output.setint(toInt32(src.getnumber()));
1313     }
1314     QML_V4_END_INSTR(ConvertNumberToInt, unaryop)
1315
1316     QML_V4_BEGIN_INSTR(ConvertNumberToJSValue, unaryop)
1317     {
1318         const Register &src = registers[instr->unaryop.src];
1319         Register &output = registers[instr->unaryop.output];
1320         if (src.isUndefined()) {
1321             output.setUndefined();
1322         } else {
1323             new (output.getjsvalueptr()) QJSValue(src.getnumber());
1324             JSVALUE_REGISTER(instr->unaryop.output);
1325         }
1326     }
1327     QML_V4_END_INSTR(ConvertNumberToJSValue, unaryop)
1328
1329     QML_V4_BEGIN_INSTR(ConvertNumberToString, unaryop)
1330     {
1331         const Register &src = registers[instr->unaryop.src];
1332         Register &output = registers[instr->unaryop.output];
1333         // ### NaN
1334         if (src.isUndefined()) {
1335             output.setUndefined();
1336         } else {
1337             new (output.getstringptr()) QString(QString::number(src.getnumber(), 'g', 16));
1338             STRING_REGISTER(instr->unaryop.output);
1339         }
1340     }
1341     QML_V4_END_INSTR(ConvertNumberToString, unaryop)
1342
1343     QML_V4_BEGIN_INSTR(ConvertNumberToVariant, unaryop)
1344     {
1345         const Register &src = registers[instr->unaryop.src];
1346         Register &output = registers[instr->unaryop.output];
1347         if (src.isUndefined()) {
1348             output.setUndefined();
1349         } else {
1350             new (output.getvariantptr()) QVariant(src.getnumber());
1351             VARIANT_REGISTER(instr->unaryop.output);
1352         }
1353     }
1354     QML_V4_END_INSTR(ConvertNumberToVariant, unaryop)
1355
1356     QML_V4_BEGIN_INSTR(ConvertNumberToVar, unaryop)
1357     {
1358         const Register &src = registers[instr->unaryop.src];
1359         Register &output = registers[instr->unaryop.output];
1360         if (src.isUndefined()) {
1361             output.setUndefined();
1362         } else {
1363             new (output.gethandleptr()) v8::Handle<v8::Value>(v8::Number::New(src.getnumber()));
1364             V8HANDLE_REGISTER(instr->unaryop.output);
1365         }
1366     }
1367     QML_V4_END_INSTR(ConvertNumberToVar, unaryop)
1368
1369     QML_V4_BEGIN_INSTR(ConvertStringToBool, unaryop)
1370     {
1371         const Register &src = registers[instr->unaryop.src];
1372         Register &output = registers[instr->unaryop.output];
1373         // ### NaN
1374         if (src.isUndefined()) {
1375             output.setUndefined();
1376         } else {
1377             // Delegate the conversion. This is pretty fast and it doesn't require a QScriptEngine.
1378             // Ideally we should just call the methods in the QScript namespace directly.
1379             QJSValue tmp(*src.getstringptr());
1380             if (instr->unaryop.src == instr->unaryop.output) {
1381                 output.cleanupString();
1382                 MARK_CLEAN_REGISTER(instr->unaryop.output);
1383             }
1384             output.setbool(tmp.toBool());
1385         }
1386     }
1387     QML_V4_END_INSTR(ConvertStringToBool, unaryop)
1388
1389     QML_V4_BEGIN_INSTR(ConvertStringToInt, unaryop)
1390     {
1391         const Register &src = registers[instr->unaryop.src];
1392         Register &output = registers[instr->unaryop.output];
1393         // ### NaN
1394         if (src.isUndefined()) {
1395             output.setUndefined();
1396         } else {
1397             // Delegate the conversion. This is pretty fast and it doesn't require a QScriptEngine.
1398             // Ideally we should just call the methods in the QScript namespace directly.
1399             QJSValue tmp(*src.getstringptr());
1400             if (instr->unaryop.src == instr->unaryop.output) {
1401                 output.cleanupString();
1402                 MARK_CLEAN_REGISTER(instr->unaryop.output);
1403             }
1404             output.setint(tmp.toInt());
1405         }
1406     }
1407     QML_V4_END_INSTR(ConvertStringToInt, unaryop)
1408
1409     QML_V4_BEGIN_INSTR(ConvertStringToJSValue, unaryop)
1410     {
1411         const Register &src = registers[instr->unaryop.src];
1412         Register &output = registers[instr->unaryop.output];
1413         if (src.isUndefined()) {
1414             output.setUndefined();
1415         } else {
1416             QString tmp(*src.getstringptr());
1417             if (instr->unaryop.src == instr->unaryop.output) {
1418                 output.cleanupString();
1419                 MARK_CLEAN_REGISTER(instr->unaryop.output);
1420             }
1421             new (output.getjsvalueptr()) QJSValue(tmp);
1422             JSVALUE_REGISTER(instr->unaryop.output);
1423         }
1424     }
1425     QML_V4_END_INSTR(ConvertStringToJSValue, unaryop)
1426
1427     QML_V4_BEGIN_INSTR(ConvertStringToNumber, unaryop)
1428     {
1429         const Register &src = registers[instr->unaryop.src];
1430         Register &output = registers[instr->unaryop.output];
1431         // ### NaN
1432         if (src.isUndefined()) {
1433             output.setUndefined();
1434         } else {
1435             // Delegate the conversion. This is pretty fast and it doesn't require a QScriptEngine.
1436             // Ideally we should just call the methods in the QScript namespace directly.
1437             QJSValue tmp(*src.getstringptr());
1438             if (instr->unaryop.src == instr->unaryop.output) {
1439                 output.cleanupString();
1440                 MARK_CLEAN_REGISTER(instr->unaryop.output);
1441             }
1442             output.setnumber(tmp.toNumber());
1443         }
1444     }
1445     QML_V4_END_INSTR(ConvertStringToNumber, unaryop)
1446
1447     QML_V4_BEGIN_INSTR(ConvertStringToUrl, unaryop)
1448     {
1449         const Register &src = registers[instr->unaryop.src];
1450         Register &output = registers[instr->unaryop.output];
1451         // ### NaN
1452         if (src.isUndefined()) {
1453             output.setUndefined();
1454         } else {
1455             QString tmp(*src.getstringptr());
1456             // Encoded dir-separators defeat QUrl processing - decode them first
1457             tmp.replace(QLatin1String("%2f"), QLatin1String("/"), Qt::CaseInsensitive);
1458             if (instr->unaryop.src == instr->unaryop.output) {
1459                 output.cleanupString();
1460                 MARK_CLEAN_REGISTER(instr->unaryop.output);
1461             }
1462             new (output.geturlptr()) QUrl(tmp);
1463
1464             URL_REGISTER(instr->unaryop.output);
1465         }
1466     }
1467     QML_V4_END_INSTR(ConvertStringToUrl, unaryop)
1468
1469     QML_V4_BEGIN_INSTR(ConvertStringToColor, unaryop)
1470     {
1471         const Register &src = registers[instr->unaryop.src];
1472         Register &output = registers[instr->unaryop.output];
1473         // ### NaN
1474         if (src.isUndefined()) {
1475             output.setUndefined();
1476         } else {
1477             const QString tmp(*src.getstringptr());
1478             if (instr->unaryop.src == instr->unaryop.output) {
1479                 output.cleanupString();
1480                 MARK_CLEAN_REGISTER(instr->unaryop.output);
1481             }
1482             QQml_valueTypeProvider()->createValueFromString(QMetaType::QColor, tmp, output.typeDataPtr(), output.dataSize());
1483
1484             COLOR_REGISTER(instr->unaryop.output);
1485         }
1486     }
1487     QML_V4_END_INSTR(ConvertStringToColor, unaryop)
1488
1489     QML_V4_BEGIN_INSTR(ConvertStringToVariant, unaryop)
1490     {
1491         const Register &src = registers[instr->unaryop.src];
1492         Register &output = registers[instr->unaryop.output];
1493         if (src.isUndefined()) {
1494             output.setUndefined();
1495         } else {
1496             const QString tmp(*src.getstringptr());
1497             if (instr->unaryop.src == instr->unaryop.output) {
1498                 output.cleanupString();
1499                 MARK_CLEAN_REGISTER(instr->unaryop.output);
1500             }
1501             new (output.getvariantptr()) QVariant(tmp);
1502
1503             VARIANT_REGISTER(instr->unaryop.output);
1504         }
1505     }
1506     QML_V4_END_INSTR(ConvertStringToVariant, unaryop)
1507
1508     QML_V4_BEGIN_INSTR(ConvertStringToVar, unaryop)
1509     {
1510         const Register &src = registers[instr->unaryop.src];
1511         Register &output = registers[instr->unaryop.output];
1512         if (src.isUndefined()) {
1513             output.setUndefined();
1514         } else {
1515             const QString tmp(*src.getstringptr());
1516             if (instr->unaryop.src == instr->unaryop.output) {
1517                 output.cleanupString();
1518                 MARK_CLEAN_REGISTER(instr->unaryop.output);
1519             }
1520             new (output.gethandleptr()) v8::Handle<v8::Value>(QJSConverter::toString(tmp));
1521             V8HANDLE_REGISTER(instr->unaryop.output);
1522         }
1523     }
1524     QML_V4_END_INSTR(ConvertStringToVar, unaryop)
1525
1526     QML_V4_BEGIN_INSTR(ConvertUrlToBool, unaryop)
1527     {
1528         const Register &src = registers[instr->unaryop.src];
1529         Register &output = registers[instr->unaryop.output];
1530         // ### NaN
1531         if (src.isUndefined()) {
1532             output.setUndefined();
1533         } else {
1534             const QUrl tmp(*src.geturlptr());
1535             if (instr->unaryop.src == instr->unaryop.output) {
1536                 output.cleanupUrl();
1537                 MARK_CLEAN_REGISTER(instr->unaryop.output);
1538             }
1539             output.setbool(!tmp.isEmpty());
1540         }
1541     }
1542     QML_V4_END_INSTR(ConvertUrlToBool, unaryop)
1543
1544     QML_V4_BEGIN_INSTR(ConvertUrlToJSValue, unaryop)
1545     {
1546         const Register &src = registers[instr->unaryop.src];
1547         Register &output = registers[instr->unaryop.output];
1548         if (src.isUndefined()) {
1549             output.setUndefined();
1550         } else {
1551             const QUrl tmp(*src.geturlptr());
1552             if (instr->unaryop.src == instr->unaryop.output) {
1553                 output.cleanupUrl();
1554                 MARK_CLEAN_REGISTER(instr->unaryop.output);
1555             }
1556             new (output.getjsvalueptr()) QJSValue(tmp.toString());
1557             JSVALUE_REGISTER(instr->unaryop.output);
1558         }
1559     }
1560     QML_V4_END_INSTR(ConvertUrlToJSValue, unaryop)
1561
1562     QML_V4_BEGIN_INSTR(ConvertUrlToString, unaryop)
1563     {
1564         const Register &src = registers[instr->unaryop.src];
1565         Register &output = registers[instr->unaryop.output];
1566         // ### NaN
1567         if (src.isUndefined()) {
1568             output.setUndefined();
1569         } else {
1570             const QUrl tmp(*src.geturlptr());
1571             if (instr->unaryop.src == instr->unaryop.output) {
1572                 output.cleanupUrl();
1573                 MARK_CLEAN_REGISTER(instr->unaryop.output);
1574             }
1575             new (output.getstringptr()) QString(tmp.toString());
1576             STRING_REGISTER(instr->unaryop.output);
1577         }
1578     }
1579     QML_V4_END_INSTR(ConvertUrlToString, unaryop)
1580
1581     QML_V4_BEGIN_INSTR(ConvertUrlToVariant, unaryop)
1582     {
1583         const Register &src = registers[instr->unaryop.src];
1584         Register &output = registers[instr->unaryop.output];
1585         // ### NaN
1586         if (src.isUndefined()) {
1587             output.setUndefined();
1588         } else {
1589             const QUrl tmp(*src.geturlptr());
1590             if (instr->unaryop.src == instr->unaryop.output) {
1591                 output.cleanupUrl();
1592                 MARK_CLEAN_REGISTER(instr->unaryop.output);
1593             }
1594             new (output.getvariantptr()) QVariant(tmp);
1595             VARIANT_REGISTER(instr->unaryop.output);
1596         }
1597     }
1598     QML_V4_END_INSTR(ConvertUrlToVariant, unaryop)
1599
1600     QML_V4_BEGIN_INSTR(ConvertUrlToVar, unaryop)
1601     {
1602         const Register &src = registers[instr->unaryop.src];
1603         Register &output = registers[instr->unaryop.output];
1604         // ### NaN
1605         if (src.isUndefined()) {
1606             output.setUndefined();
1607         } else {
1608             const QUrl tmp(*src.geturlptr());
1609             if (instr->unaryop.src == instr->unaryop.output) {
1610                 output.cleanupUrl();
1611                 MARK_CLEAN_REGISTER(instr->unaryop.output);
1612             }
1613             new (output.gethandleptr()) v8::Handle<v8::Value>(QJSConverter::toString(tmp.toString()));
1614             V8HANDLE_REGISTER(instr->unaryop.output);
1615         }
1616     }
1617     QML_V4_END_INSTR(ConvertUrlToVar, unaryop)
1618
1619     QML_V4_BEGIN_INSTR(ConvertColorToBool, unaryop)
1620     {
1621         const Register &src = registers[instr->unaryop.src];
1622         Register &output = registers[instr->unaryop.output];
1623         // ### NaN
1624         if (src.isUndefined()) {
1625             output.setUndefined();
1626         } else {
1627             // for compatibility with color behavior in v8, always true
1628             output.setbool(true);
1629         }
1630     }
1631     QML_V4_END_INSTR(ConvertColorToBool, unaryop)
1632
1633     QML_V4_BEGIN_INSTR(ConvertColorToJSValue, unaryop)
1634     {
1635         const Register &src = registers[instr->unaryop.src];
1636         Register &output = registers[instr->unaryop.output];
1637         if (src.isUndefined()) {
1638             output.setUndefined();
1639         } else {
1640             const QVariant tmp(QMetaType::QColor, src.typeDataPtr());
1641             if (instr->unaryop.src == instr->unaryop.output) {
1642                 output.cleanupColor();
1643                 MARK_CLEAN_REGISTER(instr->unaryop.output);
1644             }
1645
1646             QQmlEnginePrivate *ep = QQmlEnginePrivate::get(context->engine);
1647             QV8Engine *v8engine = ep->v8engine();
1648             QQmlValueType *vt = QQmlValueTypeFactory::valueType(QMetaType::QColor);
1649             v8::HandleScope handle_scope;
1650             v8::Context::Scope scope(v8engine->context());
1651             new (output.getjsvalueptr()) QJSValue(v8engine->scriptValueFromInternal(
1652                     v8engine->valueTypeWrapper()->newValueType(tmp, vt)));
1653             JSVALUE_REGISTER(instr->unaryop.output);
1654         }
1655     }
1656     QML_V4_END_INSTR(ConvertColorToJSValue, unaryop)
1657
1658     QML_V4_BEGIN_INSTR(ConvertColorToString, unaryop)
1659     {
1660         const Register &src = registers[instr->unaryop.src];
1661         Register &output = registers[instr->unaryop.output];
1662         // ### NaN
1663         if (src.isUndefined()) {
1664             output.setUndefined();
1665         } else {
1666             QQml_valueTypeProvider()->createStringFromValue(QMetaType::QColor, src.typeDataPtr(), output.getstringptr());
1667             STRING_REGISTER(instr->unaryop.output);
1668         }
1669     }
1670     QML_V4_END_INSTR(ConvertColorToString, unaryop)
1671
1672     QML_V4_BEGIN_INSTR(ConvertColorToVariant, unaryop)
1673     {
1674         const Register &src = registers[instr->unaryop.src];
1675         Register &output = registers[instr->unaryop.output];
1676         // ### NaN
1677         if (src.isUndefined()) {
1678             output.setUndefined();
1679         } else {
1680             QVariant tmp(QMetaType::QColor, src.typeDataPtr());
1681             if (instr->unaryop.src == instr->unaryop.output) {
1682                 output.cleanupColor();
1683                 MARK_CLEAN_REGISTER(instr->unaryop.output);
1684             }
1685             new (output.getvariantptr()) QVariant(tmp);
1686             VARIANT_REGISTER(instr->unaryop.output);
1687         }
1688     }
1689     QML_V4_END_INSTR(ConvertColorToVariant, unaryop)
1690
1691     QML_V4_BEGIN_INSTR(ConvertColorToVar, unaryop)
1692     {
1693         const Register &src = registers[instr->unaryop.src];
1694         Register &output = registers[instr->unaryop.output];
1695         // ### NaN
1696         if (src.isUndefined()) {
1697             output.setUndefined();
1698         } else {
1699             const QVariant tmp(QMetaType::QColor, src.typeDataPtr());
1700             if (instr->unaryop.src == instr->unaryop.output) {
1701                 output.cleanupColor();
1702                 MARK_CLEAN_REGISTER(instr->unaryop.output);
1703             }
1704
1705             QQmlEnginePrivate *ep = QQmlEnginePrivate::get(context->engine);
1706             QQmlValueType *vt = QQmlValueTypeFactory::valueType(QMetaType::QColor);
1707             new (output.gethandleptr()) v8::Handle<v8::Value>(ep->v8engine()->valueTypeWrapper()->newValueType(tmp, vt));
1708             V8HANDLE_REGISTER(instr->unaryop.output);
1709         }
1710     }
1711     QML_V4_END_INSTR(ConvertColorToVar, unaryop)
1712
1713     QML_V4_BEGIN_INSTR(ConvertObjectToBool, unaryop)
1714     {
1715         const Register &src = registers[instr->unaryop.src];
1716         Register &output = registers[instr->unaryop.output];
1717         // ### NaN
1718         if (src.isUndefined())
1719             output.setUndefined();
1720         else
1721             output.setbool(src.getQObject() != 0);
1722     }
1723     QML_V4_END_INSTR(ConvertObjectToBool, unaryop)
1724
1725     QML_V4_BEGIN_INSTR(ConvertObjectToJSValue, unaryop)
1726     {
1727         const Register &src = registers[instr->unaryop.src];
1728         Register &output = registers[instr->unaryop.output];
1729         if (src.isUndefined()) {
1730             output.setUndefined();
1731         } else {
1732             QQmlEnginePrivate *ep = QQmlEnginePrivate::get(context->engine);
1733             v8::HandleScope handle_scope;
1734             v8::Context::Scope scope(ep->v8engine()->context());
1735             new (output.getjsvalueptr()) QJSValue(context->engine->newQObject(src.getQObject()));
1736             JSVALUE_REGISTER(instr->unaryop.output);
1737         }
1738     }
1739     QML_V4_END_INSTR(ConvertObjectToJSValue, unaryop)
1740
1741     QML_V4_BEGIN_INSTR(ConvertObjectToVariant, unaryop)
1742     {
1743         const Register &src = registers[instr->unaryop.src];
1744         Register &output = registers[instr->unaryop.output];
1745         // ### NaN
1746         if (src.isUndefined())
1747             output.setUndefined();
1748         else {
1749             new (output.getvariantptr()) QVariant(qVariantFromValue<QObject *>(src.getQObject()));
1750             VARIANT_REGISTER(instr->unaryop.output);
1751         }
1752     }
1753     QML_V4_END_INSTR(ConvertObjectToVariant, unaryop)
1754
1755     QML_V4_BEGIN_INSTR(ConvertObjectToVar, unaryop)
1756     {
1757         const Register &src = registers[instr->unaryop.src];
1758         Register &output = registers[instr->unaryop.output];
1759         // ### NaN
1760         if (src.isUndefined())
1761             output.setUndefined();
1762         else {
1763             QQmlEnginePrivate *ep = QQmlEnginePrivate::get(context->engine);
1764             new (output.gethandleptr()) v8::Handle<v8::Value>(ep->v8engine()->newQObject(src.getQObject()));
1765             V8HANDLE_REGISTER(instr->unaryop.output);
1766         }
1767     }
1768     QML_V4_END_INSTR(ConvertObjectToVar, unaryop)
1769
1770     QML_V4_BEGIN_INSTR(ConvertVarToJSValue, unaryop)
1771     {
1772         const Register &src = registers[instr->unaryop.src];
1773         Register &output = registers[instr->unaryop.output];
1774         if (src.isUndefined()) {
1775             output.setUndefined();
1776         } else {
1777             v8::Handle<v8::Value> tmp(*src.gethandleptr());
1778             if (instr->unaryop.src == instr->unaryop.output) {
1779                 output.cleanupHandle();
1780                 MARK_CLEAN_REGISTER(instr->unaryop.output);
1781             }
1782             QV8Engine *v8engine = QQmlEnginePrivate::get(context->engine)->v8engine();
1783             new (output.getjsvalueptr()) QJSValue(v8engine->scriptValueFromInternal(tmp));
1784             JSVALUE_REGISTER(instr->unaryop.output);
1785         }
1786     }
1787     QML_V4_END_INSTR(ConvertVarToJSValue, unaryop)
1788
1789     QML_V4_BEGIN_INSTR(ConvertNullToJSValue, unaryop)
1790     {
1791         Register &output = registers[instr->unaryop.output];
1792         new (output.getjsvalueptr()) QJSValue(QJSValue::NullValue);
1793         JSVALUE_REGISTER(instr->unaryop.output);
1794     }
1795     QML_V4_END_INSTR(ConvertNullToJSValue, unaryop)
1796
1797     QML_V4_BEGIN_INSTR(ConvertNullToObject, unaryop)
1798     {
1799         Register &output = registers[instr->unaryop.output];
1800         output.setQObject(0);
1801     }
1802     QML_V4_END_INSTR(ConvertNullToObject, unaryop)
1803
1804     QML_V4_BEGIN_INSTR(ConvertNullToVariant, unaryop)
1805     {
1806         Register &output = registers[instr->unaryop.output];
1807         new (output.getvariantptr()) QVariant();
1808         VARIANT_REGISTER(instr->unaryop.output);
1809     }
1810     QML_V4_END_INSTR(ConvertNullToVariant, unaryop)
1811
1812     QML_V4_BEGIN_INSTR(ConvertNullToVar, unaryop)
1813     {
1814         Register &output = registers[instr->unaryop.output];
1815         new (output.gethandleptr()) v8::Handle<v8::Value>(v8::Null());
1816         V8HANDLE_REGISTER(instr->unaryop.output);
1817     }
1818     QML_V4_END_INSTR(ConvertNullToVar, unaryop)
1819
1820     QML_V4_BEGIN_INSTR(ResolveUrl, unaryop)
1821     {
1822         const Register &src = registers[instr->unaryop.src];
1823         Register &output = registers[instr->unaryop.output];
1824         if (src.isUndefined()) {
1825             output.setUndefined();
1826         } else {
1827             const QUrl tmp(*src.geturlptr());
1828             if (instr->unaryop.src == instr->unaryop.output) {
1829                 *output.geturlptr() = context->resolvedUrl(tmp);
1830             } else {
1831                 new (output.geturlptr()) QUrl(context->resolvedUrl(tmp));
1832                 URL_REGISTER(instr->unaryop.output);
1833             }
1834         }
1835     }
1836     QML_V4_END_INSTR(ResolveUrl, unaryop)
1837
1838     QML_V4_BEGIN_INSTR(MathSinNumber, unaryop)
1839     {
1840         const Register &src = registers[instr->unaryop.src];
1841         Register &output = registers[instr->unaryop.output];
1842         if (src.isUndefined()) output.setUndefined();
1843         else output.setnumber(qSin(src.getnumber()));
1844     }
1845     QML_V4_END_INSTR(MathSinNumber, unaryop)
1846
1847     QML_V4_BEGIN_INSTR(MathCosNumber, unaryop)
1848     {
1849         const Register &src = registers[instr->unaryop.src];
1850         Register &output = registers[instr->unaryop.output];
1851         if (src.isUndefined()) output.setUndefined();
1852         else output.setnumber(qCos(src.getnumber()));
1853     }
1854     QML_V4_END_INSTR(MathCosNumber, unaryop)
1855
1856     QML_V4_BEGIN_INSTR(MathAbsNumber, unaryop)
1857     {
1858         const Register &src = registers[instr->unaryop.src];
1859         Register &output = registers[instr->unaryop.output];
1860         if (src.isUndefined()) output.setUndefined();
1861         else output.setnumber(clearSignBit(qAbs(src.getnumber())));
1862     }
1863     QML_V4_END_INSTR(MathAbsNumber, unaryop)
1864
1865     QML_V4_BEGIN_INSTR(MathRoundNumber, unaryop)
1866     {
1867         const Register &src = registers[instr->unaryop.src];
1868         Register &output = registers[instr->unaryop.output];
1869         if (src.isUndefined()) output.setUndefined();
1870         else output.setint(qRound(src.getnumber()));
1871     }
1872     QML_V4_END_INSTR(MathRoundNumber, unaryop)
1873
1874     QML_V4_BEGIN_INSTR(MathFloorNumber, unaryop)
1875     {
1876         const Register &src = registers[instr->unaryop.src];
1877         Register &output = registers[instr->unaryop.output];
1878         if (src.isUndefined())
1879             output.setUndefined();
1880         else if (src.isNaN())
1881             // output should be an int, but still NaN
1882             output.setNaNType();
1883         else if (src.isInf())
1884             // output should be an int, but still Inf
1885             output.setInfType(signBitSet(src.getnumber()));
1886         else if (src.isNegativeZero())
1887             // output should be an int, but still -0
1888             output.setNegativeZeroType();
1889         else
1890             output.setint(qFloor(src.getnumber()));
1891     }
1892     QML_V4_END_INSTR(MathFloorNumber, unaryop)
1893
1894     QML_V4_BEGIN_INSTR(MathCeilNumber, unaryop)
1895     {
1896         const Register &src = registers[instr->unaryop.src];
1897         Register &output = registers[instr->unaryop.output];
1898         if (src.isUndefined())
1899             output.setUndefined();
1900         else if (src.isNaN())
1901             // output should be an int, but still NaN
1902             output.setNaNType();
1903         else if (src.isInf())
1904             // output should be an int, but still Inf
1905             output.setInfType(signBitSet(src.getnumber()));
1906         else if (src.isNegativeZero())
1907             // output should be an int, but still -0
1908             output.setNegativeZeroType();
1909         else {
1910             // Ensure that we preserve the sign bit (Math.ceil(-0) -> -0)
1911             const double input = src.getnumber();
1912             const int ceiled = qCeil(input);
1913             if (ceiled == 0 && signBitSet(input)) {
1914                 output.setNegativeZeroType();
1915             } else {
1916                 output.setint(ceiled);
1917             }
1918         }
1919     }
1920     QML_V4_END_INSTR(MathCeilNumber, unaryop)
1921
1922     QML_V4_BEGIN_INSTR(MathPINumber, unaryop)
1923     {
1924         static const double qmlPI = 2.0 * qAsin(1.0);
1925         Register &output = registers[instr->unaryop.output];
1926         output.setnumber(qmlPI);
1927     }
1928     QML_V4_END_INSTR(MathPINumber, unaryop)
1929
1930     QML_V4_BEGIN_INSTR(LoadNull, null_value)
1931         registers[instr->null_value.reg].setNull();
1932     QML_V4_END_INSTR(LoadNull, null_value)
1933
1934     QML_V4_BEGIN_INSTR(LoadNumber, number_value)
1935         registers[instr->number_value.reg].setnumber(instr->number_value.value);
1936     QML_V4_END_INSTR(LoadNumber, number_value)
1937
1938     QML_V4_BEGIN_INSTR(LoadInt, int_value)
1939         registers[instr->int_value.reg].setint(instr->int_value.value);
1940     QML_V4_END_INSTR(LoadInt, int_value)
1941
1942     QML_V4_BEGIN_INSTR(LoadBool, bool_value)
1943         registers[instr->bool_value.reg].setbool(instr->bool_value.value);
1944     QML_V4_END_INSTR(LoadBool, bool_value)
1945
1946     QML_V4_BEGIN_INSTR(LoadString, string_value)
1947     {
1948         Register &output = registers[instr->string_value.reg];
1949         QChar *string = (QChar *)(data + instr->string_value.offset);
1950         new (output.getstringptr()) QString(string, instr->string_value.length);
1951         STRING_REGISTER(instr->string_value.reg);
1952     }
1953     QML_V4_END_INSTR(LoadString, string_value)
1954
1955     QML_V4_BEGIN_INSTR(EnableV4Test, string_value)
1956     {
1957         testBindingSource = new QString((QChar *)(data + instr->string_value.offset), instr->string_value.length);
1958         testBinding = true;
1959     }
1960     QML_V4_END_INSTR(String, string_value)
1961
1962     QML_V4_BEGIN_INSTR(BitAndInt, binaryop)
1963     {
1964         registers[instr->binaryop.output].setint(registers[instr->binaryop.left].getint() &
1965                                                  registers[instr->binaryop.right].getint());
1966     }
1967     QML_V4_END_INSTR(BitAndInt, binaryop)
1968
1969     QML_V4_BEGIN_INSTR(BitOrInt, binaryop)
1970     {
1971         registers[instr->binaryop.output].setint(registers[instr->binaryop.left].getint() |
1972                                                  registers[instr->binaryop.right].getint());
1973     }
1974     QML_V4_END_INSTR(BitAndInt, binaryop)
1975
1976     QML_V4_BEGIN_INSTR(BitXorInt, binaryop)
1977     {
1978         registers[instr->binaryop.output].setint(registers[instr->binaryop.left].getint() ^
1979                                                  registers[instr->binaryop.right].getint());
1980     }
1981     QML_V4_END_INSTR(BitXorInt, binaryop)
1982
1983     QML_V4_BEGIN_INSTR(AddNumber, binaryop)
1984     {
1985         registers[instr->binaryop.output].setnumber(registers[instr->binaryop.left].getnumber() +
1986                                                    registers[instr->binaryop.right].getnumber());
1987     }
1988     QML_V4_END_INSTR(AddNumber, binaryop)
1989
1990     QML_V4_BEGIN_INSTR(AddString, binaryop)
1991     {
1992         QString &string = *registers[instr->binaryop.output].getstringptr();
1993         if (instr->binaryop.output == instr->binaryop.left) {
1994             string += registers[instr->binaryop.right].getstringptr();
1995         } else {
1996             string = *registers[instr->binaryop.left].getstringptr() +
1997                      *registers[instr->binaryop.right].getstringptr();
1998         }
1999     }
2000     QML_V4_END_INSTR(AddString, binaryop)
2001
2002     QML_V4_BEGIN_INSTR(SubNumber, binaryop)
2003     {
2004         registers[instr->binaryop.output].setnumber(registers[instr->binaryop.left].getnumber() -
2005                                                    registers[instr->binaryop.right].getnumber());
2006     }
2007     QML_V4_END_INSTR(SubNumber, binaryop)
2008
2009     QML_V4_BEGIN_INSTR(MulNumber, binaryop)
2010     {
2011         registers[instr->binaryop.output].setnumber(registers[instr->binaryop.left].getnumber() *
2012                                                    registers[instr->binaryop.right].getnumber());
2013     }
2014     QML_V4_END_INSTR(MulNumber, binaryop)
2015
2016     QML_V4_BEGIN_INSTR(DivNumber, binaryop)
2017     {
2018         registers[instr->binaryop.output].setnumber(registers[instr->binaryop.left].getnumber() /
2019                                                    registers[instr->binaryop.right].getnumber());
2020     }
2021     QML_V4_END_INSTR(DivNumber, binaryop)
2022
2023     QML_V4_BEGIN_INSTR(ModNumber, binaryop)
2024     {
2025         Register &target = registers[instr->binaryop.output];
2026         const Register &left = registers[instr->binaryop.left];
2027         const Register &right = registers[instr->binaryop.right];
2028         target.setnumber(::fmod(left.getnumber(), right.getnumber()));
2029     }
2030     QML_V4_END_INSTR(ModInt, binaryop)
2031
2032     QML_V4_BEGIN_INSTR(LShiftInt, binaryop)
2033     {
2034         registers[instr->binaryop.output].setint(registers[instr->binaryop.left].getint() <<
2035                                                  registers[instr->binaryop.right].getint());
2036     }
2037     QML_V4_END_INSTR(LShiftInt, binaryop)
2038
2039     QML_V4_BEGIN_INSTR(RShiftInt, binaryop)
2040     {
2041         registers[instr->binaryop.output].setint(registers[instr->binaryop.left].getint() >>
2042                                                  registers[instr->binaryop.right].getint());
2043     }
2044     QML_V4_END_INSTR(RShiftInt, binaryop)
2045
2046     QML_V4_BEGIN_INSTR(URShiftInt, binaryop)
2047     {
2048         registers[instr->binaryop.output].setint((unsigned)registers[instr->binaryop.left].getint() >>
2049                                                  registers[instr->binaryop.right].getint());
2050     }
2051     QML_V4_END_INSTR(URShiftInt, binaryop)
2052
2053     QML_V4_BEGIN_INSTR(GtNumber, binaryop)
2054     {
2055         registers[instr->binaryop.output].setbool(registers[instr->binaryop.left].getnumber() >
2056                                                   registers[instr->binaryop.right].getnumber());
2057     }
2058     QML_V4_END_INSTR(GtNumber, binaryop)
2059
2060     QML_V4_BEGIN_INSTR(LtNumber, binaryop)
2061     {
2062         registers[instr->binaryop.output].setbool(registers[instr->binaryop.left].getnumber() <
2063                                                   registers[instr->binaryop.right].getnumber());
2064     }
2065     QML_V4_END_INSTR(LtNumber, binaryop)
2066
2067     QML_V4_BEGIN_INSTR(GeNumber, binaryop)
2068     {
2069         registers[instr->binaryop.output].setbool(registers[instr->binaryop.left].getnumber() >=
2070                                                   registers[instr->binaryop.right].getnumber());
2071     }
2072     QML_V4_END_INSTR(GeNumber, binaryop)
2073
2074     QML_V4_BEGIN_INSTR(LeNumber, binaryop)
2075     {
2076         registers[instr->binaryop.output].setbool(registers[instr->binaryop.left].getnumber() <=
2077                                                   registers[instr->binaryop.right].getnumber());
2078     }
2079     QML_V4_END_INSTR(LeNumber, binaryop)
2080
2081     QML_V4_BEGIN_INSTR(EqualNumber, binaryop)
2082     {
2083         registers[instr->binaryop.output].setbool(registers[instr->binaryop.left].getnumber() ==
2084                                                   registers[instr->binaryop.right].getnumber());
2085     }
2086     QML_V4_END_INSTR(EqualNumber, binaryop)
2087
2088     QML_V4_BEGIN_INSTR(NotEqualNumber, binaryop)
2089     {
2090         registers[instr->binaryop.output].setbool(registers[instr->binaryop.left].getnumber() !=
2091                                                   registers[instr->binaryop.right].getnumber());
2092     }
2093     QML_V4_END_INSTR(NotEqualNumber, binaryop)
2094
2095     QML_V4_BEGIN_INSTR(StrictEqualNumber, binaryop)
2096     {
2097         registers[instr->binaryop.output].setbool(registers[instr->binaryop.left].getnumber() ==
2098                                                   registers[instr->binaryop.right].getnumber());
2099     }
2100     QML_V4_END_INSTR(StrictEqualNumber, binaryop)
2101
2102     QML_V4_BEGIN_INSTR(StrictNotEqualNumber, binaryop)
2103     {
2104         registers[instr->binaryop.output].setbool(registers[instr->binaryop.left].getnumber() !=
2105                                                   registers[instr->binaryop.right].getnumber());
2106     }
2107     QML_V4_END_INSTR(StrictNotEqualNumber, binaryop)
2108
2109     QML_V4_BEGIN_INSTR(GtString, binaryop)
2110     {
2111         const QString &a = *registers[instr->binaryop.left].getstringptr();
2112         const QString &b = *registers[instr->binaryop.right].getstringptr();
2113         bool result = a > b;
2114         if (instr->binaryop.left == instr->binaryop.output) {
2115             registers[instr->binaryop.output].cleanupString();
2116             MARK_CLEAN_REGISTER(instr->binaryop.output);
2117         }
2118         registers[instr->binaryop.output].setbool(result);
2119     }
2120     QML_V4_END_INSTR(GtString, binaryop)
2121
2122     QML_V4_BEGIN_INSTR(LtString, binaryop)
2123     {
2124         const QString &a = *registers[instr->binaryop.left].getstringptr();
2125         const QString &b = *registers[instr->binaryop.right].getstringptr();
2126         bool result = a < b;
2127         if (instr->binaryop.left == instr->binaryop.output) {
2128             registers[instr->binaryop.output].cleanupString();
2129             MARK_CLEAN_REGISTER(instr->binaryop.output);
2130         }
2131         registers[instr->binaryop.output].setbool(result);
2132     }
2133     QML_V4_END_INSTR(LtString, binaryop)
2134
2135     QML_V4_BEGIN_INSTR(GeString, binaryop)
2136     {
2137         const QString &a = *registers[instr->binaryop.left].getstringptr();
2138         const QString &b = *registers[instr->binaryop.right].getstringptr();
2139         bool result = a >= b;
2140         if (instr->binaryop.left == instr->binaryop.output) {
2141             registers[instr->binaryop.output].cleanupString();
2142             MARK_CLEAN_REGISTER(instr->binaryop.output);
2143         }
2144         registers[instr->binaryop.output].setbool(result);
2145     }
2146     QML_V4_END_INSTR(GeString, binaryop)
2147
2148     QML_V4_BEGIN_INSTR(LeString, binaryop)
2149     {
2150         const QString &a = *registers[instr->binaryop.left].getstringptr();
2151         const QString &b = *registers[instr->binaryop.right].getstringptr();
2152         bool result = a <= b;
2153         if (instr->binaryop.left == instr->binaryop.output) {
2154             registers[instr->binaryop.output].cleanupString();
2155             MARK_CLEAN_REGISTER(instr->binaryop.output);
2156         }
2157         registers[instr->binaryop.output].setbool(result);
2158     }
2159     QML_V4_END_INSTR(LeString, binaryop)
2160
2161     QML_V4_BEGIN_INSTR(EqualString, binaryop)
2162     {
2163         const QString &a = *registers[instr->binaryop.left].getstringptr();
2164         const QString &b = *registers[instr->binaryop.right].getstringptr();
2165         bool result = a == b;
2166         if (instr->binaryop.left == instr->binaryop.output) {
2167             registers[instr->binaryop.output].cleanupString();
2168             MARK_CLEAN_REGISTER(instr->binaryop.output);
2169         }
2170         registers[instr->binaryop.output].setbool(result);
2171     }
2172     QML_V4_END_INSTR(EqualString, binaryop)
2173
2174     QML_V4_BEGIN_INSTR(NotEqualString, binaryop)
2175     {
2176         const QString &a = *registers[instr->binaryop.left].getstringptr();
2177         const QString &b = *registers[instr->binaryop.right].getstringptr();
2178         bool result = a != b;
2179         if (instr->binaryop.left == instr->binaryop.output) {
2180             registers[instr->binaryop.output].cleanupString();
2181             MARK_CLEAN_REGISTER(instr->binaryop.output);
2182         }
2183         registers[instr->binaryop.output].setbool(result);
2184     }
2185     QML_V4_END_INSTR(NotEqualString, binaryop)
2186
2187     QML_V4_BEGIN_INSTR(StrictEqualString, binaryop)
2188     {
2189         const QString &a = *registers[instr->binaryop.left].getstringptr();
2190         const QString &b = *registers[instr->binaryop.right].getstringptr();
2191         bool result = a == b;
2192         if (instr->binaryop.left == instr->binaryop.output) {
2193             registers[instr->binaryop.output].cleanupString();
2194             MARK_CLEAN_REGISTER(instr->binaryop.output);
2195         }
2196         registers[instr->binaryop.output].setbool(result);
2197     }
2198     QML_V4_END_INSTR(StrictEqualString, binaryop)
2199
2200     QML_V4_BEGIN_INSTR(StrictNotEqualString, binaryop)
2201     {
2202         const QString &a = *registers[instr->binaryop.left].getstringptr();
2203         const QString &b = *registers[instr->binaryop.right].getstringptr();
2204         bool result = a != b;
2205         if (instr->binaryop.left == instr->binaryop.output) {
2206             registers[instr->binaryop.output].cleanupString();
2207             MARK_CLEAN_REGISTER(instr->binaryop.output);
2208         }
2209         registers[instr->binaryop.output].setbool(result);
2210     }
2211     QML_V4_END_INSTR(StrictNotEqualString, binaryop)
2212
2213     QML_V4_BEGIN_INSTR(EqualObject, binaryop)
2214     {
2215         const Register &left = registers[instr->binaryop.left];
2216         const Register &right = registers[instr->binaryop.right];
2217         QObject *leftobj = (left.gettype() == NullType) ? 0 : left.getQObject();
2218         QObject *rightobj = (right.gettype() == NullType) ? 0 : right.getQObject();
2219         registers[instr->binaryop.output].setbool(leftobj == rightobj);
2220     }
2221     QML_V4_END_INSTR(EqualObject, binaryop)
2222
2223     QML_V4_BEGIN_INSTR(NotEqualObject, binaryop)
2224     {
2225         const Register &left = registers[instr->binaryop.left];
2226         const Register &right = registers[instr->binaryop.right];
2227         QObject *leftobj = (left.gettype() == NullType) ? 0 : left.getQObject();
2228         QObject *rightobj = (right.gettype() == NullType) ? 0 : right.getQObject();
2229         registers[instr->binaryop.output].setbool(leftobj != rightobj);
2230     }
2231     QML_V4_END_INSTR(NotEqualObject, binaryop)
2232
2233     QML_V4_BEGIN_INSTR(StrictEqualObject, binaryop)
2234     {
2235         const Register &left = registers[instr->binaryop.left];
2236         const Register &right = registers[instr->binaryop.right];
2237         QObject *leftobj = (left.gettype() == NullType) ? 0 : left.getQObject();
2238         QObject *rightobj = (right.gettype() == NullType) ? 0 : right.getQObject();
2239         registers[instr->binaryop.output].setbool(leftobj == rightobj);
2240     }
2241     QML_V4_END_INSTR(StrictEqualObject, binaryop)
2242
2243     QML_V4_BEGIN_INSTR(StrictNotEqualObject, binaryop)
2244     {
2245         const Register &left = registers[instr->binaryop.left];
2246         const Register &right = registers[instr->binaryop.right];
2247         QObject *leftobj = (left.gettype() == NullType) ? 0 : left.getQObject();
2248         QObject *rightobj = (right.gettype() == NullType) ? 0 : right.getQObject();
2249         registers[instr->binaryop.output].setbool(leftobj != rightobj);
2250     }
2251     QML_V4_END_INSTR(StrictNotEqualObject, binaryop)
2252
2253     QML_V4_BEGIN_INSTR(MathMaxNumber, binaryop)
2254     {
2255         const Register &left = registers[instr->binaryop.left];
2256         const Register &right = registers[instr->binaryop.right];
2257         Register &output = registers[instr->binaryop.output];
2258         if (left.isUndefined() || right.isUndefined()) {
2259             output.setUndefined();
2260         } else {
2261             const double lhs = left.getnumber();
2262             const double rhs = right.getnumber();
2263             double result(lhs);
2264             if (lhs == rhs) {
2265                 // If these are both zero, +0 is greater than -0
2266                 if (signBitSet(lhs) && !signBitSet(rhs))
2267                     result = rhs;
2268             } else {
2269                 result = qMax(lhs, rhs);
2270             }
2271             output.setnumber(result);
2272         }
2273     }
2274     QML_V4_END_INSTR(MathMaxNumber, binaryop)
2275
2276     QML_V4_BEGIN_INSTR(MathMinNumber, binaryop)
2277     {
2278         const Register &left = registers[instr->binaryop.left];
2279         const Register &right = registers[instr->binaryop.right];
2280         Register &output = registers[instr->binaryop.output];
2281         if (left.isUndefined() || right.isUndefined()) {
2282             output.setUndefined();
2283         } else {
2284             const double lhs = left.getnumber();
2285             const double rhs = right.getnumber();
2286             double result(lhs);
2287             if (lhs == rhs) {
2288                 // If these are both zero, -0 is lesser than +0
2289                 if (!signBitSet(lhs) && signBitSet(rhs))
2290                     result = rhs;
2291             } else {
2292                 result = qMin(lhs, rhs);
2293             }
2294             output.setnumber(result);
2295         }
2296     }
2297     QML_V4_END_INSTR(MathMinNumber, binaryop)
2298
2299     QML_V4_BEGIN_INSTR(NewString, construct)
2300     {
2301         Register &output = registers[instr->construct.reg];
2302         new (output.getstringptr()) QString;
2303         STRING_REGISTER(instr->construct.reg);
2304     }
2305     QML_V4_END_INSTR(NewString, construct)
2306
2307     QML_V4_BEGIN_INSTR(NewUrl, construct)
2308     {
2309         Register &output = registers[instr->construct.reg];
2310         new (output.geturlptr()) QUrl;
2311         URL_REGISTER(instr->construct.reg);
2312     }
2313     QML_V4_END_INSTR(NewUrl, construct)
2314
2315     QML_V4_BEGIN_INSTR(Fetch, fetch)
2316     {
2317         Register &reg = registers[instr->fetch.reg];
2318
2319         if (reg.isUndefined())
2320             THROW_EXCEPTION(instr->fetch.exceptionId);
2321
2322         QObject *object = reg.getQObject();
2323         if (!object) {
2324             THROW_EXCEPTION(instr->fetch.exceptionId);
2325         } else {
2326             if (bindingInvalidated(invalidated, object, context, instr->fetch.index))
2327                 goto programExit;
2328
2329             const Register::Type valueType = (Register::Type)instr->fetch.valueType;
2330             reg.init(valueType);
2331             if (instr->fetch.valueType >= FirstCleanupType)
2332                 MARK_REGISTER(instr->fetch.reg);
2333
2334             QQmlData::flushPendingBinding(object, instr->fetch.index);
2335
2336             void *argv[] = { reg.typeDataPtr(), 0 };
2337             QMetaObject::metacall(object, QMetaObject::ReadProperty, instr->fetch.index, argv);
2338             if (valueType == FloatType) {
2339                 // promote floats
2340                 const double v = reg.getfloat();
2341                 reg.setnumber(v);
2342             }
2343
2344             if (instr->fetch.subIndex != static_cast<quint32>(-1))
2345                 subscribe(object, instr->fetch.subIndex, instr->fetch.subOffset, context->engine);
2346
2347         }
2348     }
2349     QML_V4_END_INSTR(Fetch, fetch)
2350
2351     QML_V4_BEGIN_INSTR(TestV4Store, storetest)
2352     {
2353         Register &data = registers[instr->storetest.reg];
2354         testBindingResult(*testBindingSource, bindingLine, bindingColumn, context,
2355                           scope, data, instr->storetest.regType);
2356     }
2357     QML_V4_END_INSTR(TestV4Store, storetest)
2358
2359     QML_V4_BEGIN_INSTR(Store, store)
2360     {
2361         Register &data = registers[instr->store.reg];
2362
2363         if (data.isUndefined())
2364             THROW_EXCEPTION_STR(instr->store.exceptionId, QLatin1String("Unable to assign undefined value"));
2365
2366         if (data.gettype() == QObjectStarType) {
2367             if (QObject *dataObject = data.getQObject()) {
2368                 QQmlMetaObject dataMo(dataObject);
2369
2370                 QQmlEnginePrivate *ep = QQmlEnginePrivate::get(context->engine);
2371
2372                 QQmlMetaObject receiverMo;
2373
2374                 if (QQmlData::get(output, false) && QQmlData::get(output, false)->propertyCache) {
2375                     QQmlPropertyData *receiver =
2376                         QQmlData::get(output, false)->propertyCache->property(instr->store.index);
2377                     receiverMo = ep->rawMetaObjectForType(receiver->propType);
2378                 } else {
2379                     QMetaProperty receiver = output->metaObject()->property(instr->store.index);
2380                     receiverMo = ep->rawMetaObjectForType(receiver.userType());
2381                 }
2382
2383                 // Verify that these types are compatible
2384                 if (!QQmlMetaObject::canConvert(dataMo, receiverMo)) {
2385                     THROW_EXCEPTION_STR(instr->store.exceptionId, QLatin1String("Unable to assign ") +
2386                                                                   QLatin1String(dataMo.className()) +
2387                                                                   QLatin1String(" to ") +
2388                                                                   QLatin1String(receiverMo.className()));
2389                 }
2390             }
2391         }
2392
2393         if (instr->store.valueType == FloatType) {
2394             // cast numbers to floats
2395             const float v = (float) data.getnumber();
2396             data.setfloat(v);
2397         }
2398
2399         if (data.gettype() == V8HandleType) {
2400             // This property must be a VME var property
2401             QQmlVMEMetaObject *vmemo = QQmlVMEMetaObject::get(output);
2402             Q_ASSERT(vmemo);
2403             vmemo->setVMEProperty(instr->store.index, *data.gethandleptr());
2404         } else {
2405             int status = -1;
2406             void *argv[] = { data.typeDataPtr(), 0, &status, &storeFlags };
2407             QMetaObject::metacall(output, QMetaObject::WriteProperty,
2408                                   instr->store.index, argv);
2409         }
2410
2411         goto programExit;
2412     }
2413     QML_V4_END_INSTR(Store, store)
2414
2415     QML_V4_BEGIN_INSTR(Copy, copy)
2416         registers[instr->copy.reg].copy(registers[instr->copy.src]);
2417         if (registers[instr->copy.reg].gettype() >= FirstCleanupType)
2418             MARK_REGISTER(instr->copy.reg);
2419     QML_V4_END_INSTR(Copy, copy)
2420
2421     QML_V4_BEGIN_INSTR(Jump, jump)
2422         if (instr->jump.reg == -1 || !registers[instr->jump.reg].getbool())
2423             code += instr->jump.count;
2424     QML_V4_END_INSTR(Jump, jump)
2425
2426     QML_V4_BEGIN_INSTR(BranchTrue, branchop)
2427         if (registers[instr->branchop.reg].getbool())
2428             code += instr->branchop.offset;
2429     QML_V4_END_INSTR(BranchTrue, branchop)
2430
2431     QML_V4_BEGIN_INSTR(BranchFalse, branchop)
2432         if (! registers[instr->branchop.reg].getbool())
2433             code += instr->branchop.offset;
2434     QML_V4_END_INSTR(BranchFalse, branchop)
2435
2436     QML_V4_BEGIN_INSTR(Branch, branchop)
2437         code += instr->branchop.offset;
2438     QML_V4_END_INSTR(Branch, branchop)
2439
2440     QML_V4_BEGIN_INSTR(Block, blockop)
2441         executedBlocks |= instr->blockop.block;
2442     QML_V4_END_INSTR(Block, blockop)
2443
2444     QML_V4_BEGIN_INSTR(CleanupRegister, cleanup)
2445         registers[instr->cleanup.reg].cleanup();
2446     QML_V4_END_INSTR(CleanupRegister, cleanup)
2447
2448     QML_V4_BEGIN_INSTR(Throw, throwop)
2449         THROW_VALUE_EXCEPTION_STR(instr->throwop.exceptionId, *registers[instr->throwop.message].getstringptr());
2450     QML_V4_END_INSTR(Throw, throwop)
2451
2452 #ifdef QML_THREADED_INTERPRETER
2453     // nothing to do
2454 #else
2455     default:
2456         qFatal("QV4: Unknown instruction %d encountered.", instr->common.type);
2457         break;
2458     } // switch
2459
2460     } // while
2461 #endif
2462
2463     Q_ASSERT(!"Unreachable code reached");
2464
2465 programExit:
2466 exceptionExit:
2467     delete testBindingSource;
2468
2469     int reg = 0;
2470     while (cleanupRegisterMask) {
2471         if (cleanupRegisterMask & 0x1)
2472             registers[reg].cleanup();
2473
2474         reg++;
2475         cleanupRegisterMask >>= 1;
2476     }
2477 }
2478
2479 QT_END_NAMESPACE