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