1 /****************************************************************************
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
6 ** This file is part of the QtQml module of the Qt Toolkit.
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.
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.
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.
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.
40 ****************************************************************************/
42 // #define REGISTER_CLEANUP_DEBUG
44 #include "qv4bindings_p.h"
45 #include "qv4program_p.h"
46 #include "qv4compiler_p.h"
47 #include "qv4compiler_p_p.h"
49 #include <private/qqmlglobal_p.h>
51 #include <private/qv8_p.h>
52 #include <private/qjsconverter_p.h>
53 #include <private/qjsconverter_impl_p.h>
54 #include <private/qjsvalue_impl_p.h>
55 #include <private/qjsvalueiterator_impl_p.h>
56 #include <private/qv8engine_impl_p.h>
58 #include <private/qqmlaccessors_p.h>
59 #include <private/qqmlprofilerservice_p.h>
60 #include <private/qqmlmetatype_p.h>
61 #include <private/qqmltrace_p.h>
62 #include <private/qqmlstringconverters_p.h>
63 #include <private/qqmlproperty_p.h>
64 #include <private/qqmlvmemetaobject_p.h>
66 #include <QtQml/qqmlinfo.h>
67 #include <QtCore/qnumeric.h>
68 #include <QtCore/qmath.h>
69 #include <math.h> // ::fmod
71 Q_DECLARE_METATYPE(QJSValue)
75 using namespace QQmlJS;
77 QQmlAbstractBinding::VTable QV4Bindings_Binding_vtable = {
78 QV4Bindings::Binding::destroy,
79 QQmlAbstractBinding::default_expression,
80 QV4Bindings::Binding::propertyIndex,
81 QV4Bindings::Binding::object,
82 QV4Bindings::Binding::setEnabled,
83 QV4Bindings::Binding::update,
84 QV4Bindings::Binding::retargetBinding
89 // The highest bit is the sign bit, in any endianness
90 static const quint64 doubleSignMask = (quint64(0x1) << 63);
92 inline bool signBitSet(const double &v)
94 union { double d; quint64 u; } u;
96 return (u.u & doubleSignMask);
99 inline double setSignBit(const double &v, bool b = true)
101 union { double d; quint64 u; } u;
105 u.u |= doubleSignMask;
107 u.u &= ~doubleSignMask;
112 inline double clearSignBit(const double &v, bool b = true)
114 return setSignBit(v, !b);
118 typedef QQmlRegisterType Type;
120 enum SpecialNumericValue {
122 PositiveInfinity = 2,
123 NegativeInfinity = 3,
127 inline void setUndefined() { dataType = UndefinedType; }
128 inline bool isUndefined() const { return dataType == UndefinedType; }
130 inline void setNull() { dataType = NullType; }
132 inline void setNaN() { setnumber(qSNaN()); }
133 inline void setNaNType() { dataType = SpecialNumericType; intValue = NotANumber; } // non-numeric representation of NaN
134 inline bool isNaN() const { return (((dataType == SpecialNumericType) && (intValue == NotANumber)) ||
135 ((dataType == NumberType) && qIsNaN(numberValue))); }
137 inline void setInf(bool negative) { setnumber(setSignBit(qInf(), negative)); }
138 inline void setInfType(bool negative) { dataType = SpecialNumericType; intValue = (negative ? NegativeInfinity : PositiveInfinity); } // non-numeric representation of Inf
139 inline bool isInf() const { return (((dataType == SpecialNumericType) && ((intValue == NegativeInfinity) || (intValue == PositiveInfinity))) ||
140 ((dataType == NumberType) && qIsInf(numberValue))); }
142 inline void setNegativeZero() { setnumber(setSignBit(0)); }
143 inline void setNegativeZeroType() { dataType = SpecialNumericType; intValue = NegativeZero; } // non-numeric representation of -0
144 inline bool isNegativeZero() const { return (((dataType == SpecialNumericType) && (intValue == NegativeZero)) ||
145 ((dataType == NumberType) && (numberValue == 0) && signBitSet(numberValue))); }
147 inline void setQObject(QObject *o) { qobjectValue = o; dataType = QObjectStarType; }
148 inline QObject *getQObject() const { return qobjectValue; }
150 inline void setnumber(double v) { numberValue = v; dataType = NumberType; }
151 inline double getnumber() const { return numberValue; }
152 inline double &getnumberref() { return numberValue; }
154 inline void setfloat(float v) { floatValue = v; dataType = FloatType; }
155 inline float getfloat() const { return floatValue; }
156 inline float &getfloatref() { return floatValue; }
158 inline void setint(int v) { intValue = v; dataType = IntType; }
159 inline int getint() const { return intValue; }
160 inline int &getintref() { return intValue; }
162 inline void setbool(bool v) { boolValue = v; dataType = BoolType; }
163 inline bool getbool() const { return boolValue; }
164 inline bool &getboolref() { return boolValue; }
166 inline QVariant *getvariantptr() { return reinterpret_cast<QVariant *>(typeDataPtr()); }
167 inline QString *getstringptr() { return reinterpret_cast<QString *>(typeDataPtr()); }
168 inline QUrl *geturlptr() { return reinterpret_cast<QUrl *>(typeDataPtr()); }
169 inline v8::Handle<v8::Value> *gethandleptr() { return reinterpret_cast<v8::Handle<v8::Value> *>(typeDataPtr()); }
170 inline QJSValue *getjsvalueptr() { return reinterpret_cast<QJSValue *>(typeDataPtr()); }
172 inline const QVariant *getvariantptr() const { return reinterpret_cast<const QVariant *>(typeDataPtr()); }
173 inline const QString *getstringptr() const { return reinterpret_cast<const QString *>(typeDataPtr()); }
174 inline const QUrl *geturlptr() const { return reinterpret_cast<const QUrl *>(typeDataPtr()); }
175 inline const v8::Handle<v8::Value> *gethandleptr() const { return reinterpret_cast<const v8::Handle<v8::Value> *>(typeDataPtr()); }
176 inline const QJSValue *getjsvalueptr() const { return reinterpret_cast<const QJSValue *>(typeDataPtr()); }
178 size_t dataSize() { return sizeof(data); }
179 inline void *typeDataPtr() { return (void *)&data; }
180 inline void *typeMemory() { return (void *)data; }
181 inline const void *typeDataPtr() const { return (void *)&data; }
182 inline const void *typeMemory() const { return (void *)data; }
184 inline Type gettype() const { return dataType; }
185 inline void settype(Type t) { dataType = t; }
187 Type dataType; // Type of data
189 QObject *qobjectValue;
194 void *data[sizeof(QVariant)];
195 qint64 q_for_alignment_1;
196 double q_for_alignment_2;
199 inline void cleanup();
200 inline void cleanupString();
201 inline void cleanupUrl();
202 inline void cleanupColor();
203 inline void cleanupVariant();
204 inline void cleanupHandle();
205 inline void cleanupJSValue();
207 inline void copy(const Register &other);
208 inline void init(Type type);
209 #ifdef REGISTER_CLEANUP_DEBUG
215 if (dataType >= FirstCleanupType)
216 qWarning("Register leaked of type %d", dataType);
220 template <typename T>
221 inline static void copyConstructPointee(T *p, const T *other)
226 template <typename T>
227 inline static void defaultConstructPointee(T *p)
232 template <typename T>
233 inline static void destroyPointee(T *p)
239 void Register::cleanup()
241 if (dataType >= FirstCleanupType) {
242 if (dataType == QStringType) {
243 destroyPointee(getstringptr());
244 } else if (dataType == QUrlType) {
245 destroyPointee(geturlptr());
246 } else if (dataType == QColorType) {
247 QQml_valueTypeProvider()->destroyValueType(QMetaType::QColor, typeDataPtr(), dataSize());
248 } else if (dataType == QVariantType) {
249 destroyPointee(getvariantptr());
250 } else if (dataType == qMetaTypeId<v8::Handle<v8::Value> >()) {
251 destroyPointee(gethandleptr());
252 } else if (dataType == qMetaTypeId<QJSValue>()) {
253 destroyPointee(getjsvalueptr());
259 void Register::cleanupString()
261 destroyPointee(getstringptr());
265 void Register::cleanupUrl()
267 destroyPointee(geturlptr());
271 void Register::cleanupColor()
273 QQml_valueTypeProvider()->destroyValueType(QMetaType::QColor, typeDataPtr(), dataSize());
277 void Register::cleanupVariant()
279 destroyPointee(getvariantptr());
283 void Register::cleanupHandle()
285 destroyPointee(gethandleptr());
289 void Register::cleanupJSValue()
291 destroyPointee(getjsvalueptr());
295 void Register::copy(const Register &other)
298 if (other.dataType >= FirstCleanupType) {
299 if (other.dataType == QStringType)
300 copyConstructPointee(getstringptr(), other.getstringptr());
301 else if (other.dataType == QUrlType)
302 copyConstructPointee(geturlptr(), other.geturlptr());
303 else if (other.dataType == QColorType)
304 QQml_valueTypeProvider()->copyValueType(QMetaType::QColor, other.typeDataPtr(), typeDataPtr(), dataSize());
305 else if (other.dataType == QVariantType)
306 copyConstructPointee(getvariantptr(), other.getvariantptr());
307 else if (other.dataType == qMetaTypeId<v8::Handle<v8::Value> >())
308 copyConstructPointee(gethandleptr(), other.gethandleptr());
309 else if (other.dataType == qMetaTypeId<QJSValue>())
310 copyConstructPointee(getjsvalueptr(), other.getjsvalueptr());
314 void Register::init(Type type)
317 if (dataType >= FirstCleanupType) {
318 if (dataType == QStringType)
319 defaultConstructPointee(getstringptr());
320 else if (dataType == QUrlType)
321 defaultConstructPointee(geturlptr());
322 else if (dataType == QColorType)
323 QQml_valueTypeProvider()->initValueType(QMetaType::QColor, typeDataPtr(), dataSize());
324 else if (dataType == QVariantType)
325 defaultConstructPointee(getvariantptr());
326 else if (dataType == qMetaTypeId<v8::Handle<v8::Value> >())
327 defaultConstructPointee(gethandleptr());
328 else if (dataType == qMetaTypeId<QJSValue>())
329 defaultConstructPointee(getjsvalueptr());
333 } // end of anonymous namespace
335 QV4Bindings::QV4Bindings(const char *programData, QQmlContextData *context)
336 : subscriptions(0), program(0), bindings(0)
338 program = (QV4Program *)programData;
340 subscriptions = new Subscription[program->subscriptions];
341 bindings = new Binding[program->bindings];
343 QQmlAbstractExpression::setContext(context);
347 QV4Bindings::~QV4Bindings()
349 delete [] bindings; bindings = 0;
350 delete [] subscriptions; subscriptions = 0;
353 QQmlAbstractBinding *QV4Bindings::configBinding(QObject *target, QObject *scope,
354 const QQmlInstruction::instr_assignV4Binding *i)
356 Binding *rv = bindings + i->value;
363 addref(); // This is decremented in Binding::destroy()
368 void QV4Bindings::Binding::setEnabled(QQmlAbstractBinding *_This,
369 bool e, QQmlPropertyPrivate::WriteFlags flags)
371 QV4Bindings::Binding *This = static_cast<QV4Bindings::Binding *>(_This);
373 if (This->enabledFlag() != e) {
374 This->setEnabledFlag(e);
376 if (e) update(_This, flags);
380 void QV4Bindings::Binding::update(QQmlAbstractBinding *_This, QQmlPropertyPrivate::WriteFlags flags)
382 QV4Bindings::Binding *This = static_cast<QV4Bindings::Binding *>(_This);
383 This->parent->run(This, flags);
386 void QV4Bindings::Binding::destroy(QQmlAbstractBinding *_This, QQmlAbstractBinding::DestroyMode mode)
388 QV4Bindings::Binding *This = static_cast<QV4Bindings::Binding *>(_This);
390 if (mode == QQmlAbstractBinding::DisconnectBinding)
393 This->setEnabledFlag(false);
394 This->removeFromObject();
397 This->parent->release();
400 int QV4Bindings::Binding::propertyIndex(const QQmlAbstractBinding *_This)
402 const QV4Bindings::Binding *This = static_cast<const QV4Bindings::Binding *>(_This);
404 if (This->target.hasValue()) return This->target.constValue()->targetProperty;
405 else return This->instruction->property;
408 QObject *QV4Bindings::Binding::object(const QQmlAbstractBinding *_This)
410 const QV4Bindings::Binding *This = static_cast<const QV4Bindings::Binding *>(_This);
412 if (This->target.hasValue()) return This->target.constValue()->target;
413 return *This->target;
416 void QV4Bindings::Binding::retargetBinding(QQmlAbstractBinding *_This, QObject *t, int i)
418 QV4Bindings::Binding *This = static_cast<QV4Bindings::Binding *>(_This);
420 This->target.value().target = t;
421 This->target.value().targetProperty = i;
424 void QV4Bindings::Binding::disconnect()
426 // We iterate over the signal table to find all subscriptions associated with this binding.
427 // This is slow, but disconnect() is not called in the common case, only in special cases
428 // like when the binding is overwritten.
429 QV4Program * const program = parent->program;
430 for (quint16 subIndex = 0; subIndex < program->subscriptions; subIndex++) {
431 QV4Program::BindingReferenceList * const list = program->signalTable(subIndex);
432 for (quint32 bindingIndex = 0; bindingIndex < list->count; ++bindingIndex) {
433 QV4Program::BindingReference * const bindingRef = list->bindings + bindingIndex;
434 Binding * const binding = parent->bindings + bindingRef->binding;
435 if (binding == this) {
436 Subscription * const sub = parent->subscriptions + subIndex;
438 sub->setActive(false);
446 QV4Bindings::Subscription::Subscription()
449 setCallback(QQmlNotifierEndpoint::QV4BindingsSubscription);
452 int QV4Bindings::Subscription::method() const
454 Q_ASSERT(bindings() != 0);
455 return (this - bindings()->subscriptions);
458 void QV4Bindings::Subscription::setBindings(QV4Bindings *bindings)
460 m_bindings = bindings;
463 QV4Bindings *QV4Bindings::Subscription::bindings() const
468 bool QV4Bindings::Subscription::active() const
470 return m_bindings.flag();
473 void QV4Bindings::Subscription::setActive(bool active)
475 m_bindings.setFlagValue(active);
478 void QV4BindingsSubscription_callback(QQmlNotifierEndpoint *e, void **)
480 QV4Bindings::Subscription *s = static_cast<QV4Bindings::Subscription *>(e);
481 Q_ASSERT(s->bindings());
482 s->bindings()->subscriptionNotify(s->method());
485 void QV4Bindings::subscriptionNotify(int id)
487 QV4Program::BindingReferenceList *list = program->signalTable(id);
489 for (quint32 ii = 0; ii < list->count; ++ii) {
490 QV4Program::BindingReference *bindingRef = list->bindings + ii;
492 Binding *binding = bindings + bindingRef->binding;
494 if (binding->executedBlocks & bindingRef->blockMask) {
495 run(binding, QQmlPropertyPrivate::DontRemoveBinding);
500 void QV4Bindings::run(Binding *binding, QQmlPropertyPrivate::WriteFlags flags)
502 if (!binding->enabledFlag())
505 QQmlContextData *context = QQmlAbstractExpression::context();
506 if (!context || !context->isValid())
509 // Check that the target has not been deleted
510 if (QQmlData::wasDeleted(*binding->target))
513 QQmlTrace trace("V4 Binding Update");
514 trace.addDetail("URL", context->url);
515 trace.addDetail("Line", binding->instruction->line);
516 trace.addDetail("Column", binding->instruction->column);
518 QQmlBindingProfiler prof(context->urlString, binding->instruction->line, binding->instruction->column, QQmlProfilerService::V4Binding);
520 const int propType = binding->instruction->propType;
521 const int property = binding->instruction->property;
523 if (binding->updatingFlag()) {
526 QQmlValueType *vt = QQmlValueTypeFactory::valueType(propType);
529 name = QLatin1String(binding->target->metaObject()->property(property & 0x0000FFFF).name());
530 name.append(QLatin1Char('.'));
531 name.append(QLatin1String(vt->metaObject()->property(property >> 16).name()));
533 name = QLatin1String(binding->target->metaObject()->property(property).name());
535 qmlInfo(*binding->target) << tr("Binding loop detected for property \"%1\"").arg(name);
539 int index = binding->instruction->value;
540 int fallbackIndex = binding->instruction->fallbackValue;
542 bool invalidated = false;
543 bool *inv = (fallbackIndex != -1) ? &invalidated : 0;
545 binding->setUpdatingFlag(true);
547 QQmlValueType *vt = QQmlValueTypeFactory::valueType(propType);
549 vt->read(*binding->target, property & 0x0000FFFF);
551 QObject *target = vt;
552 run(index, binding->executedBlocks, context, binding, binding->scope, target, flags, inv);
555 vt->write(*binding->target, property & 0x0000FFFF, flags);
558 QQmlData *data = QQmlData::get(*binding->target);
559 QQmlPropertyData *propertyData = (data && data->propertyCache ? data->propertyCache->property(property) : 0);
561 if (propertyData && propertyData->isVarProperty()) {
562 // We will allocate a V8 handle in this conversion/store
563 v8::HandleScope handle_scope;
564 v8::Context::Scope context_scope(QQmlEnginePrivate::get(context->engine)->v8engine()->context());
566 run(index, binding->executedBlocks, context, binding, binding->scope, *binding->target, flags, inv);
568 run(index, binding->executedBlocks, context, binding, binding->scope, *binding->target, flags, inv);
571 binding->setUpdatingFlag(false);
574 // This binding is no longer valid - fallback to V8
575 Q_ASSERT(fallbackIndex > -1);
576 QQmlAbstractBinding *b = QQmlPropertyPrivate::activateSharedBinding(context, fallbackIndex, flags);
577 Q_ASSERT(b == binding);
582 void QV4Bindings::subscribeId(QQmlContextData *p, int idIndex, int subIndex)
584 Subscription *sub = (subscriptions + subIndex);
587 if (p->idValues[idIndex]) {
588 sub->setBindings(this);
589 sub->connect(&p->idValues[idIndex].bindings);
590 sub->setActive(true);
592 sub->setActive(false);
596 void QV4Bindings::subscribe(QObject *o, int notifyIndex, int subIndex, QQmlEngine *e)
598 Subscription *sub = (subscriptions + subIndex);
599 if (sub->isConnected(o, notifyIndex))
601 sub->setBindings(this);
603 sub->connect(o, notifyIndex, e);
604 sub->setActive(true);
607 sub->setActive(false);
611 static bool testCompareVariants(const QVariant &qtscriptRaw, const QVariant &v4)
613 QVariant qtscript = qtscriptRaw;
615 if (qtscript.userType() == v4.userType()) {
616 } else if (qtscript.canConvert(v4.userType())) {
617 qtscript.convert(v4.userType());
618 } else if (qtscript.userType() == QVariant::Invalid && v4.userType() == QMetaType::QObjectStar) {
619 qtscript = qVariantFromValue<QObject *>(0);
624 int type = qtscript.userType();
626 if (type == QQmlMetaType::QQuickAnchorLineMetaTypeId()) {
627 return QQmlMetaType::QQuickAnchorLineCompare(qtscript.constData(), v4.constData());
628 } else if (type == QMetaType::Double) {
630 double la = qvariant_cast<double>(qtscript);
631 double lr = qvariant_cast<double>(v4);
633 return la == lr || (qIsNaN(la) && qIsNaN(lr));
635 } else if (type == QMetaType::Float) {
637 float la = qvariant_cast<float>(qtscript);
638 float lr = qvariant_cast<float>(v4);
640 return la == lr || (qIsNaN(la) && qIsNaN(lr));
643 return qtscript == v4;
647 QByteArray testResultToString(const QVariant &result, bool undefined)
659 static void testBindingResult(const QString &binding, quint16 line, quint16 column,
660 QQmlContextData *context, QObject *scope,
661 const Register &result, int resultType)
663 QQmlExpression expression(context->asQQmlContext(), scope, binding);
664 bool isUndefined = false;
665 QVariant value = expression.evaluate(&isUndefined);
667 bool iserror = false;
668 QByteArray qtscriptResult;
671 const int handleType = qMetaTypeId<v8::Handle<v8::Value> >();
673 if (expression.hasError()) {
675 qtscriptResult = "exception";
676 } else if ((value.userType() != resultType) &&
677 (resultType != QMetaType::QVariant) &&
678 (resultType != qMetaTypeId<QJSValue>()) &&
679 (resultType != handleType)) {
680 // Override the QMetaType conversions to make them more JS friendly.
681 if (value.userType() == QMetaType::Double && (resultType == QMetaType::QString ||
682 resultType == QMetaType::QUrl)) {
683 // number to string-like conversion.
684 value = QVariant::fromValue<QString>(QString::number(value.toDouble(), 'g', 16));
685 } else if (value.userType() == QMetaType::QUrl && resultType == QMetaType::Bool) {
686 // url to bool conversion
687 value = QVariant::fromValue<bool>(!value.toUrl().isEmpty());
690 if (!value.isNull() && !value.convert(resultType)) {
692 qtscriptResult = "exception";
693 } else if (resultType == QMetaType::QUrl) {
694 // a V8 value was converted to QUrl.
695 value = QVariant::fromValue<QUrl>(context->resolvedUrl(value.toUrl()));
700 qtscriptResult = testResultToString(value, isUndefined);
702 if (isUndefined && result.isUndefined()) {
704 } else if(isUndefined != result.isUndefined()) {
709 if (!result.isUndefined()) {
710 switch (resultType) {
711 case QMetaType::QString:
712 v4value = *result.getstringptr();
714 case QMetaType::QUrl:
715 v4value = *result.geturlptr();
717 case QMetaType::QObjectStar:
718 v4value = qVariantFromValue<QObject *>(result.getQObject());
720 case QMetaType::Bool:
721 v4value = result.getbool();
724 v4value = result.getint();
726 case QMetaType::Double:
727 v4value = result.getnumber();
729 case QMetaType::QColor:
730 v4value = QVariant(QMetaType::QColor, result.typeDataPtr());
732 case QMetaType::QVariant:
733 v4value = *result.getvariantptr();
736 if (resultType == QQmlMetaType::QQuickAnchorLineMetaTypeId()) {
737 v4value = QVariant(QQmlMetaType::QQuickAnchorLineMetaTypeId(), result.typeDataPtr());
738 } else if (resultType == qMetaTypeId<QJSValue>()) {
739 v4value = result.getjsvalueptr()->toVariant();
740 } else if (resultType == handleType) {
741 QQmlEnginePrivate *ep = QQmlEnginePrivate::get(context->engine);
742 v4value = ep->v8engine()->toVariant(*result.gethandleptr(), resultType);
745 v4Result = "Unknown V4 type";
749 if (v4Result.isEmpty())
750 v4Result = testResultToString(v4value, result.isUndefined());
752 if (!testCompareVariants(value, v4value))
756 qWarning().nospace() << "QV4: Optimization error @" << context->url.toString().toUtf8().constData() << ':' << line << ':' << column;
758 qWarning().nospace() << " Binding: " << binding;
759 qWarning().nospace() << " QtScript: " << qtscriptResult.constData();
760 qWarning().nospace() << " V4: " << v4Result.constData();
764 static void testBindingException(const QString &binding, quint16 line, quint16 column,
765 QQmlContextData *context, QObject *scope)
767 QQmlExpression expression(context->asQQmlContext(), scope, binding);
768 bool isUndefined = false;
769 QVariant value = expression.evaluate(&isUndefined);
771 if (!expression.hasError()) {
772 QByteArray qtscriptResult = testResultToString(value, isUndefined);
773 qWarning().nospace() << "QV4: Optimization error @" << context->url.toString().toUtf8().constData() << ':' << line << ':' << column;
774 qWarning().nospace() << " Binding: " << binding;
775 qWarning().nospace() << " QtScript: " << qtscriptResult.constData();
776 qWarning().nospace() << " V4: exception";
780 static void throwException(int id, QQmlDelayedError *error,
781 QV4Program *program, QQmlContextData *context,
782 const QString &description = QString())
784 if (description.isEmpty())
785 error->setErrorDescription(QLatin1String("TypeError: Result of expression is not an object"));
787 error->setErrorDescription(description);
789 quint32 e = *((quint32 *)(program->data() + program->exceptionDataOffset) + id);
790 error->setErrorLocation(context->url, (e >> 16), (e & 0xFFFF));
792 error->setErrorLocation(context->url, -1, -1);
794 if (!context->engine || !error->addError(QQmlEnginePrivate::get(context->engine)))
795 QQmlEnginePrivate::warning(context->engine, error);
798 const double QV4Bindings::D32 = 4294967296.0;
800 qint32 QV4Bindings::toInt32(double n)
802 if (qIsNaN(n) || qIsInf(n) || (n == 0))
805 double sign = (n < 0) ? -1.0 : 1.0;
806 double abs_n = fabs(n);
808 n = ::fmod(sign * ::floor(abs_n), D32);
809 const double D31 = D32 / 2.0;
811 if (sign == -1 && n < -D31)
814 else if (sign != -1 && n >= D31)
820 inline quint32 QV4Bindings::toUint32(double n)
822 if (qIsNaN(n) || qIsInf(n) || (n == 0))
825 double sign = (n < 0) ? -1.0 : 1.0;
826 double abs_n = fabs(n);
828 n = ::fmod(sign * ::floor(abs_n), D32);
836 #define THROW_EXCEPTION_STR(id, str) { \
837 if (testBinding) testBindingException(*testBindingSource, bindingLine, bindingColumn, context, scope); \
838 throwException((id), error, program, context, (str)); \
839 goto exceptionExit; \
842 #define THROW_VALUE_EXCEPTION_STR(id, str) { \
843 throwException((id), error, program, context, (str)); \
844 goto exceptionExit; \
847 #define THROW_EXCEPTION(id) THROW_EXCEPTION_STR(id, QString())
849 #define MARK_REGISTER(reg) cleanupRegisterMask |= (1 << (reg))
850 #define MARK_CLEAN_REGISTER(reg) cleanupRegisterMask &= ~(1 << (reg))
852 #define STRING_REGISTER(reg) { \
853 registers[(reg)].settype(QStringType); \
854 MARK_REGISTER(reg); \
857 #define URL_REGISTER(reg) { \
858 registers[(reg)].settype(QUrlType); \
859 MARK_REGISTER(reg); \
862 #define COLOR_REGISTER(reg) { \
863 registers[(reg)].settype(QColorType); \
864 MARK_REGISTER(reg); \
867 #define VARIANT_REGISTER(reg) { \
868 registers[(reg)].settype(QVariantType); \
869 MARK_REGISTER(reg); \
872 #define V8HANDLE_REGISTER(reg) { \
873 registers[(reg)].settype(V8HandleType); \
874 MARK_REGISTER(reg); \
877 #define JSVALUE_REGISTER(reg) { \
878 registers[(reg)].settype(QJSValueType); \
879 MARK_REGISTER(reg); \
882 //TODO: avoid construction of name and name-based lookup
883 #define INVALIDATION_CHECK(inv, obj, index) { \
885 QQmlData *data = QQmlData::get((obj)); \
886 if (data && !data->propertyCache) { \
887 data->propertyCache = QQmlEnginePrivate::get(context->engine)->cache(object); \
888 if (data->propertyCache) data->propertyCache->addref(); \
890 QQmlPropertyData *prop = (data && data->propertyCache) ? data->propertyCache->property((index)) : 0; \
891 if (prop && prop->isOverridden()) { \
892 int resolvedIndex = data->propertyCache->property(prop->name(obj), obj, context)->coreIndex; \
893 if ((int)index < resolvedIndex) { \
901 #ifdef QML_THREADED_INTERPRETER
902 void **QV4Bindings::getDecodeInstrTable()
904 static void **decode_instr;
906 QV4Bindings *dummy = new QV4Bindings(0, 0);
907 quint32 executedBlocks = 0;
908 dummy->run(0, executedBlocks, 0, 0, 0, 0,
909 QQmlPropertyPrivate::BypassInterceptor,
917 void QV4Bindings::run(int instrIndex, quint32 &executedBlocks,
918 QQmlContextData *context, QQmlDelayedError *error,
919 QObject *scope, QObject *output,
920 QQmlPropertyPrivate::WriteFlags storeFlags,
922 #ifdef QML_THREADED_INTERPRETER
927 #ifdef QML_THREADED_INTERPRETER
929 static void *decode_instr[] = {
930 FOR_EACH_V4_INSTR(QML_V4_INSTR_ADDR)
933 *table = decode_instr;
939 error->removeError();
941 Register registers[32];
942 quint32 cleanupRegisterMask = 0;
946 const char *code = program->instructions();
947 code += instrIndex * QML_V4_INSTR_SIZE(Jump, jump);
948 const V4Instr *instr = reinterpret_cast<const V4Instr *>(code);
950 const char *data = program->data();
952 QString *testBindingSource = 0;
953 bool testBinding = false;
955 int bindingColumn = 0;
957 #ifdef QML_THREADED_INTERPRETER
958 goto *instr->common.code;
961 switch (instr->common.type) {
964 QML_V4_BEGIN_INSTR(Noop, common)
965 QML_V4_END_INSTR(Noop, common)
967 QML_V4_BEGIN_INSTR(BindingId, id)
968 bindingLine = instr->id.line;
969 bindingColumn = instr->id.column;
970 QML_V4_END_INSTR(BindingId, id)
972 QML_V4_BEGIN_INSTR(SubscribeId, subscribeop)
973 subscribeId(context, instr->subscribeop.index, instr->subscribeop.offset);
974 QML_V4_END_INSTR(SubscribeId, subscribeop)
976 QML_V4_BEGIN_INSTR(Subscribe, subscribeop)
979 const Register &object = registers[instr->subscribeop.reg];
980 if (!object.isUndefined()) o = object.getQObject();
981 subscribe(o, instr->subscribeop.index, instr->subscribeop.offset, context->engine);
983 QML_V4_END_INSTR(Subscribe, subscribeop)
985 QML_V4_BEGIN_INSTR(FetchAndSubscribe, fetchAndSubscribe)
987 Register ® = registers[instr->fetchAndSubscribe.reg];
989 if (reg.isUndefined())
990 THROW_EXCEPTION(instr->fetchAndSubscribe.exceptionId);
992 QObject *object = reg.getQObject();
994 THROW_EXCEPTION(instr->fetchAndSubscribe.exceptionId);
996 INVALIDATION_CHECK(invalidated, object, instr->fetchAndSubscribe.property.coreIndex);
998 const Register::Type valueType = (Register::Type)instr->fetchAndSubscribe.valueType;
1000 if (instr->fetchAndSubscribe.valueType >= FirstCleanupType)
1001 MARK_REGISTER(instr->fetchAndSubscribe.reg);
1002 QQmlAccessors *accessors = instr->fetchAndSubscribe.property.accessors;
1003 accessors->read(object, instr->fetchAndSubscribe.property.accessorData,
1006 if (valueType == FloatType) {
1008 const double v = reg.getfloat();
1012 if (accessors->notifier) {
1013 QQmlNotifier *notifier = 0;
1014 accessors->notifier(object, instr->fetchAndSubscribe.property.accessorData, ¬ifier);
1016 int subIdx = instr->fetchAndSubscribe.subscription;
1017 Subscription *sub = 0;
1019 sub = (subscriptions + subIdx);
1020 sub->setBindings(this);
1022 sub->connect(notifier);
1025 const int notifyIndex = instr->fetchAndSubscribe.property.notifyIndex;
1026 if (notifyIndex != -1) {
1027 const int subIdx = instr->fetchAndSubscribe.subscription;
1028 subscribe(object, notifyIndex, subIdx, context->engine);
1033 QML_V4_END_INSTR(FetchAndSubscribe, fetchAndSubscribe)
1035 QML_V4_BEGIN_INSTR(LoadId, load)
1036 registers[instr->load.reg].setQObject(context->idValues[instr->load.index].data());
1037 QML_V4_END_INSTR(LoadId, load)
1039 QML_V4_BEGIN_INSTR(LoadScope, load)
1040 registers[instr->load.reg].setQObject(scope);
1041 QML_V4_END_INSTR(LoadScope, load)
1043 QML_V4_BEGIN_INSTR(LoadRoot, load)
1044 registers[instr->load.reg].setQObject(context->contextObject);
1045 QML_V4_END_INSTR(LoadRoot, load)
1047 QML_V4_BEGIN_INSTR(LoadSingletonObject, load)
1049 Register ® = registers[instr->load.reg];
1051 const QString *name = reg.getstringptr();
1052 QQmlTypeNameCache::Result r = context->imports->query(*name);
1053 reg.cleanupString();
1055 if (r.isValid() && r.type) {
1056 if (r.type->isSingleton()) {
1057 QQmlEngine *e = context->engine;
1058 QQmlType::SingletonInstanceInfo *siinfo = r.type->singletonInstanceInfo();
1059 siinfo->init(e); // note: this will also create QJSValue singleton, which is not strictly required here.
1060 QObject *qobjectSingleton = siinfo->qobjectApi(e);
1061 if (qobjectSingleton)
1062 reg.setQObject(qobjectSingleton);
1066 QML_V4_END_INSTR(LoadSingletonObject, load)
1068 QML_V4_BEGIN_INSTR(LoadAttached, attached)
1070 const Register &input = registers[instr->attached.reg];
1071 Register &output = registers[instr->attached.output];
1072 if (input.isUndefined())
1073 THROW_EXCEPTION(instr->attached.exceptionId);
1075 QObject *object = registers[instr->attached.reg].getQObject();
1077 output.setUndefined();
1079 QObject *attached = qmlAttachedPropertiesObjectById(instr->attached.id, input.getQObject(), true);
1081 output.setQObject(attached);
1084 QML_V4_END_INSTR(LoadAttached, attached)
1086 QML_V4_BEGIN_INSTR(UnaryNot, unaryop)
1088 registers[instr->unaryop.output].setbool(!registers[instr->unaryop.src].getbool());
1090 QML_V4_END_INSTR(UnaryNot, unaryop)
1092 QML_V4_BEGIN_INSTR(UnaryMinusNumber, unaryop)
1094 registers[instr->unaryop.output].setnumber(-registers[instr->unaryop.src].getnumber());
1096 QML_V4_END_INSTR(UnaryMinusNumber, unaryop)
1098 QML_V4_BEGIN_INSTR(UnaryMinusInt, unaryop)
1100 registers[instr->unaryop.output].setint(-registers[instr->unaryop.src].getint());
1102 QML_V4_END_INSTR(UnaryMinusInt, unaryop)
1104 QML_V4_BEGIN_INSTR(UnaryPlusNumber, unaryop)
1106 registers[instr->unaryop.output].setnumber(+registers[instr->unaryop.src].getnumber());
1108 QML_V4_END_INSTR(UnaryPlusNumber, unaryop)
1110 QML_V4_BEGIN_INSTR(UnaryPlusInt, unaryop)
1112 registers[instr->unaryop.output].setint(+registers[instr->unaryop.src].getint());
1114 QML_V4_END_INSTR(UnaryPlusInt, unaryop)
1116 QML_V4_BEGIN_INSTR(ConvertBoolToInt, unaryop)
1118 const Register &src = registers[instr->unaryop.src];
1119 Register &output = registers[instr->unaryop.output];
1120 if (src.isUndefined()) output.setUndefined();
1121 else output.setint(src.getbool());
1123 QML_V4_END_INSTR(ConvertBoolToInt, unaryop)
1125 QML_V4_BEGIN_INSTR(ConvertBoolToJSValue, unaryop)
1127 const Register &src = registers[instr->unaryop.src];
1128 Register &output = registers[instr->unaryop.output];
1129 if (src.isUndefined()) {
1130 output.setUndefined();
1132 new (output.getjsvalueptr()) QJSValue(src.getbool());
1133 JSVALUE_REGISTER(instr->unaryop.output);
1136 QML_V4_END_INSTR(ConvertBoolToJSValue, unaryop)
1138 QML_V4_BEGIN_INSTR(ConvertBoolToNumber, unaryop)
1140 const Register &src = registers[instr->unaryop.src];
1141 Register &output = registers[instr->unaryop.output];
1142 if (src.isUndefined()) output.setUndefined();
1143 else output.setnumber(src.getbool());
1145 QML_V4_END_INSTR(ConvertBoolToNumber, unaryop)
1147 QML_V4_BEGIN_INSTR(ConvertBoolToString, unaryop)
1149 const Register &src = registers[instr->unaryop.src];
1150 Register &output = registers[instr->unaryop.output];
1151 if (src.isUndefined()) {
1152 output.setUndefined();
1154 new (output.getstringptr()) QString(QLatin1String(src.getbool() ? "true" : "false"));
1155 STRING_REGISTER(instr->unaryop.output);
1158 QML_V4_END_INSTR(ConvertBoolToString, unaryop)
1160 QML_V4_BEGIN_INSTR(ConvertBoolToVariant, unaryop)
1162 const Register &src = registers[instr->unaryop.src];
1163 Register &output = registers[instr->unaryop.output];
1164 if (src.isUndefined()) {
1165 output.setUndefined();
1167 new (output.getvariantptr()) QVariant(src.getbool());
1168 VARIANT_REGISTER(instr->unaryop.output);
1171 QML_V4_END_INSTR(ConvertBoolToVariant, unaryop)
1173 QML_V4_BEGIN_INSTR(ConvertBoolToVar, unaryop)
1175 const Register &src = registers[instr->unaryop.src];
1176 Register &output = registers[instr->unaryop.output];
1177 if (src.isUndefined()) {
1178 output.setUndefined();
1180 new (output.gethandleptr()) v8::Handle<v8::Value>(v8::Boolean::New(src.getbool()));
1181 V8HANDLE_REGISTER(instr->unaryop.output);
1184 QML_V4_END_INSTR(ConvertBoolToVar, unaryop)
1186 QML_V4_BEGIN_INSTR(ConvertIntToBool, unaryop)
1188 const Register &src = registers[instr->unaryop.src];
1189 Register &output = registers[instr->unaryop.output];
1190 if (src.isUndefined()) output.setUndefined();
1191 else output.setbool(src.getint());
1193 QML_V4_END_INSTR(ConvertIntToBool, unaryop)
1195 QML_V4_BEGIN_INSTR(ConvertIntToJSValue, unaryop)
1197 const Register &src = registers[instr->unaryop.src];
1198 Register &output = registers[instr->unaryop.output];
1199 if (src.isUndefined()) {
1200 output.setUndefined();
1202 new (output.getjsvalueptr()) QJSValue(src.getint());
1203 JSVALUE_REGISTER(instr->unaryop.output);
1206 QML_V4_END_INSTR(ConvertIntToJSValue, unaryop)
1208 QML_V4_BEGIN_INSTR(ConvertIntToNumber, unaryop)
1210 const Register &src = registers[instr->unaryop.src];
1211 Register &output = registers[instr->unaryop.output];
1212 if (src.isUndefined()) output.setUndefined();
1213 else if (src.isNaN()) output.setNaN();
1214 else if (src.isInf()) output.setInf(src.getint() == Register::NegativeInfinity);
1215 else if (src.isNegativeZero()) output.setNegativeZero();
1216 else output.setnumber(double(src.getint()));
1218 QML_V4_END_INSTR(ConvertIntToNumber, unaryop)
1220 QML_V4_BEGIN_INSTR(ConvertIntToString, unaryop)
1222 const Register &src = registers[instr->unaryop.src];
1223 Register &output = registers[instr->unaryop.output];
1224 if (src.isUndefined()) {
1225 output.setUndefined();
1227 new (output.getstringptr()) QString(QString::number(src.getint()));
1228 STRING_REGISTER(instr->unaryop.output);
1231 QML_V4_END_INSTR(ConvertIntToString, unaryop)
1233 QML_V4_BEGIN_INSTR(ConvertIntToVariant, unaryop)
1235 const Register &src = registers[instr->unaryop.src];
1236 Register &output = registers[instr->unaryop.output];
1237 if (src.isUndefined()) {
1238 output.setUndefined();
1240 new (output.getvariantptr()) QVariant(src.getint());
1241 VARIANT_REGISTER(instr->unaryop.output);
1244 QML_V4_END_INSTR(ConvertIntToVariant, unaryop)
1246 QML_V4_BEGIN_INSTR(ConvertIntToVar, unaryop)
1248 const Register &src = registers[instr->unaryop.src];
1249 Register &output = registers[instr->unaryop.output];
1250 if (src.isUndefined()) {
1251 output.setUndefined();
1253 new (output.gethandleptr()) v8::Handle<v8::Value>(v8::Integer::New(src.getint()));
1254 V8HANDLE_REGISTER(instr->unaryop.output);
1257 QML_V4_END_INSTR(ConvertIntToVar, unaryop)
1259 QML_V4_BEGIN_INSTR(ConvertJSValueToVar, unaryop)
1261 const Register &src = registers[instr->unaryop.src];
1262 Register &output = registers[instr->unaryop.output];
1263 if (src.isUndefined()) {
1264 output.setUndefined();
1266 QJSValue tmp(*src.getjsvalueptr());
1267 if (instr->unaryop.src == instr->unaryop.output) {
1268 output.cleanupJSValue();
1269 MARK_CLEAN_REGISTER(instr->unaryop.output);
1271 if (tmp.isUndefined()) {
1272 output.setUndefined();
1274 QV8Engine *v8engine = QQmlEnginePrivate::get(context->engine)->v8engine();
1275 new (output.gethandleptr()) v8::Handle<v8::Value>(
1276 QJSValuePrivate::get(tmp)->asV8Value(v8engine));
1277 V8HANDLE_REGISTER(instr->unaryop.output);
1281 QML_V4_END_INSTR(ConvertJSValueToVar, unaryop)
1283 QML_V4_BEGIN_INSTR(ConvertNumberToBool, unaryop)
1285 const Register &src = registers[instr->unaryop.src];
1286 Register &output = registers[instr->unaryop.output];
1287 if (src.isUndefined()) output.setUndefined();
1288 else output.setbool(src.getnumber() != 0);
1290 QML_V4_END_INSTR(ConvertNumberToBool, unaryop)
1292 QML_V4_BEGIN_INSTR(ConvertNumberToInt, unaryop)
1294 const Register &src = registers[instr->unaryop.src];
1295 Register &output = registers[instr->unaryop.output];
1296 if (src.isUndefined()) output.setUndefined();
1297 else output.setint(toInt32(src.getnumber()));
1299 QML_V4_END_INSTR(ConvertNumberToInt, unaryop)
1301 QML_V4_BEGIN_INSTR(ConvertNumberToJSValue, unaryop)
1303 const Register &src = registers[instr->unaryop.src];
1304 Register &output = registers[instr->unaryop.output];
1305 if (src.isUndefined()) {
1306 output.setUndefined();
1308 new (output.getjsvalueptr()) QJSValue(src.getnumber());
1309 JSVALUE_REGISTER(instr->unaryop.output);
1312 QML_V4_END_INSTR(ConvertNumberToJSValue, unaryop)
1314 QML_V4_BEGIN_INSTR(ConvertNumberToString, unaryop)
1316 const Register &src = registers[instr->unaryop.src];
1317 Register &output = registers[instr->unaryop.output];
1319 if (src.isUndefined()) {
1320 output.setUndefined();
1322 new (output.getstringptr()) QString(QString::number(src.getnumber(), 'g', 16));
1323 STRING_REGISTER(instr->unaryop.output);
1326 QML_V4_END_INSTR(ConvertNumberToString, unaryop)
1328 QML_V4_BEGIN_INSTR(ConvertNumberToVariant, unaryop)
1330 const Register &src = registers[instr->unaryop.src];
1331 Register &output = registers[instr->unaryop.output];
1332 if (src.isUndefined()) {
1333 output.setUndefined();
1335 new (output.getvariantptr()) QVariant(src.getnumber());
1336 VARIANT_REGISTER(instr->unaryop.output);
1339 QML_V4_END_INSTR(ConvertNumberToVariant, unaryop)
1341 QML_V4_BEGIN_INSTR(ConvertNumberToVar, unaryop)
1343 const Register &src = registers[instr->unaryop.src];
1344 Register &output = registers[instr->unaryop.output];
1345 if (src.isUndefined()) {
1346 output.setUndefined();
1348 new (output.gethandleptr()) v8::Handle<v8::Value>(v8::Number::New(src.getnumber()));
1349 V8HANDLE_REGISTER(instr->unaryop.output);
1352 QML_V4_END_INSTR(ConvertNumberToVar, unaryop)
1354 QML_V4_BEGIN_INSTR(ConvertStringToBool, unaryop)
1356 const Register &src = registers[instr->unaryop.src];
1357 Register &output = registers[instr->unaryop.output];
1359 if (src.isUndefined()) {
1360 output.setUndefined();
1362 // Delegate the conversion. This is pretty fast and it doesn't require a QScriptEngine.
1363 // Ideally we should just call the methods in the QScript namespace directly.
1364 QJSValue tmp(*src.getstringptr());
1365 if (instr->unaryop.src == instr->unaryop.output) {
1366 output.cleanupString();
1367 MARK_CLEAN_REGISTER(instr->unaryop.output);
1369 output.setbool(tmp.toBool());
1372 QML_V4_END_INSTR(ConvertStringToBool, unaryop)
1374 QML_V4_BEGIN_INSTR(ConvertStringToInt, unaryop)
1376 const Register &src = registers[instr->unaryop.src];
1377 Register &output = registers[instr->unaryop.output];
1379 if (src.isUndefined()) {
1380 output.setUndefined();
1382 // Delegate the conversion. This is pretty fast and it doesn't require a QScriptEngine.
1383 // Ideally we should just call the methods in the QScript namespace directly.
1384 QJSValue tmp(*src.getstringptr());
1385 if (instr->unaryop.src == instr->unaryop.output) {
1386 output.cleanupString();
1387 MARK_CLEAN_REGISTER(instr->unaryop.output);
1389 output.setint(tmp.toInt());
1392 QML_V4_END_INSTR(ConvertStringToInt, unaryop)
1394 QML_V4_BEGIN_INSTR(ConvertStringToJSValue, unaryop)
1396 const Register &src = registers[instr->unaryop.src];
1397 Register &output = registers[instr->unaryop.output];
1398 if (src.isUndefined()) {
1399 output.setUndefined();
1401 QString tmp(*src.getstringptr());
1402 if (instr->unaryop.src == instr->unaryop.output) {
1403 output.cleanupString();
1404 MARK_CLEAN_REGISTER(instr->unaryop.output);
1406 new (output.getjsvalueptr()) QJSValue(tmp);
1407 JSVALUE_REGISTER(instr->unaryop.output);
1410 QML_V4_END_INSTR(ConvertStringToJSValue, unaryop)
1412 QML_V4_BEGIN_INSTR(ConvertStringToNumber, unaryop)
1414 const Register &src = registers[instr->unaryop.src];
1415 Register &output = registers[instr->unaryop.output];
1417 if (src.isUndefined()) {
1418 output.setUndefined();
1420 // Delegate the conversion. This is pretty fast and it doesn't require a QScriptEngine.
1421 // Ideally we should just call the methods in the QScript namespace directly.
1422 QJSValue tmp(*src.getstringptr());
1423 if (instr->unaryop.src == instr->unaryop.output) {
1424 output.cleanupString();
1425 MARK_CLEAN_REGISTER(instr->unaryop.output);
1427 output.setnumber(tmp.toNumber());
1430 QML_V4_END_INSTR(ConvertStringToNumber, unaryop)
1432 QML_V4_BEGIN_INSTR(ConvertStringToUrl, unaryop)
1434 const Register &src = registers[instr->unaryop.src];
1435 Register &output = registers[instr->unaryop.output];
1437 if (src.isUndefined()) {
1438 output.setUndefined();
1440 QString tmp(*src.getstringptr());
1441 // Encoded dir-separators defeat QUrl processing - decode them first
1442 tmp.replace(QLatin1String("%2f"), QLatin1String("/"), Qt::CaseInsensitive);
1443 if (instr->unaryop.src == instr->unaryop.output) {
1444 output.cleanupString();
1445 MARK_CLEAN_REGISTER(instr->unaryop.output);
1447 new (output.geturlptr()) QUrl(tmp);
1449 URL_REGISTER(instr->unaryop.output);
1452 QML_V4_END_INSTR(ConvertStringToUrl, unaryop)
1454 QML_V4_BEGIN_INSTR(ConvertStringToColor, unaryop)
1456 const Register &src = registers[instr->unaryop.src];
1457 Register &output = registers[instr->unaryop.output];
1459 if (src.isUndefined()) {
1460 output.setUndefined();
1462 const QString tmp(*src.getstringptr());
1463 if (instr->unaryop.src == instr->unaryop.output) {
1464 output.cleanupString();
1465 MARK_CLEAN_REGISTER(instr->unaryop.output);
1467 QQml_valueTypeProvider()->createValueFromString(QMetaType::QColor, tmp, output.typeDataPtr(), output.dataSize());
1469 COLOR_REGISTER(instr->unaryop.output);
1472 QML_V4_END_INSTR(ConvertStringToColor, unaryop)
1474 QML_V4_BEGIN_INSTR(ConvertStringToVariant, unaryop)
1476 const Register &src = registers[instr->unaryop.src];
1477 Register &output = registers[instr->unaryop.output];
1478 if (src.isUndefined()) {
1479 output.setUndefined();
1481 const QString tmp(*src.getstringptr());
1482 if (instr->unaryop.src == instr->unaryop.output) {
1483 output.cleanupString();
1484 MARK_CLEAN_REGISTER(instr->unaryop.output);
1486 new (output.getvariantptr()) QVariant(tmp);
1488 VARIANT_REGISTER(instr->unaryop.output);
1491 QML_V4_END_INSTR(ConvertStringToVariant, unaryop)
1493 QML_V4_BEGIN_INSTR(ConvertStringToVar, unaryop)
1495 const Register &src = registers[instr->unaryop.src];
1496 Register &output = registers[instr->unaryop.output];
1497 if (src.isUndefined()) {
1498 output.setUndefined();
1500 const QString tmp(*src.getstringptr());
1501 if (instr->unaryop.src == instr->unaryop.output) {
1502 output.cleanupString();
1503 MARK_CLEAN_REGISTER(instr->unaryop.output);
1505 new (output.gethandleptr()) v8::Handle<v8::Value>(QJSConverter::toString(tmp));
1506 V8HANDLE_REGISTER(instr->unaryop.output);
1509 QML_V4_END_INSTR(ConvertStringToVar, unaryop)
1511 QML_V4_BEGIN_INSTR(ConvertUrlToBool, unaryop)
1513 const Register &src = registers[instr->unaryop.src];
1514 Register &output = registers[instr->unaryop.output];
1516 if (src.isUndefined()) {
1517 output.setUndefined();
1519 const QUrl tmp(*src.geturlptr());
1520 if (instr->unaryop.src == instr->unaryop.output) {
1521 output.cleanupUrl();
1522 MARK_CLEAN_REGISTER(instr->unaryop.output);
1524 output.setbool(!tmp.isEmpty());
1527 QML_V4_END_INSTR(ConvertUrlToBool, unaryop)
1529 QML_V4_BEGIN_INSTR(ConvertUrlToJSValue, unaryop)
1531 const Register &src = registers[instr->unaryop.src];
1532 Register &output = registers[instr->unaryop.output];
1533 if (src.isUndefined()) {
1534 output.setUndefined();
1536 const QUrl tmp(*src.geturlptr());
1537 if (instr->unaryop.src == instr->unaryop.output) {
1538 output.cleanupUrl();
1539 MARK_CLEAN_REGISTER(instr->unaryop.output);
1541 new (output.getjsvalueptr()) QJSValue(tmp.toString());
1542 JSVALUE_REGISTER(instr->unaryop.output);
1545 QML_V4_END_INSTR(ConvertUrlToJSValue, unaryop)
1547 QML_V4_BEGIN_INSTR(ConvertUrlToString, unaryop)
1549 const Register &src = registers[instr->unaryop.src];
1550 Register &output = registers[instr->unaryop.output];
1552 if (src.isUndefined()) {
1553 output.setUndefined();
1555 const QUrl tmp(*src.geturlptr());
1556 if (instr->unaryop.src == instr->unaryop.output) {
1557 output.cleanupUrl();
1558 MARK_CLEAN_REGISTER(instr->unaryop.output);
1560 new (output.getstringptr()) QString(tmp.toString());
1561 STRING_REGISTER(instr->unaryop.output);
1564 QML_V4_END_INSTR(ConvertUrlToString, unaryop)
1566 QML_V4_BEGIN_INSTR(ConvertUrlToVariant, unaryop)
1568 const Register &src = registers[instr->unaryop.src];
1569 Register &output = registers[instr->unaryop.output];
1571 if (src.isUndefined()) {
1572 output.setUndefined();
1574 const QUrl tmp(*src.geturlptr());
1575 if (instr->unaryop.src == instr->unaryop.output) {
1576 output.cleanupUrl();
1577 MARK_CLEAN_REGISTER(instr->unaryop.output);
1579 new (output.getvariantptr()) QVariant(tmp);
1580 VARIANT_REGISTER(instr->unaryop.output);
1583 QML_V4_END_INSTR(ConvertUrlToVariant, unaryop)
1585 QML_V4_BEGIN_INSTR(ConvertUrlToVar, unaryop)
1587 const Register &src = registers[instr->unaryop.src];
1588 Register &output = registers[instr->unaryop.output];
1590 if (src.isUndefined()) {
1591 output.setUndefined();
1593 const QUrl tmp(*src.geturlptr());
1594 if (instr->unaryop.src == instr->unaryop.output) {
1595 output.cleanupUrl();
1596 MARK_CLEAN_REGISTER(instr->unaryop.output);
1598 new (output.gethandleptr()) v8::Handle<v8::Value>(QJSConverter::toString(tmp.toString()));
1599 V8HANDLE_REGISTER(instr->unaryop.output);
1602 QML_V4_END_INSTR(ConvertUrlToVar, unaryop)
1604 QML_V4_BEGIN_INSTR(ConvertColorToBool, unaryop)
1606 const Register &src = registers[instr->unaryop.src];
1607 Register &output = registers[instr->unaryop.output];
1609 if (src.isUndefined()) {
1610 output.setUndefined();
1612 // for compatibility with color behavior in v8, always true
1613 output.setbool(true);
1616 QML_V4_END_INSTR(ConvertColorToBool, unaryop)
1618 QML_V4_BEGIN_INSTR(ConvertColorToJSValue, unaryop)
1620 const Register &src = registers[instr->unaryop.src];
1621 Register &output = registers[instr->unaryop.output];
1622 if (src.isUndefined()) {
1623 output.setUndefined();
1625 const QVariant tmp(QMetaType::QColor, src.typeDataPtr());
1626 if (instr->unaryop.src == instr->unaryop.output) {
1627 output.cleanupColor();
1628 MARK_CLEAN_REGISTER(instr->unaryop.output);
1631 QQmlEnginePrivate *ep = QQmlEnginePrivate::get(context->engine);
1632 QV8Engine *v8engine = ep->v8engine();
1633 QQmlValueType *vt = QQmlValueTypeFactory::valueType(QMetaType::QColor);
1634 v8::HandleScope handle_scope;
1635 v8::Context::Scope scope(v8engine->context());
1636 new (output.getjsvalueptr()) QJSValue(v8engine->scriptValueFromInternal(
1637 v8engine->valueTypeWrapper()->newValueType(tmp, vt)));
1638 JSVALUE_REGISTER(instr->unaryop.output);
1641 QML_V4_END_INSTR(ConvertColorToJSValue, unaryop)
1643 QML_V4_BEGIN_INSTR(ConvertColorToString, unaryop)
1645 const Register &src = registers[instr->unaryop.src];
1646 Register &output = registers[instr->unaryop.output];
1648 if (src.isUndefined()) {
1649 output.setUndefined();
1651 QQml_valueTypeProvider()->createStringFromValue(QMetaType::QColor, src.typeDataPtr(), output.getstringptr());
1652 STRING_REGISTER(instr->unaryop.output);
1655 QML_V4_END_INSTR(ConvertColorToString, unaryop)
1657 QML_V4_BEGIN_INSTR(ConvertColorToVariant, unaryop)
1659 const Register &src = registers[instr->unaryop.src];
1660 Register &output = registers[instr->unaryop.output];
1662 if (src.isUndefined()) {
1663 output.setUndefined();
1665 QVariant tmp(QMetaType::QColor, src.typeDataPtr());
1666 if (instr->unaryop.src == instr->unaryop.output) {
1667 output.cleanupColor();
1668 MARK_CLEAN_REGISTER(instr->unaryop.output);
1670 new (output.getvariantptr()) QVariant(tmp);
1671 VARIANT_REGISTER(instr->unaryop.output);
1674 QML_V4_END_INSTR(ConvertColorToVariant, unaryop)
1676 QML_V4_BEGIN_INSTR(ConvertColorToVar, unaryop)
1678 const Register &src = registers[instr->unaryop.src];
1679 Register &output = registers[instr->unaryop.output];
1681 if (src.isUndefined()) {
1682 output.setUndefined();
1684 const QVariant tmp(QMetaType::QColor, src.typeDataPtr());
1685 if (instr->unaryop.src == instr->unaryop.output) {
1686 output.cleanupColor();
1687 MARK_CLEAN_REGISTER(instr->unaryop.output);
1690 QQmlEnginePrivate *ep = QQmlEnginePrivate::get(context->engine);
1691 QQmlValueType *vt = QQmlValueTypeFactory::valueType(QMetaType::QColor);
1692 new (output.gethandleptr()) v8::Handle<v8::Value>(ep->v8engine()->valueTypeWrapper()->newValueType(tmp, vt));
1693 V8HANDLE_REGISTER(instr->unaryop.output);
1696 QML_V4_END_INSTR(ConvertColorToVar, unaryop)
1698 QML_V4_BEGIN_INSTR(ConvertObjectToBool, unaryop)
1700 const Register &src = registers[instr->unaryop.src];
1701 Register &output = registers[instr->unaryop.output];
1703 if (src.isUndefined())
1704 output.setUndefined();
1706 output.setbool(src.getQObject() != 0);
1708 QML_V4_END_INSTR(ConvertObjectToBool, unaryop)
1710 QML_V4_BEGIN_INSTR(ConvertObjectToJSValue, unaryop)
1712 const Register &src = registers[instr->unaryop.src];
1713 Register &output = registers[instr->unaryop.output];
1714 if (src.isUndefined()) {
1715 output.setUndefined();
1717 QQmlEnginePrivate *ep = QQmlEnginePrivate::get(context->engine);
1718 v8::HandleScope handle_scope;
1719 v8::Context::Scope scope(ep->v8engine()->context());
1720 new (output.getjsvalueptr()) QJSValue(context->engine->newQObject(src.getQObject()));
1721 JSVALUE_REGISTER(instr->unaryop.output);
1724 QML_V4_END_INSTR(ConvertObjectToJSValue, unaryop)
1726 QML_V4_BEGIN_INSTR(ConvertObjectToVariant, unaryop)
1728 const Register &src = registers[instr->unaryop.src];
1729 Register &output = registers[instr->unaryop.output];
1731 if (src.isUndefined())
1732 output.setUndefined();
1734 new (output.getvariantptr()) QVariant(qVariantFromValue<QObject *>(src.getQObject()));
1735 VARIANT_REGISTER(instr->unaryop.output);
1738 QML_V4_END_INSTR(ConvertObjectToVariant, unaryop)
1740 QML_V4_BEGIN_INSTR(ConvertObjectToVar, unaryop)
1742 const Register &src = registers[instr->unaryop.src];
1743 Register &output = registers[instr->unaryop.output];
1745 if (src.isUndefined())
1746 output.setUndefined();
1748 QQmlEnginePrivate *ep = QQmlEnginePrivate::get(context->engine);
1749 new (output.gethandleptr()) v8::Handle<v8::Value>(ep->v8engine()->newQObject(src.getQObject()));
1750 V8HANDLE_REGISTER(instr->unaryop.output);
1753 QML_V4_END_INSTR(ConvertObjectToVar, unaryop)
1755 QML_V4_BEGIN_INSTR(ConvertVarToJSValue, unaryop)
1757 const Register &src = registers[instr->unaryop.src];
1758 Register &output = registers[instr->unaryop.output];
1759 if (src.isUndefined()) {
1760 output.setUndefined();
1762 v8::Handle<v8::Value> tmp(*src.gethandleptr());
1763 if (instr->unaryop.src == instr->unaryop.output) {
1764 output.cleanupHandle();
1765 MARK_CLEAN_REGISTER(instr->unaryop.output);
1767 QV8Engine *v8engine = QQmlEnginePrivate::get(context->engine)->v8engine();
1768 new (output.getjsvalueptr()) QJSValue(v8engine->scriptValueFromInternal(tmp));
1769 JSVALUE_REGISTER(instr->unaryop.output);
1772 QML_V4_END_INSTR(ConvertVarToJSValue, unaryop)
1774 QML_V4_BEGIN_INSTR(ConvertNullToJSValue, unaryop)
1776 Register &output = registers[instr->unaryop.output];
1777 new (output.getjsvalueptr()) QJSValue(QJSValue::NullValue);
1778 JSVALUE_REGISTER(instr->unaryop.output);
1780 QML_V4_END_INSTR(ConvertNullToJSValue, unaryop)
1782 QML_V4_BEGIN_INSTR(ConvertNullToObject, unaryop)
1784 Register &output = registers[instr->unaryop.output];
1785 output.setQObject(0);
1787 QML_V4_END_INSTR(ConvertNullToObject, unaryop)
1789 QML_V4_BEGIN_INSTR(ConvertNullToVariant, unaryop)
1791 Register &output = registers[instr->unaryop.output];
1792 new (output.getvariantptr()) QVariant();
1793 VARIANT_REGISTER(instr->unaryop.output);
1795 QML_V4_END_INSTR(ConvertNullToVariant, unaryop)
1797 QML_V4_BEGIN_INSTR(ConvertNullToVar, unaryop)
1799 Register &output = registers[instr->unaryop.output];
1800 new (output.gethandleptr()) v8::Handle<v8::Value>(v8::Null());
1801 V8HANDLE_REGISTER(instr->unaryop.output);
1803 QML_V4_END_INSTR(ConvertNullToVar, unaryop)
1805 QML_V4_BEGIN_INSTR(ResolveUrl, unaryop)
1807 const Register &src = registers[instr->unaryop.src];
1808 Register &output = registers[instr->unaryop.output];
1809 if (src.isUndefined()) {
1810 output.setUndefined();
1812 const QUrl tmp(*src.geturlptr());
1813 if (instr->unaryop.src == instr->unaryop.output) {
1814 *output.geturlptr() = context->resolvedUrl(tmp);
1816 new (output.geturlptr()) QUrl(context->resolvedUrl(tmp));
1817 URL_REGISTER(instr->unaryop.output);
1821 QML_V4_END_INSTR(ResolveUrl, unaryop)
1823 QML_V4_BEGIN_INSTR(MathSinNumber, unaryop)
1825 const Register &src = registers[instr->unaryop.src];
1826 Register &output = registers[instr->unaryop.output];
1827 if (src.isUndefined()) output.setUndefined();
1828 else output.setnumber(qSin(src.getnumber()));
1830 QML_V4_END_INSTR(MathSinNumber, unaryop)
1832 QML_V4_BEGIN_INSTR(MathCosNumber, unaryop)
1834 const Register &src = registers[instr->unaryop.src];
1835 Register &output = registers[instr->unaryop.output];
1836 if (src.isUndefined()) output.setUndefined();
1837 else output.setnumber(qCos(src.getnumber()));
1839 QML_V4_END_INSTR(MathCosNumber, unaryop)
1841 QML_V4_BEGIN_INSTR(MathAbsNumber, unaryop)
1843 const Register &src = registers[instr->unaryop.src];
1844 Register &output = registers[instr->unaryop.output];
1845 if (src.isUndefined()) output.setUndefined();
1846 else output.setnumber(clearSignBit(qAbs(src.getnumber())));
1848 QML_V4_END_INSTR(MathAbsNumber, unaryop)
1850 QML_V4_BEGIN_INSTR(MathRoundNumber, unaryop)
1852 const Register &src = registers[instr->unaryop.src];
1853 Register &output = registers[instr->unaryop.output];
1854 if (src.isUndefined()) output.setUndefined();
1855 else output.setint(qRound(src.getnumber()));
1857 QML_V4_END_INSTR(MathRoundNumber, unaryop)
1859 QML_V4_BEGIN_INSTR(MathFloorNumber, unaryop)
1861 const Register &src = registers[instr->unaryop.src];
1862 Register &output = registers[instr->unaryop.output];
1863 if (src.isUndefined())
1864 output.setUndefined();
1865 else if (src.isNaN())
1866 // output should be an int, but still NaN
1867 output.setNaNType();
1868 else if (src.isInf())
1869 // output should be an int, but still Inf
1870 output.setInfType(signBitSet(src.getnumber()));
1871 else if (src.isNegativeZero())
1872 // output should be an int, but still -0
1873 output.setNegativeZeroType();
1875 output.setint(qFloor(src.getnumber()));
1877 QML_V4_END_INSTR(MathFloorNumber, unaryop)
1879 QML_V4_BEGIN_INSTR(MathCeilNumber, unaryop)
1881 const Register &src = registers[instr->unaryop.src];
1882 Register &output = registers[instr->unaryop.output];
1883 if (src.isUndefined())
1884 output.setUndefined();
1885 else if (src.isNaN())
1886 // output should be an int, but still NaN
1887 output.setNaNType();
1888 else if (src.isInf())
1889 // output should be an int, but still Inf
1890 output.setInfType(signBitSet(src.getnumber()));
1891 else if (src.isNegativeZero())
1892 // output should be an int, but still -0
1893 output.setNegativeZeroType();
1895 // Ensure that we preserve the sign bit (Math.ceil(-0) -> -0)
1896 const double input = src.getnumber();
1897 const int ceiled = qCeil(input);
1898 if (ceiled == 0 && signBitSet(input)) {
1899 output.setNegativeZeroType();
1901 output.setint(ceiled);
1905 QML_V4_END_INSTR(MathCeilNumber, unaryop)
1907 QML_V4_BEGIN_INSTR(MathPINumber, unaryop)
1909 static const double qmlPI = 2.0 * qAsin(1.0);
1910 Register &output = registers[instr->unaryop.output];
1911 output.setnumber(qmlPI);
1913 QML_V4_END_INSTR(MathPINumber, unaryop)
1915 QML_V4_BEGIN_INSTR(LoadNull, null_value)
1916 registers[instr->null_value.reg].setNull();
1917 QML_V4_END_INSTR(LoadNull, null_value)
1919 QML_V4_BEGIN_INSTR(LoadNumber, number_value)
1920 registers[instr->number_value.reg].setnumber(instr->number_value.value);
1921 QML_V4_END_INSTR(LoadNumber, number_value)
1923 QML_V4_BEGIN_INSTR(LoadInt, int_value)
1924 registers[instr->int_value.reg].setint(instr->int_value.value);
1925 QML_V4_END_INSTR(LoadInt, int_value)
1927 QML_V4_BEGIN_INSTR(LoadBool, bool_value)
1928 registers[instr->bool_value.reg].setbool(instr->bool_value.value);
1929 QML_V4_END_INSTR(LoadBool, bool_value)
1931 QML_V4_BEGIN_INSTR(LoadString, string_value)
1933 Register &output = registers[instr->string_value.reg];
1934 QChar *string = (QChar *)(data + instr->string_value.offset);
1935 new (output.getstringptr()) QString(string, instr->string_value.length);
1936 STRING_REGISTER(instr->string_value.reg);
1938 QML_V4_END_INSTR(LoadString, string_value)
1940 QML_V4_BEGIN_INSTR(EnableV4Test, string_value)
1942 testBindingSource = new QString((QChar *)(data + instr->string_value.offset), instr->string_value.length);
1945 QML_V4_END_INSTR(String, string_value)
1947 QML_V4_BEGIN_INSTR(BitAndInt, binaryop)
1949 registers[instr->binaryop.output].setint(registers[instr->binaryop.left].getint() &
1950 registers[instr->binaryop.right].getint());
1952 QML_V4_END_INSTR(BitAndInt, binaryop)
1954 QML_V4_BEGIN_INSTR(BitOrInt, binaryop)
1956 registers[instr->binaryop.output].setint(registers[instr->binaryop.left].getint() |
1957 registers[instr->binaryop.right].getint());
1959 QML_V4_END_INSTR(BitAndInt, binaryop)
1961 QML_V4_BEGIN_INSTR(BitXorInt, binaryop)
1963 registers[instr->binaryop.output].setint(registers[instr->binaryop.left].getint() ^
1964 registers[instr->binaryop.right].getint());
1966 QML_V4_END_INSTR(BitXorInt, binaryop)
1968 QML_V4_BEGIN_INSTR(AddNumber, binaryop)
1970 registers[instr->binaryop.output].setnumber(registers[instr->binaryop.left].getnumber() +
1971 registers[instr->binaryop.right].getnumber());
1973 QML_V4_END_INSTR(AddNumber, binaryop)
1975 QML_V4_BEGIN_INSTR(AddString, binaryop)
1977 QString &string = *registers[instr->binaryop.output].getstringptr();
1978 if (instr->binaryop.output == instr->binaryop.left) {
1979 string += registers[instr->binaryop.right].getstringptr();
1981 string = *registers[instr->binaryop.left].getstringptr() +
1982 *registers[instr->binaryop.right].getstringptr();
1985 QML_V4_END_INSTR(AddString, binaryop)
1987 QML_V4_BEGIN_INSTR(SubNumber, binaryop)
1989 registers[instr->binaryop.output].setnumber(registers[instr->binaryop.left].getnumber() -
1990 registers[instr->binaryop.right].getnumber());
1992 QML_V4_END_INSTR(SubNumber, binaryop)
1994 QML_V4_BEGIN_INSTR(MulNumber, binaryop)
1996 registers[instr->binaryop.output].setnumber(registers[instr->binaryop.left].getnumber() *
1997 registers[instr->binaryop.right].getnumber());
1999 QML_V4_END_INSTR(MulNumber, binaryop)
2001 QML_V4_BEGIN_INSTR(DivNumber, binaryop)
2003 registers[instr->binaryop.output].setnumber(registers[instr->binaryop.left].getnumber() /
2004 registers[instr->binaryop.right].getnumber());
2006 QML_V4_END_INSTR(DivNumber, binaryop)
2008 QML_V4_BEGIN_INSTR(ModNumber, binaryop)
2010 Register &target = registers[instr->binaryop.output];
2011 const Register &left = registers[instr->binaryop.left];
2012 const Register &right = registers[instr->binaryop.right];
2013 target.setnumber(::fmod(left.getnumber(), right.getnumber()));
2015 QML_V4_END_INSTR(ModInt, binaryop)
2017 QML_V4_BEGIN_INSTR(LShiftInt, binaryop)
2019 registers[instr->binaryop.output].setint(registers[instr->binaryop.left].getint() <<
2020 registers[instr->binaryop.right].getint());
2022 QML_V4_END_INSTR(LShiftInt, binaryop)
2024 QML_V4_BEGIN_INSTR(RShiftInt, binaryop)
2026 registers[instr->binaryop.output].setint(registers[instr->binaryop.left].getint() >>
2027 registers[instr->binaryop.right].getint());
2029 QML_V4_END_INSTR(RShiftInt, binaryop)
2031 QML_V4_BEGIN_INSTR(URShiftInt, binaryop)
2033 registers[instr->binaryop.output].setint((unsigned)registers[instr->binaryop.left].getint() >>
2034 registers[instr->binaryop.right].getint());
2036 QML_V4_END_INSTR(URShiftInt, binaryop)
2038 QML_V4_BEGIN_INSTR(GtNumber, binaryop)
2040 registers[instr->binaryop.output].setbool(registers[instr->binaryop.left].getnumber() >
2041 registers[instr->binaryop.right].getnumber());
2043 QML_V4_END_INSTR(GtNumber, binaryop)
2045 QML_V4_BEGIN_INSTR(LtNumber, binaryop)
2047 registers[instr->binaryop.output].setbool(registers[instr->binaryop.left].getnumber() <
2048 registers[instr->binaryop.right].getnumber());
2050 QML_V4_END_INSTR(LtNumber, binaryop)
2052 QML_V4_BEGIN_INSTR(GeNumber, binaryop)
2054 registers[instr->binaryop.output].setbool(registers[instr->binaryop.left].getnumber() >=
2055 registers[instr->binaryop.right].getnumber());
2057 QML_V4_END_INSTR(GeNumber, binaryop)
2059 QML_V4_BEGIN_INSTR(LeNumber, binaryop)
2061 registers[instr->binaryop.output].setbool(registers[instr->binaryop.left].getnumber() <=
2062 registers[instr->binaryop.right].getnumber());
2064 QML_V4_END_INSTR(LeNumber, binaryop)
2066 QML_V4_BEGIN_INSTR(EqualNumber, binaryop)
2068 registers[instr->binaryop.output].setbool(registers[instr->binaryop.left].getnumber() ==
2069 registers[instr->binaryop.right].getnumber());
2071 QML_V4_END_INSTR(EqualNumber, binaryop)
2073 QML_V4_BEGIN_INSTR(NotEqualNumber, binaryop)
2075 registers[instr->binaryop.output].setbool(registers[instr->binaryop.left].getnumber() !=
2076 registers[instr->binaryop.right].getnumber());
2078 QML_V4_END_INSTR(NotEqualNumber, binaryop)
2080 QML_V4_BEGIN_INSTR(StrictEqualNumber, binaryop)
2082 registers[instr->binaryop.output].setbool(registers[instr->binaryop.left].getnumber() ==
2083 registers[instr->binaryop.right].getnumber());
2085 QML_V4_END_INSTR(StrictEqualNumber, binaryop)
2087 QML_V4_BEGIN_INSTR(StrictNotEqualNumber, binaryop)
2089 registers[instr->binaryop.output].setbool(registers[instr->binaryop.left].getnumber() !=
2090 registers[instr->binaryop.right].getnumber());
2092 QML_V4_END_INSTR(StrictNotEqualNumber, binaryop)
2094 QML_V4_BEGIN_INSTR(GtString, binaryop)
2096 const QString &a = *registers[instr->binaryop.left].getstringptr();
2097 const QString &b = *registers[instr->binaryop.right].getstringptr();
2098 bool result = a > b;
2099 if (instr->binaryop.left == instr->binaryop.output) {
2100 registers[instr->binaryop.output].cleanupString();
2101 MARK_CLEAN_REGISTER(instr->binaryop.output);
2103 registers[instr->binaryop.output].setbool(result);
2105 QML_V4_END_INSTR(GtString, binaryop)
2107 QML_V4_BEGIN_INSTR(LtString, binaryop)
2109 const QString &a = *registers[instr->binaryop.left].getstringptr();
2110 const QString &b = *registers[instr->binaryop.right].getstringptr();
2111 bool result = a < b;
2112 if (instr->binaryop.left == instr->binaryop.output) {
2113 registers[instr->binaryop.output].cleanupString();
2114 MARK_CLEAN_REGISTER(instr->binaryop.output);
2116 registers[instr->binaryop.output].setbool(result);
2118 QML_V4_END_INSTR(LtString, binaryop)
2120 QML_V4_BEGIN_INSTR(GeString, binaryop)
2122 const QString &a = *registers[instr->binaryop.left].getstringptr();
2123 const QString &b = *registers[instr->binaryop.right].getstringptr();
2124 bool result = a >= b;
2125 if (instr->binaryop.left == instr->binaryop.output) {
2126 registers[instr->binaryop.output].cleanupString();
2127 MARK_CLEAN_REGISTER(instr->binaryop.output);
2129 registers[instr->binaryop.output].setbool(result);
2131 QML_V4_END_INSTR(GeString, binaryop)
2133 QML_V4_BEGIN_INSTR(LeString, binaryop)
2135 const QString &a = *registers[instr->binaryop.left].getstringptr();
2136 const QString &b = *registers[instr->binaryop.right].getstringptr();
2137 bool result = a <= b;
2138 if (instr->binaryop.left == instr->binaryop.output) {
2139 registers[instr->binaryop.output].cleanupString();
2140 MARK_CLEAN_REGISTER(instr->binaryop.output);
2142 registers[instr->binaryop.output].setbool(result);
2144 QML_V4_END_INSTR(LeString, binaryop)
2146 QML_V4_BEGIN_INSTR(EqualString, binaryop)
2148 const QString &a = *registers[instr->binaryop.left].getstringptr();
2149 const QString &b = *registers[instr->binaryop.right].getstringptr();
2150 bool result = a == b;
2151 if (instr->binaryop.left == instr->binaryop.output) {
2152 registers[instr->binaryop.output].cleanupString();
2153 MARK_CLEAN_REGISTER(instr->binaryop.output);
2155 registers[instr->binaryop.output].setbool(result);
2157 QML_V4_END_INSTR(EqualString, binaryop)
2159 QML_V4_BEGIN_INSTR(NotEqualString, binaryop)
2161 const QString &a = *registers[instr->binaryop.left].getstringptr();
2162 const QString &b = *registers[instr->binaryop.right].getstringptr();
2163 bool result = a != b;
2164 if (instr->binaryop.left == instr->binaryop.output) {
2165 registers[instr->binaryop.output].cleanupString();
2166 MARK_CLEAN_REGISTER(instr->binaryop.output);
2168 registers[instr->binaryop.output].setbool(result);
2170 QML_V4_END_INSTR(NotEqualString, binaryop)
2172 QML_V4_BEGIN_INSTR(StrictEqualString, binaryop)
2174 const QString &a = *registers[instr->binaryop.left].getstringptr();
2175 const QString &b = *registers[instr->binaryop.right].getstringptr();
2176 bool result = a == b;
2177 if (instr->binaryop.left == instr->binaryop.output) {
2178 registers[instr->binaryop.output].cleanupString();
2179 MARK_CLEAN_REGISTER(instr->binaryop.output);
2181 registers[instr->binaryop.output].setbool(result);
2183 QML_V4_END_INSTR(StrictEqualString, binaryop)
2185 QML_V4_BEGIN_INSTR(StrictNotEqualString, binaryop)
2187 const QString &a = *registers[instr->binaryop.left].getstringptr();
2188 const QString &b = *registers[instr->binaryop.right].getstringptr();
2189 bool result = a != b;
2190 if (instr->binaryop.left == instr->binaryop.output) {
2191 registers[instr->binaryop.output].cleanupString();
2192 MARK_CLEAN_REGISTER(instr->binaryop.output);
2194 registers[instr->binaryop.output].setbool(result);
2196 QML_V4_END_INSTR(StrictNotEqualString, binaryop)
2198 QML_V4_BEGIN_INSTR(EqualObject, binaryop)
2200 const Register &left = registers[instr->binaryop.left];
2201 const Register &right = registers[instr->binaryop.right];
2202 QObject *leftobj = (left.gettype() == NullType) ? 0 : left.getQObject();
2203 QObject *rightobj = (right.gettype() == NullType) ? 0 : right.getQObject();
2204 registers[instr->binaryop.output].setbool(leftobj == rightobj);
2206 QML_V4_END_INSTR(EqualObject, binaryop)
2208 QML_V4_BEGIN_INSTR(NotEqualObject, binaryop)
2210 const Register &left = registers[instr->binaryop.left];
2211 const Register &right = registers[instr->binaryop.right];
2212 QObject *leftobj = (left.gettype() == NullType) ? 0 : left.getQObject();
2213 QObject *rightobj = (right.gettype() == NullType) ? 0 : right.getQObject();
2214 registers[instr->binaryop.output].setbool(leftobj != rightobj);
2216 QML_V4_END_INSTR(NotEqualObject, binaryop)
2218 QML_V4_BEGIN_INSTR(StrictEqualObject, binaryop)
2220 const Register &left = registers[instr->binaryop.left];
2221 const Register &right = registers[instr->binaryop.right];
2222 QObject *leftobj = (left.gettype() == NullType) ? 0 : left.getQObject();
2223 QObject *rightobj = (right.gettype() == NullType) ? 0 : right.getQObject();
2224 registers[instr->binaryop.output].setbool(leftobj == rightobj);
2226 QML_V4_END_INSTR(StrictEqualObject, binaryop)
2228 QML_V4_BEGIN_INSTR(StrictNotEqualObject, binaryop)
2230 const Register &left = registers[instr->binaryop.left];
2231 const Register &right = registers[instr->binaryop.right];
2232 QObject *leftobj = (left.gettype() == NullType) ? 0 : left.getQObject();
2233 QObject *rightobj = (right.gettype() == NullType) ? 0 : right.getQObject();
2234 registers[instr->binaryop.output].setbool(leftobj != rightobj);
2236 QML_V4_END_INSTR(StrictNotEqualObject, binaryop)
2238 QML_V4_BEGIN_INSTR(MathMaxNumber, binaryop)
2240 const Register &left = registers[instr->binaryop.left];
2241 const Register &right = registers[instr->binaryop.right];
2242 Register &output = registers[instr->binaryop.output];
2243 if (left.isUndefined() || right.isUndefined()) {
2244 output.setUndefined();
2246 const double lhs = left.getnumber();
2247 const double rhs = right.getnumber();
2250 // If these are both zero, +0 is greater than -0
2251 if (signBitSet(lhs) && !signBitSet(rhs))
2254 result = qMax(lhs, rhs);
2256 output.setnumber(result);
2259 QML_V4_END_INSTR(MathMaxNumber, binaryop)
2261 QML_V4_BEGIN_INSTR(MathMinNumber, binaryop)
2263 const Register &left = registers[instr->binaryop.left];
2264 const Register &right = registers[instr->binaryop.right];
2265 Register &output = registers[instr->binaryop.output];
2266 if (left.isUndefined() || right.isUndefined()) {
2267 output.setUndefined();
2269 const double lhs = left.getnumber();
2270 const double rhs = right.getnumber();
2273 // If these are both zero, -0 is lesser than +0
2274 if (!signBitSet(lhs) && signBitSet(rhs))
2277 result = qMin(lhs, rhs);
2279 output.setnumber(result);
2282 QML_V4_END_INSTR(MathMinNumber, binaryop)
2284 QML_V4_BEGIN_INSTR(NewString, construct)
2286 Register &output = registers[instr->construct.reg];
2287 new (output.getstringptr()) QString;
2288 STRING_REGISTER(instr->construct.reg);
2290 QML_V4_END_INSTR(NewString, construct)
2292 QML_V4_BEGIN_INSTR(NewUrl, construct)
2294 Register &output = registers[instr->construct.reg];
2295 new (output.geturlptr()) QUrl;
2296 URL_REGISTER(instr->construct.reg);
2298 QML_V4_END_INSTR(NewUrl, construct)
2300 QML_V4_BEGIN_INSTR(Fetch, fetch)
2302 Register ® = registers[instr->fetch.reg];
2304 if (reg.isUndefined())
2305 THROW_EXCEPTION(instr->fetch.exceptionId);
2307 QObject *object = reg.getQObject();
2309 THROW_EXCEPTION(instr->fetch.exceptionId);
2311 INVALIDATION_CHECK(invalidated, object, instr->fetch.index);
2313 const Register::Type valueType = (Register::Type)instr->fetch.valueType;
2314 reg.init(valueType);
2315 if (instr->fetch.valueType >= FirstCleanupType)
2316 MARK_REGISTER(instr->fetch.reg);
2317 void *argv[] = { reg.typeDataPtr(), 0 };
2318 QMetaObject::metacall(object, QMetaObject::ReadProperty, instr->fetch.index, argv);
2319 if (valueType == FloatType) {
2321 const double v = reg.getfloat();
2326 QML_V4_END_INSTR(Fetch, fetch)
2328 QML_V4_BEGIN_INSTR(TestV4Store, storetest)
2330 Register &data = registers[instr->storetest.reg];
2331 testBindingResult(*testBindingSource, bindingLine, bindingColumn, context,
2332 scope, data, instr->storetest.regType);
2334 QML_V4_END_INSTR(TestV4Store, storetest)
2336 QML_V4_BEGIN_INSTR(Store, store)
2338 Register &data = registers[instr->store.reg];
2340 if (data.isUndefined())
2341 THROW_EXCEPTION_STR(instr->store.exceptionId, QLatin1String("Unable to assign undefined value"));
2343 if (data.gettype() == QObjectStarType) {
2344 if (QObject *dataObject = data.getQObject()) {
2345 QQmlMetaObject dataMo(dataObject);
2347 QQmlEnginePrivate *ep = QQmlEnginePrivate::get(context->engine);
2349 QQmlMetaObject receiverMo;
2351 if (QQmlData::get(output, false) && QQmlData::get(output, false)->propertyCache) {
2352 QQmlPropertyData *receiver =
2353 QQmlData::get(output, false)->propertyCache->property(instr->store.index);
2354 receiverMo = ep->rawMetaObjectForType(receiver->propType);
2356 QMetaProperty receiver = output->metaObject()->property(instr->store.index);
2357 receiverMo = ep->rawMetaObjectForType(receiver.userType());
2360 // Verify that these types are compatible
2361 if (!QQmlMetaObject::canConvert(dataMo, receiverMo)) {
2362 THROW_EXCEPTION_STR(instr->store.exceptionId, QLatin1String("Unable to assign ") +
2363 QLatin1String(dataMo.className()) +
2364 QLatin1String(" to ") +
2365 QLatin1String(receiverMo.className()));
2370 if (instr->store.valueType == FloatType) {
2371 // cast numbers to floats
2372 const float v = (float) data.getnumber();
2376 if (data.gettype() == V8HandleType) {
2377 // This property must be a VME var property
2378 QQmlVMEMetaObject *vmemo = QQmlVMEMetaObject::get(output);
2380 vmemo->setVMEProperty(instr->store.index, *data.gethandleptr());
2383 void *argv[] = { data.typeDataPtr(), 0, &status, &storeFlags };
2384 QMetaObject::metacall(output, QMetaObject::WriteProperty,
2385 instr->store.index, argv);
2390 QML_V4_END_INSTR(Store, store)
2392 QML_V4_BEGIN_INSTR(Copy, copy)
2393 registers[instr->copy.reg].copy(registers[instr->copy.src]);
2394 if (registers[instr->copy.reg].gettype() >= FirstCleanupType)
2395 MARK_REGISTER(instr->copy.reg);
2396 QML_V4_END_INSTR(Copy, copy)
2398 QML_V4_BEGIN_INSTR(Jump, jump)
2399 if (instr->jump.reg == -1 || !registers[instr->jump.reg].getbool())
2400 code += instr->jump.count;
2401 QML_V4_END_INSTR(Jump, jump)
2403 QML_V4_BEGIN_INSTR(BranchTrue, branchop)
2404 if (registers[instr->branchop.reg].getbool())
2405 code += instr->branchop.offset;
2406 QML_V4_END_INSTR(BranchTrue, branchop)
2408 QML_V4_BEGIN_INSTR(BranchFalse, branchop)
2409 if (! registers[instr->branchop.reg].getbool())
2410 code += instr->branchop.offset;
2411 QML_V4_END_INSTR(BranchFalse, branchop)
2413 QML_V4_BEGIN_INSTR(Branch, branchop)
2414 code += instr->branchop.offset;
2415 QML_V4_END_INSTR(Branch, branchop)
2417 QML_V4_BEGIN_INSTR(Block, blockop)
2418 executedBlocks |= instr->blockop.block;
2419 QML_V4_END_INSTR(Block, blockop)
2421 QML_V4_BEGIN_INSTR(CleanupRegister, cleanup)
2422 registers[instr->cleanup.reg].cleanup();
2423 QML_V4_END_INSTR(CleanupRegister, cleanup)
2425 QML_V4_BEGIN_INSTR(Throw, throwop)
2426 THROW_VALUE_EXCEPTION_STR(instr->throwop.exceptionId, *registers[instr->throwop.message].getstringptr());
2427 QML_V4_END_INSTR(Throw, throwop)
2429 #ifdef QML_THREADED_INTERPRETER
2433 qFatal("QV4: Unknown instruction %d encountered.", instr->common.type);
2440 Q_ASSERT(!"Unreachable code reached");
2444 delete testBindingSource;
2447 while (cleanupRegisterMask) {
2448 if (cleanupRegisterMask & 0x1)
2449 registers[reg].cleanup();
2452 cleanupRegisterMask >>= 1;