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