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)
74 // MSVC2010 warns about 'unreferenced formal parameter', even if it's used in p->~T()
75 # pragma warning( disable : 4100 )
80 using namespace QQmlJS;
82 QQmlAbstractBinding::VTable QV4Bindings_Binding_vtable = {
83 QV4Bindings::Binding::destroy,
84 QQmlAbstractBinding::default_expression,
85 QV4Bindings::Binding::propertyIndex,
86 QV4Bindings::Binding::object,
87 QV4Bindings::Binding::setEnabled,
88 QV4Bindings::Binding::update,
89 QV4Bindings::Binding::retargetBinding
94 // The highest bit is the sign bit, in any endianness
95 static const quint64 doubleSignMask = (quint64(0x1) << 63);
97 inline bool signBitSet(const double &v)
99 union { double d; quint64 u; } u;
101 return (u.u & doubleSignMask);
104 inline double setSignBit(const double &v, bool b = true)
106 union { double d; quint64 u; } u;
110 u.u |= doubleSignMask;
112 u.u &= ~doubleSignMask;
117 inline double clearSignBit(const double &v, bool b = true)
119 return setSignBit(v, !b);
123 typedef QQmlRegisterType Type;
125 enum SpecialNumericValue {
127 PositiveInfinity = 2,
128 NegativeInfinity = 3,
132 inline void setUndefined() { dataType = UndefinedType; }
133 inline bool isUndefined() const { return dataType == UndefinedType; }
135 inline void setNull() { dataType = NullType; }
137 inline void setNaN() { setnumber(qSNaN()); }
138 inline void setNaNType() { dataType = SpecialNumericType; intValue = NotANumber; } // non-numeric representation of NaN
139 inline bool isNaN() const { return (((dataType == SpecialNumericType) && (intValue == NotANumber)) ||
140 ((dataType == NumberType) && qIsNaN(numberValue))); }
142 inline void setInf(bool negative) { setnumber(setSignBit(qInf(), negative)); }
143 inline void setInfType(bool negative) { dataType = SpecialNumericType; intValue = (negative ? NegativeInfinity : PositiveInfinity); } // non-numeric representation of Inf
144 inline bool isInf() const { return (((dataType == SpecialNumericType) && ((intValue == NegativeInfinity) || (intValue == PositiveInfinity))) ||
145 ((dataType == NumberType) && qIsInf(numberValue))); }
147 inline void setNegativeZero() { setnumber(setSignBit(0)); }
148 inline void setNegativeZeroType() { dataType = SpecialNumericType; intValue = NegativeZero; } // non-numeric representation of -0
149 inline bool isNegativeZero() const { return (((dataType == SpecialNumericType) && (intValue == NegativeZero)) ||
150 ((dataType == NumberType) && (numberValue == 0) && signBitSet(numberValue))); }
152 inline void setQObject(QObject *o) { qobjectValue = o; dataType = QObjectStarType; }
153 inline QObject *getQObject() const { return qobjectValue; }
155 inline void setnumber(double v) { numberValue = v; dataType = NumberType; }
156 inline double getnumber() const { return numberValue; }
157 inline double &getnumberref() { return numberValue; }
159 inline void setfloat(float v) { floatValue = v; dataType = FloatType; }
160 inline float getfloat() const { return floatValue; }
161 inline float &getfloatref() { return floatValue; }
163 inline void setint(int v) { intValue = v; dataType = IntType; }
164 inline int getint() const { return intValue; }
165 inline int &getintref() { return intValue; }
167 inline void setbool(bool v) { boolValue = v; dataType = BoolType; }
168 inline bool getbool() const { return boolValue; }
169 inline bool &getboolref() { return boolValue; }
171 inline QVariant *getvariantptr() { return reinterpret_cast<QVariant *>(typeDataPtr()); }
172 inline QString *getstringptr() { return reinterpret_cast<QString *>(typeDataPtr()); }
173 inline QUrl *geturlptr() { return reinterpret_cast<QUrl *>(typeDataPtr()); }
174 inline v8::Handle<v8::Value> *gethandleptr() { return reinterpret_cast<v8::Handle<v8::Value> *>(typeDataPtr()); }
175 inline QJSValue *getjsvalueptr() { return reinterpret_cast<QJSValue *>(typeDataPtr()); }
177 inline const QVariant *getvariantptr() const { return reinterpret_cast<const QVariant *>(typeDataPtr()); }
178 inline const QString *getstringptr() const { return reinterpret_cast<const QString *>(typeDataPtr()); }
179 inline const QUrl *geturlptr() const { return reinterpret_cast<const QUrl *>(typeDataPtr()); }
180 inline const v8::Handle<v8::Value> *gethandleptr() const { return reinterpret_cast<const v8::Handle<v8::Value> *>(typeDataPtr()); }
181 inline const QJSValue *getjsvalueptr() const { return reinterpret_cast<const QJSValue *>(typeDataPtr()); }
183 size_t dataSize() { return sizeof(data); }
184 inline void *typeDataPtr() { return (void *)&data; }
185 inline void *typeMemory() { return (void *)data; }
186 inline const void *typeDataPtr() const { return (void *)&data; }
187 inline const void *typeMemory() const { return (void *)data; }
189 inline Type gettype() const { return dataType; }
190 inline void settype(Type t) { dataType = t; }
192 Type dataType; // Type of data
194 QObject *qobjectValue;
199 void *data[sizeof(QVariant)];
200 qint64 q_for_alignment_1;
201 double q_for_alignment_2;
204 inline void cleanup();
205 inline void cleanupString();
206 inline void cleanupUrl();
207 inline void cleanupColor();
208 inline void cleanupVariant();
209 inline void cleanupHandle();
210 inline void cleanupJSValue();
212 inline void copy(const Register &other);
213 inline void init(Type type);
214 #ifdef REGISTER_CLEANUP_DEBUG
220 if (dataType >= FirstCleanupType)
221 qWarning("Register leaked of type %d", dataType);
225 template <typename T>
226 inline static void copyConstructPointee(T *p, const T *other)
231 template <typename T>
232 inline static void defaultConstructPointee(T *p)
237 template <typename T>
238 inline static void destroyPointee(T *p)
244 void Register::cleanup()
246 if (dataType >= FirstCleanupType) {
247 if (dataType == QStringType) {
248 destroyPointee(getstringptr());
249 } else if (dataType == QUrlType) {
250 destroyPointee(geturlptr());
251 } else if (dataType == QColorType) {
252 QQml_valueTypeProvider()->destroyValueType(QMetaType::QColor, typeDataPtr(), dataSize());
253 } else if (dataType == QVariantType) {
254 destroyPointee(getvariantptr());
255 } else if (dataType == qMetaTypeId<v8::Handle<v8::Value> >()) {
256 destroyPointee(gethandleptr());
257 } else if (dataType == qMetaTypeId<QJSValue>()) {
258 destroyPointee(getjsvalueptr());
264 void Register::cleanupString()
266 destroyPointee(getstringptr());
270 void Register::cleanupUrl()
272 destroyPointee(geturlptr());
276 void Register::cleanupColor()
278 QQml_valueTypeProvider()->destroyValueType(QMetaType::QColor, typeDataPtr(), dataSize());
282 void Register::cleanupVariant()
284 destroyPointee(getvariantptr());
288 void Register::cleanupHandle()
290 destroyPointee(gethandleptr());
294 void Register::cleanupJSValue()
296 destroyPointee(getjsvalueptr());
300 void Register::copy(const Register &other)
303 if (other.dataType >= FirstCleanupType) {
304 if (other.dataType == QStringType)
305 copyConstructPointee(getstringptr(), other.getstringptr());
306 else if (other.dataType == QUrlType)
307 copyConstructPointee(geturlptr(), other.geturlptr());
308 else if (other.dataType == QColorType)
309 QQml_valueTypeProvider()->copyValueType(QMetaType::QColor, other.typeDataPtr(), typeDataPtr(), dataSize());
310 else if (other.dataType == QVariantType)
311 copyConstructPointee(getvariantptr(), other.getvariantptr());
312 else if (other.dataType == qMetaTypeId<v8::Handle<v8::Value> >())
313 copyConstructPointee(gethandleptr(), other.gethandleptr());
314 else if (other.dataType == qMetaTypeId<QJSValue>())
315 copyConstructPointee(getjsvalueptr(), other.getjsvalueptr());
319 void Register::init(Type type)
322 if (dataType >= FirstCleanupType) {
323 if (dataType == QStringType)
324 defaultConstructPointee(getstringptr());
325 else if (dataType == QUrlType)
326 defaultConstructPointee(geturlptr());
327 else if (dataType == QColorType)
328 QQml_valueTypeProvider()->initValueType(QMetaType::QColor, typeDataPtr(), dataSize());
329 else if (dataType == QVariantType)
330 defaultConstructPointee(getvariantptr());
331 else if (dataType == qMetaTypeId<v8::Handle<v8::Value> >())
332 defaultConstructPointee(gethandleptr());
333 else if (dataType == qMetaTypeId<QJSValue>())
334 defaultConstructPointee(getjsvalueptr());
338 } // end of anonymous namespace
340 QV4Bindings::QV4Bindings(const char *programData, QQmlContextData *context)
341 : subscriptions(0), program(0), bindings(0)
343 program = (QV4Program *)programData;
345 subscriptions = new Subscription[program->subscriptions];
346 bindings = new Binding[program->bindings];
348 QQmlAbstractExpression::setContext(context);
352 QV4Bindings::~QV4Bindings()
354 delete [] bindings; bindings = 0;
355 delete [] subscriptions; subscriptions = 0;
358 QQmlAbstractBinding *QV4Bindings::configBinding(QObject *target, QObject *scope,
359 const QQmlInstruction::instr_assignV4Binding *i)
361 Binding *rv = bindings + i->value;
368 addref(); // This is decremented in Binding::destroy()
373 void QV4Bindings::Binding::setEnabled(QQmlAbstractBinding *_This,
374 bool e, QQmlPropertyPrivate::WriteFlags flags)
376 QV4Bindings::Binding *This = static_cast<QV4Bindings::Binding *>(_This);
378 if (This->enabledFlag() != e) {
379 This->setEnabledFlag(e);
381 if (e) update(_This, flags);
385 void QV4Bindings::Binding::update(QQmlAbstractBinding *_This, QQmlPropertyPrivate::WriteFlags flags)
387 QV4Bindings::Binding *This = static_cast<QV4Bindings::Binding *>(_This);
388 This->parent->run(This, flags);
391 void QV4Bindings::Binding::destroy(QQmlAbstractBinding *_This, QQmlAbstractBinding::DestroyMode mode)
393 QV4Bindings::Binding *This = static_cast<QV4Bindings::Binding *>(_This);
395 if (mode == QQmlAbstractBinding::DisconnectBinding)
398 This->setEnabledFlag(false);
399 This->removeFromObject();
402 This->parent->release();
405 int QV4Bindings::Binding::propertyIndex(const QQmlAbstractBinding *_This)
407 const QV4Bindings::Binding *This = static_cast<const QV4Bindings::Binding *>(_This);
409 if (This->target.hasValue()) return This->target.constValue()->targetProperty;
410 else return This->instruction->property;
413 QObject *QV4Bindings::Binding::object(const QQmlAbstractBinding *_This)
415 const QV4Bindings::Binding *This = static_cast<const QV4Bindings::Binding *>(_This);
417 if (This->target.hasValue()) return This->target.constValue()->target;
418 return *This->target;
421 void QV4Bindings::Binding::retargetBinding(QQmlAbstractBinding *_This, QObject *t, int i)
423 QV4Bindings::Binding *This = static_cast<QV4Bindings::Binding *>(_This);
425 This->target.value().target = t;
426 This->target.value().targetProperty = i;
429 void QV4Bindings::Binding::disconnect()
431 // We iterate over the signal table to find all subscriptions associated with this binding.
432 // This is slow, but disconnect() is not called in the common case, only in special cases
433 // like when the binding is overwritten.
434 QV4Program * const program = parent->program;
435 for (quint16 subIndex = 0; subIndex < program->subscriptions; subIndex++) {
436 QV4Program::BindingReferenceList * const list = program->signalTable(subIndex);
437 for (quint32 bindingIndex = 0; bindingIndex < list->count; ++bindingIndex) {
438 QV4Program::BindingReference * const bindingRef = list->bindings + bindingIndex;
439 Binding * const binding = parent->bindings + bindingRef->binding;
440 if (binding == this) {
441 Subscription * const sub = parent->subscriptions + subIndex;
443 sub->setActive(false);
451 void QV4Bindings::Binding::dump()
453 qWarning() << parent->context()->url << instruction->line << instruction->column;
456 QV4Bindings::Subscription::Subscription()
459 setCallback(QQmlNotifierEndpoint::QV4BindingsSubscription);
462 int QV4Bindings::Subscription::method() const
464 Q_ASSERT(bindings() != 0);
465 return (this - bindings()->subscriptions);
468 void QV4Bindings::Subscription::setBindings(QV4Bindings *bindings)
470 m_bindings = bindings;
473 QV4Bindings *QV4Bindings::Subscription::bindings() const
478 bool QV4Bindings::Subscription::active() const
480 return m_bindings.flag();
483 void QV4Bindings::Subscription::setActive(bool active)
485 m_bindings.setFlagValue(active);
488 void QV4BindingsSubscription_callback(QQmlNotifierEndpoint *e, void **)
490 QV4Bindings::Subscription *s = static_cast<QV4Bindings::Subscription *>(e);
491 Q_ASSERT(s->bindings());
492 s->bindings()->subscriptionNotify(s->method());
495 void QV4Bindings::subscriptionNotify(int id)
497 QV4Program::BindingReferenceList *list = program->signalTable(id);
499 for (quint32 ii = 0; ii < list->count; ++ii) {
500 QV4Program::BindingReference *bindingRef = list->bindings + ii;
502 Binding *binding = bindings + bindingRef->binding;
504 if (binding->executedBlocks & bindingRef->blockMask) {
505 run(binding, QQmlPropertyPrivate::DontRemoveBinding);
510 void QV4Bindings::run(Binding *binding, QQmlPropertyPrivate::WriteFlags flags)
512 if (!binding->enabledFlag())
515 QQmlContextData *context = QQmlAbstractExpression::context();
516 if (!context || !context->isValid())
519 // Check that the target has not been deleted
520 if (QQmlData::wasDeleted(*binding->target))
523 QQmlTrace trace("V4 Binding Update");
524 trace.addDetail("URL", context->url);
525 trace.addDetail("Line", binding->instruction->line);
526 trace.addDetail("Column", binding->instruction->column);
528 QQmlBindingProfiler prof(context->urlString, binding->instruction->line, binding->instruction->column, QQmlProfilerService::V4Binding);
530 const int propType = binding->instruction->propType;
531 const int property = binding->instruction->property;
533 if (binding->updatingFlag()) {
536 QQmlValueType *vt = QQmlValueTypeFactory::valueType(propType);
539 name = QLatin1String(binding->target->metaObject()->property(property & 0x0000FFFF).name());
540 name.append(QLatin1Char('.'));
541 name.append(QLatin1String(vt->metaObject()->property(property >> 16).name()));
543 name = QLatin1String(binding->target->metaObject()->property(property).name());
545 qmlInfo(*binding->target) << tr("Binding loop detected for property \"%1\"").arg(name);
549 int index = binding->instruction->value;
550 int fallbackIndex = binding->instruction->fallbackValue;
552 bool invalidated = false;
553 bool *inv = (fallbackIndex != -1) ? &invalidated : 0;
555 binding->setUpdatingFlag(true);
557 QQmlValueType *vt = QQmlValueTypeFactory::valueType(propType);
559 vt->read(*binding->target, property & 0x0000FFFF);
561 QObject *target = vt;
562 run(index, binding->executedBlocks, context, binding, binding->scope, target, flags, inv);
565 vt->write(*binding->target, property & 0x0000FFFF, flags);
568 QQmlData *data = QQmlData::get(*binding->target);
569 QQmlPropertyData *propertyData = (data && data->propertyCache ? data->propertyCache->property(property) : 0);
571 if (propertyData && propertyData->isVarProperty()) {
572 // We will allocate a V8 handle in this conversion/store
573 v8::HandleScope handle_scope;
574 v8::Context::Scope context_scope(QQmlEnginePrivate::get(context->engine)->v8engine()->context());
576 run(index, binding->executedBlocks, context, binding, binding->scope, *binding->target, flags, inv);
578 run(index, binding->executedBlocks, context, binding, binding->scope, *binding->target, flags, inv);
581 binding->setUpdatingFlag(false);
584 // This binding is no longer valid - fallback to V8
585 Q_ASSERT(fallbackIndex > -1);
586 QQmlAbstractBinding *b = QQmlPropertyPrivate::activateSharedBinding(context, fallbackIndex, flags);
587 Q_ASSERT(b == binding);
592 void QV4Bindings::subscribeId(QQmlContextData *p, int idIndex, int subIndex)
594 Subscription *sub = (subscriptions + subIndex);
597 if (p->idValues[idIndex]) {
598 sub->setBindings(this);
599 sub->connect(&p->idValues[idIndex].bindings);
600 sub->setActive(true);
602 sub->setActive(false);
606 void QV4Bindings::subscribe(QObject *o, int notifyIndex, int subIndex, QQmlEngine *e)
608 Subscription *sub = (subscriptions + subIndex);
609 if (sub->isConnected(o, notifyIndex))
611 sub->setBindings(this);
613 sub->connect(o, notifyIndex, e);
614 sub->setActive(true);
617 sub->setActive(false);
621 static bool testCompareVariants(const QVariant &qtscriptRaw, const QVariant &v4)
623 QVariant qtscript = qtscriptRaw;
625 if (qtscript.userType() == v4.userType()) {
626 } else if (qtscript.canConvert(v4.userType())) {
627 qtscript.convert(v4.userType());
628 } else if (qtscript.userType() == QVariant::Invalid && v4.userType() == QMetaType::QObjectStar) {
629 qtscript = qVariantFromValue<QObject *>(0);
634 int type = qtscript.userType();
636 if (type == QQmlMetaType::QQuickAnchorLineMetaTypeId()) {
637 return QQmlMetaType::QQuickAnchorLineCompare(qtscript.constData(), v4.constData());
638 } else if (type == QMetaType::Double) {
640 double la = qvariant_cast<double>(qtscript);
641 double lr = qvariant_cast<double>(v4);
643 return la == lr || (qIsNaN(la) && qIsNaN(lr));
645 } else if (type == QMetaType::Float) {
647 float la = qvariant_cast<float>(qtscript);
648 float lr = qvariant_cast<float>(v4);
650 return la == lr || (qIsNaN(la) && qIsNaN(lr));
653 return qtscript == v4;
657 QByteArray testResultToString(const QVariant &result, bool undefined)
669 static void testBindingResult(const QString &binding, quint16 line, quint16 column,
670 QQmlContextData *context, QObject *scope,
671 const Register &result, int resultType)
673 QQmlExpression expression(context->asQQmlContext(), scope, binding);
674 bool isUndefined = false;
675 QVariant value = expression.evaluate(&isUndefined);
677 bool iserror = false;
678 QByteArray qtscriptResult;
681 const int handleType = qMetaTypeId<v8::Handle<v8::Value> >();
683 if (expression.hasError()) {
685 qtscriptResult = "exception";
686 } else if ((value.userType() != resultType) &&
687 (resultType != QMetaType::QVariant) &&
688 (resultType != qMetaTypeId<QJSValue>()) &&
689 (resultType != handleType)) {
690 // Override the QMetaType conversions to make them more JS friendly.
691 if (value.userType() == QMetaType::Double && (resultType == QMetaType::QString ||
692 resultType == QMetaType::QUrl)) {
693 // number to string-like conversion.
694 value = QVariant::fromValue<QString>(QString::number(value.toDouble(), 'g', 16));
695 } else if (value.userType() == QMetaType::QUrl && resultType == QMetaType::Bool) {
696 // url to bool conversion
697 value = QVariant::fromValue<bool>(!value.toUrl().isEmpty());
700 if (!value.isNull() && !value.convert(resultType)) {
702 qtscriptResult = "exception";
703 } else if (resultType == QMetaType::QUrl) {
704 // a V8 value was converted to QUrl.
705 value = QVariant::fromValue<QUrl>(context->resolvedUrl(value.toUrl()));
710 qtscriptResult = testResultToString(value, isUndefined);
712 if (isUndefined && result.isUndefined()) {
714 } else if(isUndefined != result.isUndefined()) {
719 if (!result.isUndefined()) {
720 switch (resultType) {
721 case QMetaType::QString:
722 v4value = *result.getstringptr();
724 case QMetaType::QUrl:
725 v4value = *result.geturlptr();
727 case QMetaType::QObjectStar:
728 v4value = qVariantFromValue<QObject *>(result.getQObject());
730 case QMetaType::Bool:
731 v4value = result.getbool();
734 v4value = result.getint();
736 case QMetaType::Double:
737 v4value = result.getnumber();
739 case QMetaType::QColor:
740 v4value = QVariant(QMetaType::QColor, result.typeDataPtr());
742 case QMetaType::QVariant:
743 v4value = *result.getvariantptr();
746 if (resultType == QQmlMetaType::QQuickAnchorLineMetaTypeId()) {
747 v4value = QVariant(QQmlMetaType::QQuickAnchorLineMetaTypeId(), result.typeDataPtr());
748 } else if (resultType == qMetaTypeId<QJSValue>()) {
749 v4value = result.getjsvalueptr()->toVariant();
750 } else if (resultType == handleType) {
751 QQmlEnginePrivate *ep = QQmlEnginePrivate::get(context->engine);
752 v4value = ep->v8engine()->toVariant(*result.gethandleptr(), resultType);
755 v4Result = "Unknown V4 type";
759 if (v4Result.isEmpty())
760 v4Result = testResultToString(v4value, result.isUndefined());
762 if (!testCompareVariants(value, v4value))
766 qWarning().nospace() << "QV4: Optimization error @" << context->url.toString().toUtf8().constData() << ':' << line << ':' << column;
768 qWarning().nospace() << " Binding: " << binding;
769 qWarning().nospace() << " QtScript: " << qtscriptResult.constData();
770 qWarning().nospace() << " V4: " << v4Result.constData();
774 static void testBindingException(const QString &binding, quint16 line, quint16 column,
775 QQmlContextData *context, QObject *scope)
777 QQmlExpression expression(context->asQQmlContext(), scope, binding);
778 bool isUndefined = false;
779 QVariant value = expression.evaluate(&isUndefined);
781 if (!expression.hasError()) {
782 QByteArray qtscriptResult = testResultToString(value, isUndefined);
783 qWarning().nospace() << "QV4: Optimization error @" << context->url.toString().toUtf8().constData() << ':' << line << ':' << column;
784 qWarning().nospace() << " Binding: " << binding;
785 qWarning().nospace() << " QtScript: " << qtscriptResult.constData();
786 qWarning().nospace() << " V4: exception";
790 static void throwException(int id, QQmlDelayedError *error,
791 QV4Program *program, QQmlContextData *context,
792 const QString &description = QString())
794 if (description.isEmpty())
795 error->setErrorDescription(QLatin1String("TypeError: Result of expression is not an object"));
797 error->setErrorDescription(description);
799 quint32 e = *((quint32 *)(program->data() + program->exceptionDataOffset) + id);
800 error->setErrorLocation(context->url, (e >> 16), (e & 0xFFFF));
802 error->setErrorLocation(context->url, -1, -1);
804 if (!context->engine || !error->addError(QQmlEnginePrivate::get(context->engine)))
805 QQmlEnginePrivate::warning(context->engine, error);
808 const double QV4Bindings::D32 = 4294967296.0;
810 qint32 QV4Bindings::toInt32(double n)
812 if (qIsNaN(n) || qIsInf(n) || (n == 0))
815 double sign = (n < 0) ? -1.0 : 1.0;
816 double abs_n = fabs(n);
818 n = ::fmod(sign * ::floor(abs_n), D32);
819 const double D31 = D32 / 2.0;
821 if (sign == -1 && n < -D31)
824 else if (sign != -1 && n >= D31)
830 inline quint32 QV4Bindings::toUint32(double n)
832 if (qIsNaN(n) || qIsInf(n) || (n == 0))
835 double sign = (n < 0) ? -1.0 : 1.0;
836 double abs_n = fabs(n);
838 n = ::fmod(sign * ::floor(abs_n), D32);
846 #define THROW_EXCEPTION_STR(id, str) { \
847 if (testBinding) testBindingException(*testBindingSource, bindingLine, bindingColumn, context, scope); \
848 throwException((id), error, program, context, (str)); \
849 goto exceptionExit; \
852 #define THROW_VALUE_EXCEPTION_STR(id, str) { \
853 throwException((id), error, program, context, (str)); \
854 goto exceptionExit; \
857 #define THROW_EXCEPTION(id) THROW_EXCEPTION_STR(id, QString())
859 #define MARK_REGISTER(reg) cleanupRegisterMask |= (1 << (reg))
860 #define MARK_CLEAN_REGISTER(reg) cleanupRegisterMask &= ~(1 << (reg))
862 #define STRING_REGISTER(reg) { \
863 registers[(reg)].settype(QStringType); \
864 MARK_REGISTER(reg); \
867 #define URL_REGISTER(reg) { \
868 registers[(reg)].settype(QUrlType); \
869 MARK_REGISTER(reg); \
872 #define COLOR_REGISTER(reg) { \
873 registers[(reg)].settype(QColorType); \
874 MARK_REGISTER(reg); \
877 #define VARIANT_REGISTER(reg) { \
878 registers[(reg)].settype(QVariantType); \
879 MARK_REGISTER(reg); \
882 #define V8HANDLE_REGISTER(reg) { \
883 registers[(reg)].settype(V8HandleType); \
884 MARK_REGISTER(reg); \
887 #define JSVALUE_REGISTER(reg) { \
888 registers[(reg)].settype(QJSValueType); \
889 MARK_REGISTER(reg); \
894 bool bindingInvalidated(bool *invalidated, QObject *obj, QQmlContextData *context, int index)
896 if (invalidated != 0) {
897 if (QQmlData *data = QQmlData::get(obj, true)) {
898 if (!data->propertyCache) {
899 data->propertyCache = QQmlEnginePrivate::get(context->engine)->cache(obj);
900 if (data->propertyCache) data->propertyCache->addref();
903 if (QQmlPropertyData *prop = data->propertyCache ? data->propertyCache->property(index) : 0) {
904 if (prop->isOverridden()) {
905 // TODO: avoid construction of name and name-based lookup
906 int resolvedIndex = data->propertyCache->property(prop->name(obj), obj, context)->coreIndex;
907 if (index < resolvedIndex) {
921 #ifdef QML_THREADED_INTERPRETER
922 void **QV4Bindings::getDecodeInstrTable()
924 static void **decode_instr;
926 QV4Bindings *dummy = new QV4Bindings(0, 0);
927 quint32 executedBlocks = 0;
928 dummy->run(0, executedBlocks, 0, 0, 0, 0,
929 QQmlPropertyPrivate::BypassInterceptor,
937 void QV4Bindings::run(int instrIndex, quint32 &executedBlocks,
938 QQmlContextData *context, QQmlDelayedError *error,
939 QObject *scope, QObject *output,
940 QQmlPropertyPrivate::WriteFlags storeFlags,
942 #ifdef QML_THREADED_INTERPRETER
947 #ifdef QML_THREADED_INTERPRETER
949 static void *decode_instr[] = {
950 FOR_EACH_V4_INSTR(QML_V4_INSTR_ADDR)
953 *table = decode_instr;
959 error->removeError();
961 Register registers[32];
962 quint32 cleanupRegisterMask = 0;
966 const char *code = program->instructions();
967 code += instrIndex * QML_V4_INSTR_SIZE(Jump, jump);
968 const V4Instr *instr = reinterpret_cast<const V4Instr *>(code);
970 const char *data = program->data();
972 QString *testBindingSource = 0;
973 bool testBinding = false;
975 int bindingColumn = 0;
977 #ifdef QML_THREADED_INTERPRETER
978 goto *instr->common.code;
981 switch (instr->common.type) {
984 QML_V4_BEGIN_INSTR(Noop, common)
985 QML_V4_END_INSTR(Noop, common)
987 QML_V4_BEGIN_INSTR(BindingId, id)
988 bindingLine = instr->id.line;
989 bindingColumn = instr->id.column;
990 QML_V4_END_INSTR(BindingId, id)
992 QML_V4_BEGIN_INSTR(SubscribeId, subscribeop)
993 subscribeId(context, instr->subscribeop.index, instr->subscribeop.offset);
994 QML_V4_END_INSTR(SubscribeId, subscribeop)
996 QML_V4_BEGIN_INSTR(FetchAndSubscribe, fetchAndSubscribe)
998 Register ® = registers[instr->fetchAndSubscribe.reg];
1000 if (reg.isUndefined())
1001 THROW_EXCEPTION(instr->fetchAndSubscribe.exceptionId);
1003 QObject *object = reg.getQObject();
1005 THROW_EXCEPTION(instr->fetchAndSubscribe.exceptionId);
1007 if (bindingInvalidated(invalidated, object, context, instr->fetchAndSubscribe.property.coreIndex))
1010 const Register::Type valueType = (Register::Type)instr->fetchAndSubscribe.valueType;
1011 reg.init(valueType);
1012 if (instr->fetchAndSubscribe.valueType >= FirstCleanupType)
1013 MARK_REGISTER(instr->fetchAndSubscribe.reg);
1015 QQmlData::flushPendingBinding(object, instr->fetchAndSubscribe.property.coreIndex);
1017 QQmlAccessors *accessors = instr->fetchAndSubscribe.property.accessors;
1018 accessors->read(object, instr->fetchAndSubscribe.property.accessorData,
1021 if (valueType == FloatType) {
1023 const double v = reg.getfloat();
1027 if (accessors->notifier) {
1028 QQmlNotifier *notifier = 0;
1029 accessors->notifier(object, instr->fetchAndSubscribe.property.accessorData, ¬ifier);
1031 int subIdx = instr->fetchAndSubscribe.subscription;
1032 Subscription *sub = 0;
1034 sub = (subscriptions + subIdx);
1035 sub->setBindings(this);
1037 sub->connect(notifier);
1040 const int notifyIndex = instr->fetchAndSubscribe.property.notifyIndex;
1041 if (notifyIndex != -1) {
1042 const int subIdx = instr->fetchAndSubscribe.subscription;
1043 subscribe(object, notifyIndex, subIdx, context->engine);
1048 QML_V4_END_INSTR(FetchAndSubscribe, fetchAndSubscribe)
1050 QML_V4_BEGIN_INSTR(LoadId, load)
1051 registers[instr->load.reg].setQObject(context->idValues[instr->load.index].data());
1052 QML_V4_END_INSTR(LoadId, load)
1054 QML_V4_BEGIN_INSTR(LoadScope, load)
1055 registers[instr->load.reg].setQObject(scope);
1056 QML_V4_END_INSTR(LoadScope, load)
1058 QML_V4_BEGIN_INSTR(LoadRoot, load)
1059 registers[instr->load.reg].setQObject(context->contextObject);
1060 QML_V4_END_INSTR(LoadRoot, load)
1062 QML_V4_BEGIN_INSTR(LoadSingletonObject, load)
1064 Register ® = registers[instr->load.reg];
1066 const QString *name = reg.getstringptr();
1067 QQmlTypeNameCache::Result r = context->imports->query(*name);
1068 reg.cleanupString();
1070 if (r.isValid() && r.type) {
1071 if (r.type->isSingleton()) {
1072 QQmlEngine *e = context->engine;
1073 QQmlType::SingletonInstanceInfo *siinfo = r.type->singletonInstanceInfo();
1074 siinfo->init(e); // note: this will also create QJSValue singleton, which is not strictly required here.
1075 QObject *qobjectSingleton = siinfo->qobjectApi(e);
1076 if (qobjectSingleton)
1077 reg.setQObject(qobjectSingleton);
1081 QML_V4_END_INSTR(LoadSingletonObject, load)
1083 QML_V4_BEGIN_INSTR(LoadAttached, attached)
1085 const Register &input = registers[instr->attached.reg];
1086 Register &output = registers[instr->attached.output];
1087 if (input.isUndefined())
1088 THROW_EXCEPTION(instr->attached.exceptionId);
1090 QObject *object = registers[instr->attached.reg].getQObject();
1092 output.setUndefined();
1094 QObject *attached = qmlAttachedPropertiesObjectById(instr->attached.id, input.getQObject(), true);
1096 output.setQObject(attached);
1099 QML_V4_END_INSTR(LoadAttached, attached)
1101 QML_V4_BEGIN_INSTR(UnaryNot, unaryop)
1103 registers[instr->unaryop.output].setbool(!registers[instr->unaryop.src].getbool());
1105 QML_V4_END_INSTR(UnaryNot, unaryop)
1107 QML_V4_BEGIN_INSTR(UnaryMinusNumber, unaryop)
1109 registers[instr->unaryop.output].setnumber(-registers[instr->unaryop.src].getnumber());
1111 QML_V4_END_INSTR(UnaryMinusNumber, unaryop)
1113 QML_V4_BEGIN_INSTR(UnaryMinusInt, unaryop)
1115 registers[instr->unaryop.output].setint(-registers[instr->unaryop.src].getint());
1117 QML_V4_END_INSTR(UnaryMinusInt, unaryop)
1119 QML_V4_BEGIN_INSTR(UnaryPlusNumber, unaryop)
1121 registers[instr->unaryop.output].setnumber(+registers[instr->unaryop.src].getnumber());
1123 QML_V4_END_INSTR(UnaryPlusNumber, unaryop)
1125 QML_V4_BEGIN_INSTR(UnaryPlusInt, unaryop)
1127 registers[instr->unaryop.output].setint(+registers[instr->unaryop.src].getint());
1129 QML_V4_END_INSTR(UnaryPlusInt, unaryop)
1131 QML_V4_BEGIN_INSTR(ConvertBoolToInt, unaryop)
1133 const Register &src = registers[instr->unaryop.src];
1134 Register &output = registers[instr->unaryop.output];
1135 if (src.isUndefined()) output.setUndefined();
1136 else output.setint(src.getbool());
1138 QML_V4_END_INSTR(ConvertBoolToInt, unaryop)
1140 QML_V4_BEGIN_INSTR(ConvertBoolToJSValue, unaryop)
1142 const Register &src = registers[instr->unaryop.src];
1143 Register &output = registers[instr->unaryop.output];
1144 if (src.isUndefined()) {
1145 output.setUndefined();
1147 new (output.getjsvalueptr()) QJSValue(src.getbool());
1148 JSVALUE_REGISTER(instr->unaryop.output);
1151 QML_V4_END_INSTR(ConvertBoolToJSValue, unaryop)
1153 QML_V4_BEGIN_INSTR(ConvertBoolToNumber, unaryop)
1155 const Register &src = registers[instr->unaryop.src];
1156 Register &output = registers[instr->unaryop.output];
1157 if (src.isUndefined()) output.setUndefined();
1158 else output.setnumber(src.getbool());
1160 QML_V4_END_INSTR(ConvertBoolToNumber, unaryop)
1162 QML_V4_BEGIN_INSTR(ConvertBoolToString, unaryop)
1164 const Register &src = registers[instr->unaryop.src];
1165 Register &output = registers[instr->unaryop.output];
1166 if (src.isUndefined()) {
1167 output.setUndefined();
1169 new (output.getstringptr()) QString(QLatin1String(src.getbool() ? "true" : "false"));
1170 STRING_REGISTER(instr->unaryop.output);
1173 QML_V4_END_INSTR(ConvertBoolToString, unaryop)
1175 QML_V4_BEGIN_INSTR(ConvertBoolToVariant, unaryop)
1177 const Register &src = registers[instr->unaryop.src];
1178 Register &output = registers[instr->unaryop.output];
1179 if (src.isUndefined()) {
1180 output.setUndefined();
1182 new (output.getvariantptr()) QVariant(src.getbool());
1183 VARIANT_REGISTER(instr->unaryop.output);
1186 QML_V4_END_INSTR(ConvertBoolToVariant, unaryop)
1188 QML_V4_BEGIN_INSTR(ConvertBoolToVar, unaryop)
1190 const Register &src = registers[instr->unaryop.src];
1191 Register &output = registers[instr->unaryop.output];
1192 if (src.isUndefined()) {
1193 output.setUndefined();
1195 new (output.gethandleptr()) v8::Handle<v8::Value>(v8::Boolean::New(src.getbool()));
1196 V8HANDLE_REGISTER(instr->unaryop.output);
1199 QML_V4_END_INSTR(ConvertBoolToVar, unaryop)
1201 QML_V4_BEGIN_INSTR(ConvertIntToBool, unaryop)
1203 const Register &src = registers[instr->unaryop.src];
1204 Register &output = registers[instr->unaryop.output];
1205 if (src.isUndefined()) output.setUndefined();
1206 else output.setbool(src.getint());
1208 QML_V4_END_INSTR(ConvertIntToBool, unaryop)
1210 QML_V4_BEGIN_INSTR(ConvertIntToJSValue, unaryop)
1212 const Register &src = registers[instr->unaryop.src];
1213 Register &output = registers[instr->unaryop.output];
1214 if (src.isUndefined()) {
1215 output.setUndefined();
1217 new (output.getjsvalueptr()) QJSValue(src.getint());
1218 JSVALUE_REGISTER(instr->unaryop.output);
1221 QML_V4_END_INSTR(ConvertIntToJSValue, unaryop)
1223 QML_V4_BEGIN_INSTR(ConvertIntToNumber, unaryop)
1225 const Register &src = registers[instr->unaryop.src];
1226 Register &output = registers[instr->unaryop.output];
1227 if (src.isUndefined()) output.setUndefined();
1228 else if (src.isNaN()) output.setNaN();
1229 else if (src.isInf()) output.setInf(src.getint() == Register::NegativeInfinity);
1230 else if (src.isNegativeZero()) output.setNegativeZero();
1231 else output.setnumber(double(src.getint()));
1233 QML_V4_END_INSTR(ConvertIntToNumber, unaryop)
1235 QML_V4_BEGIN_INSTR(ConvertIntToString, unaryop)
1237 const Register &src = registers[instr->unaryop.src];
1238 Register &output = registers[instr->unaryop.output];
1239 if (src.isUndefined()) {
1240 output.setUndefined();
1242 new (output.getstringptr()) QString(QString::number(src.getint()));
1243 STRING_REGISTER(instr->unaryop.output);
1246 QML_V4_END_INSTR(ConvertIntToString, unaryop)
1248 QML_V4_BEGIN_INSTR(ConvertIntToVariant, unaryop)
1250 const Register &src = registers[instr->unaryop.src];
1251 Register &output = registers[instr->unaryop.output];
1252 if (src.isUndefined()) {
1253 output.setUndefined();
1255 new (output.getvariantptr()) QVariant(src.getint());
1256 VARIANT_REGISTER(instr->unaryop.output);
1259 QML_V4_END_INSTR(ConvertIntToVariant, unaryop)
1261 QML_V4_BEGIN_INSTR(ConvertIntToVar, unaryop)
1263 const Register &src = registers[instr->unaryop.src];
1264 Register &output = registers[instr->unaryop.output];
1265 if (src.isUndefined()) {
1266 output.setUndefined();
1268 new (output.gethandleptr()) v8::Handle<v8::Value>(v8::Integer::New(src.getint()));
1269 V8HANDLE_REGISTER(instr->unaryop.output);
1272 QML_V4_END_INSTR(ConvertIntToVar, unaryop)
1274 QML_V4_BEGIN_INSTR(ConvertJSValueToVar, unaryop)
1276 const Register &src = registers[instr->unaryop.src];
1277 Register &output = registers[instr->unaryop.output];
1278 if (src.isUndefined()) {
1279 output.setUndefined();
1281 QJSValue tmp(*src.getjsvalueptr());
1282 if (instr->unaryop.src == instr->unaryop.output) {
1283 output.cleanupJSValue();
1284 MARK_CLEAN_REGISTER(instr->unaryop.output);
1286 if (tmp.isUndefined()) {
1287 output.setUndefined();
1289 QV8Engine *v8engine = QQmlEnginePrivate::get(context->engine)->v8engine();
1290 new (output.gethandleptr()) v8::Handle<v8::Value>(
1291 QJSValuePrivate::get(tmp)->asV8Value(v8engine));
1292 V8HANDLE_REGISTER(instr->unaryop.output);
1296 QML_V4_END_INSTR(ConvertJSValueToVar, unaryop)
1298 QML_V4_BEGIN_INSTR(ConvertNumberToBool, unaryop)
1300 const Register &src = registers[instr->unaryop.src];
1301 Register &output = registers[instr->unaryop.output];
1302 if (src.isUndefined()) output.setUndefined();
1303 else output.setbool(src.getnumber() != 0);
1305 QML_V4_END_INSTR(ConvertNumberToBool, unaryop)
1307 QML_V4_BEGIN_INSTR(ConvertNumberToInt, unaryop)
1309 const Register &src = registers[instr->unaryop.src];
1310 Register &output = registers[instr->unaryop.output];
1311 if (src.isUndefined()) output.setUndefined();
1312 else output.setint(toInt32(src.getnumber()));
1314 QML_V4_END_INSTR(ConvertNumberToInt, unaryop)
1316 QML_V4_BEGIN_INSTR(ConvertNumberToJSValue, unaryop)
1318 const Register &src = registers[instr->unaryop.src];
1319 Register &output = registers[instr->unaryop.output];
1320 if (src.isUndefined()) {
1321 output.setUndefined();
1323 new (output.getjsvalueptr()) QJSValue(src.getnumber());
1324 JSVALUE_REGISTER(instr->unaryop.output);
1327 QML_V4_END_INSTR(ConvertNumberToJSValue, unaryop)
1329 QML_V4_BEGIN_INSTR(ConvertNumberToString, unaryop)
1331 const Register &src = registers[instr->unaryop.src];
1332 Register &output = registers[instr->unaryop.output];
1334 if (src.isUndefined()) {
1335 output.setUndefined();
1337 new (output.getstringptr()) QString(QString::number(src.getnumber(), 'g', 16));
1338 STRING_REGISTER(instr->unaryop.output);
1341 QML_V4_END_INSTR(ConvertNumberToString, unaryop)
1343 QML_V4_BEGIN_INSTR(ConvertNumberToVariant, unaryop)
1345 const Register &src = registers[instr->unaryop.src];
1346 Register &output = registers[instr->unaryop.output];
1347 if (src.isUndefined()) {
1348 output.setUndefined();
1350 new (output.getvariantptr()) QVariant(src.getnumber());
1351 VARIANT_REGISTER(instr->unaryop.output);
1354 QML_V4_END_INSTR(ConvertNumberToVariant, unaryop)
1356 QML_V4_BEGIN_INSTR(ConvertNumberToVar, unaryop)
1358 const Register &src = registers[instr->unaryop.src];
1359 Register &output = registers[instr->unaryop.output];
1360 if (src.isUndefined()) {
1361 output.setUndefined();
1363 new (output.gethandleptr()) v8::Handle<v8::Value>(v8::Number::New(src.getnumber()));
1364 V8HANDLE_REGISTER(instr->unaryop.output);
1367 QML_V4_END_INSTR(ConvertNumberToVar, unaryop)
1369 QML_V4_BEGIN_INSTR(ConvertStringToBool, unaryop)
1371 const Register &src = registers[instr->unaryop.src];
1372 Register &output = registers[instr->unaryop.output];
1374 if (src.isUndefined()) {
1375 output.setUndefined();
1377 // Delegate the conversion. This is pretty fast and it doesn't require a QScriptEngine.
1378 // Ideally we should just call the methods in the QScript namespace directly.
1379 QJSValue tmp(*src.getstringptr());
1380 if (instr->unaryop.src == instr->unaryop.output) {
1381 output.cleanupString();
1382 MARK_CLEAN_REGISTER(instr->unaryop.output);
1384 output.setbool(tmp.toBool());
1387 QML_V4_END_INSTR(ConvertStringToBool, unaryop)
1389 QML_V4_BEGIN_INSTR(ConvertStringToInt, unaryop)
1391 const Register &src = registers[instr->unaryop.src];
1392 Register &output = registers[instr->unaryop.output];
1394 if (src.isUndefined()) {
1395 output.setUndefined();
1397 // Delegate the conversion. This is pretty fast and it doesn't require a QScriptEngine.
1398 // Ideally we should just call the methods in the QScript namespace directly.
1399 QJSValue tmp(*src.getstringptr());
1400 if (instr->unaryop.src == instr->unaryop.output) {
1401 output.cleanupString();
1402 MARK_CLEAN_REGISTER(instr->unaryop.output);
1404 output.setint(tmp.toInt());
1407 QML_V4_END_INSTR(ConvertStringToInt, unaryop)
1409 QML_V4_BEGIN_INSTR(ConvertStringToJSValue, unaryop)
1411 const Register &src = registers[instr->unaryop.src];
1412 Register &output = registers[instr->unaryop.output];
1413 if (src.isUndefined()) {
1414 output.setUndefined();
1416 QString tmp(*src.getstringptr());
1417 if (instr->unaryop.src == instr->unaryop.output) {
1418 output.cleanupString();
1419 MARK_CLEAN_REGISTER(instr->unaryop.output);
1421 new (output.getjsvalueptr()) QJSValue(tmp);
1422 JSVALUE_REGISTER(instr->unaryop.output);
1425 QML_V4_END_INSTR(ConvertStringToJSValue, unaryop)
1427 QML_V4_BEGIN_INSTR(ConvertStringToNumber, unaryop)
1429 const Register &src = registers[instr->unaryop.src];
1430 Register &output = registers[instr->unaryop.output];
1432 if (src.isUndefined()) {
1433 output.setUndefined();
1435 // Delegate the conversion. This is pretty fast and it doesn't require a QScriptEngine.
1436 // Ideally we should just call the methods in the QScript namespace directly.
1437 QJSValue tmp(*src.getstringptr());
1438 if (instr->unaryop.src == instr->unaryop.output) {
1439 output.cleanupString();
1440 MARK_CLEAN_REGISTER(instr->unaryop.output);
1442 output.setnumber(tmp.toNumber());
1445 QML_V4_END_INSTR(ConvertStringToNumber, unaryop)
1447 QML_V4_BEGIN_INSTR(ConvertStringToUrl, unaryop)
1449 const Register &src = registers[instr->unaryop.src];
1450 Register &output = registers[instr->unaryop.output];
1452 if (src.isUndefined()) {
1453 output.setUndefined();
1455 QString tmp(*src.getstringptr());
1456 // Encoded dir-separators defeat QUrl processing - decode them first
1457 tmp.replace(QLatin1String("%2f"), QLatin1String("/"), Qt::CaseInsensitive);
1458 if (instr->unaryop.src == instr->unaryop.output) {
1459 output.cleanupString();
1460 MARK_CLEAN_REGISTER(instr->unaryop.output);
1462 new (output.geturlptr()) QUrl(tmp);
1464 URL_REGISTER(instr->unaryop.output);
1467 QML_V4_END_INSTR(ConvertStringToUrl, unaryop)
1469 QML_V4_BEGIN_INSTR(ConvertStringToColor, unaryop)
1471 const Register &src = registers[instr->unaryop.src];
1472 Register &output = registers[instr->unaryop.output];
1474 if (src.isUndefined()) {
1475 output.setUndefined();
1477 const QString tmp(*src.getstringptr());
1478 if (instr->unaryop.src == instr->unaryop.output) {
1479 output.cleanupString();
1480 MARK_CLEAN_REGISTER(instr->unaryop.output);
1482 QQml_valueTypeProvider()->createValueFromString(QMetaType::QColor, tmp, output.typeDataPtr(), output.dataSize());
1484 COLOR_REGISTER(instr->unaryop.output);
1487 QML_V4_END_INSTR(ConvertStringToColor, unaryop)
1489 QML_V4_BEGIN_INSTR(ConvertStringToVariant, unaryop)
1491 const Register &src = registers[instr->unaryop.src];
1492 Register &output = registers[instr->unaryop.output];
1493 if (src.isUndefined()) {
1494 output.setUndefined();
1496 const QString tmp(*src.getstringptr());
1497 if (instr->unaryop.src == instr->unaryop.output) {
1498 output.cleanupString();
1499 MARK_CLEAN_REGISTER(instr->unaryop.output);
1501 new (output.getvariantptr()) QVariant(tmp);
1503 VARIANT_REGISTER(instr->unaryop.output);
1506 QML_V4_END_INSTR(ConvertStringToVariant, unaryop)
1508 QML_V4_BEGIN_INSTR(ConvertStringToVar, unaryop)
1510 const Register &src = registers[instr->unaryop.src];
1511 Register &output = registers[instr->unaryop.output];
1512 if (src.isUndefined()) {
1513 output.setUndefined();
1515 const QString tmp(*src.getstringptr());
1516 if (instr->unaryop.src == instr->unaryop.output) {
1517 output.cleanupString();
1518 MARK_CLEAN_REGISTER(instr->unaryop.output);
1520 new (output.gethandleptr()) v8::Handle<v8::Value>(QJSConverter::toString(tmp));
1521 V8HANDLE_REGISTER(instr->unaryop.output);
1524 QML_V4_END_INSTR(ConvertStringToVar, unaryop)
1526 QML_V4_BEGIN_INSTR(ConvertUrlToBool, unaryop)
1528 const Register &src = registers[instr->unaryop.src];
1529 Register &output = registers[instr->unaryop.output];
1531 if (src.isUndefined()) {
1532 output.setUndefined();
1534 const QUrl tmp(*src.geturlptr());
1535 if (instr->unaryop.src == instr->unaryop.output) {
1536 output.cleanupUrl();
1537 MARK_CLEAN_REGISTER(instr->unaryop.output);
1539 output.setbool(!tmp.isEmpty());
1542 QML_V4_END_INSTR(ConvertUrlToBool, unaryop)
1544 QML_V4_BEGIN_INSTR(ConvertUrlToJSValue, unaryop)
1546 const Register &src = registers[instr->unaryop.src];
1547 Register &output = registers[instr->unaryop.output];
1548 if (src.isUndefined()) {
1549 output.setUndefined();
1551 const QUrl tmp(*src.geturlptr());
1552 if (instr->unaryop.src == instr->unaryop.output) {
1553 output.cleanupUrl();
1554 MARK_CLEAN_REGISTER(instr->unaryop.output);
1556 new (output.getjsvalueptr()) QJSValue(tmp.toString());
1557 JSVALUE_REGISTER(instr->unaryop.output);
1560 QML_V4_END_INSTR(ConvertUrlToJSValue, unaryop)
1562 QML_V4_BEGIN_INSTR(ConvertUrlToString, unaryop)
1564 const Register &src = registers[instr->unaryop.src];
1565 Register &output = registers[instr->unaryop.output];
1567 if (src.isUndefined()) {
1568 output.setUndefined();
1570 const QUrl tmp(*src.geturlptr());
1571 if (instr->unaryop.src == instr->unaryop.output) {
1572 output.cleanupUrl();
1573 MARK_CLEAN_REGISTER(instr->unaryop.output);
1575 new (output.getstringptr()) QString(tmp.toString());
1576 STRING_REGISTER(instr->unaryop.output);
1579 QML_V4_END_INSTR(ConvertUrlToString, unaryop)
1581 QML_V4_BEGIN_INSTR(ConvertUrlToVariant, unaryop)
1583 const Register &src = registers[instr->unaryop.src];
1584 Register &output = registers[instr->unaryop.output];
1586 if (src.isUndefined()) {
1587 output.setUndefined();
1589 const QUrl tmp(*src.geturlptr());
1590 if (instr->unaryop.src == instr->unaryop.output) {
1591 output.cleanupUrl();
1592 MARK_CLEAN_REGISTER(instr->unaryop.output);
1594 new (output.getvariantptr()) QVariant(tmp);
1595 VARIANT_REGISTER(instr->unaryop.output);
1598 QML_V4_END_INSTR(ConvertUrlToVariant, unaryop)
1600 QML_V4_BEGIN_INSTR(ConvertUrlToVar, unaryop)
1602 const Register &src = registers[instr->unaryop.src];
1603 Register &output = registers[instr->unaryop.output];
1605 if (src.isUndefined()) {
1606 output.setUndefined();
1608 const QUrl tmp(*src.geturlptr());
1609 if (instr->unaryop.src == instr->unaryop.output) {
1610 output.cleanupUrl();
1611 MARK_CLEAN_REGISTER(instr->unaryop.output);
1613 new (output.gethandleptr()) v8::Handle<v8::Value>(QJSConverter::toString(tmp.toString()));
1614 V8HANDLE_REGISTER(instr->unaryop.output);
1617 QML_V4_END_INSTR(ConvertUrlToVar, unaryop)
1619 QML_V4_BEGIN_INSTR(ConvertColorToBool, unaryop)
1621 const Register &src = registers[instr->unaryop.src];
1622 Register &output = registers[instr->unaryop.output];
1624 if (src.isUndefined()) {
1625 output.setUndefined();
1627 // for compatibility with color behavior in v8, always true
1628 output.setbool(true);
1631 QML_V4_END_INSTR(ConvertColorToBool, unaryop)
1633 QML_V4_BEGIN_INSTR(ConvertColorToJSValue, unaryop)
1635 const Register &src = registers[instr->unaryop.src];
1636 Register &output = registers[instr->unaryop.output];
1637 if (src.isUndefined()) {
1638 output.setUndefined();
1640 const QVariant tmp(QMetaType::QColor, src.typeDataPtr());
1641 if (instr->unaryop.src == instr->unaryop.output) {
1642 output.cleanupColor();
1643 MARK_CLEAN_REGISTER(instr->unaryop.output);
1646 QQmlEnginePrivate *ep = QQmlEnginePrivate::get(context->engine);
1647 QV8Engine *v8engine = ep->v8engine();
1648 QQmlValueType *vt = QQmlValueTypeFactory::valueType(QMetaType::QColor);
1649 v8::HandleScope handle_scope;
1650 v8::Context::Scope scope(v8engine->context());
1651 new (output.getjsvalueptr()) QJSValue(v8engine->scriptValueFromInternal(
1652 v8engine->valueTypeWrapper()->newValueType(tmp, vt)));
1653 JSVALUE_REGISTER(instr->unaryop.output);
1656 QML_V4_END_INSTR(ConvertColorToJSValue, unaryop)
1658 QML_V4_BEGIN_INSTR(ConvertColorToString, unaryop)
1660 const Register &src = registers[instr->unaryop.src];
1661 Register &output = registers[instr->unaryop.output];
1663 if (src.isUndefined()) {
1664 output.setUndefined();
1666 QQml_valueTypeProvider()->createStringFromValue(QMetaType::QColor, src.typeDataPtr(), output.getstringptr());
1667 STRING_REGISTER(instr->unaryop.output);
1670 QML_V4_END_INSTR(ConvertColorToString, unaryop)
1672 QML_V4_BEGIN_INSTR(ConvertColorToVariant, unaryop)
1674 const Register &src = registers[instr->unaryop.src];
1675 Register &output = registers[instr->unaryop.output];
1677 if (src.isUndefined()) {
1678 output.setUndefined();
1680 QVariant tmp(QMetaType::QColor, src.typeDataPtr());
1681 if (instr->unaryop.src == instr->unaryop.output) {
1682 output.cleanupColor();
1683 MARK_CLEAN_REGISTER(instr->unaryop.output);
1685 new (output.getvariantptr()) QVariant(tmp);
1686 VARIANT_REGISTER(instr->unaryop.output);
1689 QML_V4_END_INSTR(ConvertColorToVariant, unaryop)
1691 QML_V4_BEGIN_INSTR(ConvertColorToVar, unaryop)
1693 const Register &src = registers[instr->unaryop.src];
1694 Register &output = registers[instr->unaryop.output];
1696 if (src.isUndefined()) {
1697 output.setUndefined();
1699 const QVariant tmp(QMetaType::QColor, src.typeDataPtr());
1700 if (instr->unaryop.src == instr->unaryop.output) {
1701 output.cleanupColor();
1702 MARK_CLEAN_REGISTER(instr->unaryop.output);
1705 QQmlEnginePrivate *ep = QQmlEnginePrivate::get(context->engine);
1706 QQmlValueType *vt = QQmlValueTypeFactory::valueType(QMetaType::QColor);
1707 new (output.gethandleptr()) v8::Handle<v8::Value>(ep->v8engine()->valueTypeWrapper()->newValueType(tmp, vt));
1708 V8HANDLE_REGISTER(instr->unaryop.output);
1711 QML_V4_END_INSTR(ConvertColorToVar, unaryop)
1713 QML_V4_BEGIN_INSTR(ConvertObjectToBool, unaryop)
1715 const Register &src = registers[instr->unaryop.src];
1716 Register &output = registers[instr->unaryop.output];
1718 if (src.isUndefined())
1719 output.setUndefined();
1721 output.setbool(src.getQObject() != 0);
1723 QML_V4_END_INSTR(ConvertObjectToBool, unaryop)
1725 QML_V4_BEGIN_INSTR(ConvertObjectToJSValue, unaryop)
1727 const Register &src = registers[instr->unaryop.src];
1728 Register &output = registers[instr->unaryop.output];
1729 if (src.isUndefined()) {
1730 output.setUndefined();
1732 QQmlEnginePrivate *ep = QQmlEnginePrivate::get(context->engine);
1733 v8::HandleScope handle_scope;
1734 v8::Context::Scope scope(ep->v8engine()->context());
1735 new (output.getjsvalueptr()) QJSValue(context->engine->newQObject(src.getQObject()));
1736 JSVALUE_REGISTER(instr->unaryop.output);
1739 QML_V4_END_INSTR(ConvertObjectToJSValue, unaryop)
1741 QML_V4_BEGIN_INSTR(ConvertObjectToVariant, unaryop)
1743 const Register &src = registers[instr->unaryop.src];
1744 Register &output = registers[instr->unaryop.output];
1746 if (src.isUndefined())
1747 output.setUndefined();
1749 new (output.getvariantptr()) QVariant(qVariantFromValue<QObject *>(src.getQObject()));
1750 VARIANT_REGISTER(instr->unaryop.output);
1753 QML_V4_END_INSTR(ConvertObjectToVariant, unaryop)
1755 QML_V4_BEGIN_INSTR(ConvertObjectToVar, unaryop)
1757 const Register &src = registers[instr->unaryop.src];
1758 Register &output = registers[instr->unaryop.output];
1760 if (src.isUndefined())
1761 output.setUndefined();
1763 QQmlEnginePrivate *ep = QQmlEnginePrivate::get(context->engine);
1764 new (output.gethandleptr()) v8::Handle<v8::Value>(ep->v8engine()->newQObject(src.getQObject()));
1765 V8HANDLE_REGISTER(instr->unaryop.output);
1768 QML_V4_END_INSTR(ConvertObjectToVar, unaryop)
1770 QML_V4_BEGIN_INSTR(ConvertVarToJSValue, unaryop)
1772 const Register &src = registers[instr->unaryop.src];
1773 Register &output = registers[instr->unaryop.output];
1774 if (src.isUndefined()) {
1775 output.setUndefined();
1777 v8::Handle<v8::Value> tmp(*src.gethandleptr());
1778 if (instr->unaryop.src == instr->unaryop.output) {
1779 output.cleanupHandle();
1780 MARK_CLEAN_REGISTER(instr->unaryop.output);
1782 QV8Engine *v8engine = QQmlEnginePrivate::get(context->engine)->v8engine();
1783 new (output.getjsvalueptr()) QJSValue(v8engine->scriptValueFromInternal(tmp));
1784 JSVALUE_REGISTER(instr->unaryop.output);
1787 QML_V4_END_INSTR(ConvertVarToJSValue, unaryop)
1789 QML_V4_BEGIN_INSTR(ConvertNullToJSValue, unaryop)
1791 Register &output = registers[instr->unaryop.output];
1792 new (output.getjsvalueptr()) QJSValue(QJSValue::NullValue);
1793 JSVALUE_REGISTER(instr->unaryop.output);
1795 QML_V4_END_INSTR(ConvertNullToJSValue, unaryop)
1797 QML_V4_BEGIN_INSTR(ConvertNullToObject, unaryop)
1799 Register &output = registers[instr->unaryop.output];
1800 output.setQObject(0);
1802 QML_V4_END_INSTR(ConvertNullToObject, unaryop)
1804 QML_V4_BEGIN_INSTR(ConvertNullToVariant, unaryop)
1806 Register &output = registers[instr->unaryop.output];
1807 new (output.getvariantptr()) QVariant();
1808 VARIANT_REGISTER(instr->unaryop.output);
1810 QML_V4_END_INSTR(ConvertNullToVariant, unaryop)
1812 QML_V4_BEGIN_INSTR(ConvertNullToVar, unaryop)
1814 Register &output = registers[instr->unaryop.output];
1815 new (output.gethandleptr()) v8::Handle<v8::Value>(v8::Null());
1816 V8HANDLE_REGISTER(instr->unaryop.output);
1818 QML_V4_END_INSTR(ConvertNullToVar, unaryop)
1820 QML_V4_BEGIN_INSTR(ResolveUrl, unaryop)
1822 const Register &src = registers[instr->unaryop.src];
1823 Register &output = registers[instr->unaryop.output];
1824 if (src.isUndefined()) {
1825 output.setUndefined();
1827 const QUrl tmp(*src.geturlptr());
1828 if (instr->unaryop.src == instr->unaryop.output) {
1829 *output.geturlptr() = context->resolvedUrl(tmp);
1831 new (output.geturlptr()) QUrl(context->resolvedUrl(tmp));
1832 URL_REGISTER(instr->unaryop.output);
1836 QML_V4_END_INSTR(ResolveUrl, unaryop)
1838 QML_V4_BEGIN_INSTR(MathSinNumber, unaryop)
1840 const Register &src = registers[instr->unaryop.src];
1841 Register &output = registers[instr->unaryop.output];
1842 if (src.isUndefined()) output.setUndefined();
1843 else output.setnumber(qSin(src.getnumber()));
1845 QML_V4_END_INSTR(MathSinNumber, unaryop)
1847 QML_V4_BEGIN_INSTR(MathCosNumber, unaryop)
1849 const Register &src = registers[instr->unaryop.src];
1850 Register &output = registers[instr->unaryop.output];
1851 if (src.isUndefined()) output.setUndefined();
1852 else output.setnumber(qCos(src.getnumber()));
1854 QML_V4_END_INSTR(MathCosNumber, unaryop)
1856 QML_V4_BEGIN_INSTR(MathAbsNumber, unaryop)
1858 const Register &src = registers[instr->unaryop.src];
1859 Register &output = registers[instr->unaryop.output];
1860 if (src.isUndefined()) output.setUndefined();
1861 else output.setnumber(clearSignBit(qAbs(src.getnumber())));
1863 QML_V4_END_INSTR(MathAbsNumber, unaryop)
1865 QML_V4_BEGIN_INSTR(MathRoundNumber, unaryop)
1867 const Register &src = registers[instr->unaryop.src];
1868 Register &output = registers[instr->unaryop.output];
1869 if (src.isUndefined()) output.setUndefined();
1870 else output.setint(qRound(src.getnumber()));
1872 QML_V4_END_INSTR(MathRoundNumber, unaryop)
1874 QML_V4_BEGIN_INSTR(MathFloorNumber, unaryop)
1876 const Register &src = registers[instr->unaryop.src];
1877 Register &output = registers[instr->unaryop.output];
1878 if (src.isUndefined())
1879 output.setUndefined();
1880 else if (src.isNaN())
1881 // output should be an int, but still NaN
1882 output.setNaNType();
1883 else if (src.isInf())
1884 // output should be an int, but still Inf
1885 output.setInfType(signBitSet(src.getnumber()));
1886 else if (src.isNegativeZero())
1887 // output should be an int, but still -0
1888 output.setNegativeZeroType();
1890 output.setint(qFloor(src.getnumber()));
1892 QML_V4_END_INSTR(MathFloorNumber, unaryop)
1894 QML_V4_BEGIN_INSTR(MathCeilNumber, unaryop)
1896 const Register &src = registers[instr->unaryop.src];
1897 Register &output = registers[instr->unaryop.output];
1898 if (src.isUndefined())
1899 output.setUndefined();
1900 else if (src.isNaN())
1901 // output should be an int, but still NaN
1902 output.setNaNType();
1903 else if (src.isInf())
1904 // output should be an int, but still Inf
1905 output.setInfType(signBitSet(src.getnumber()));
1906 else if (src.isNegativeZero())
1907 // output should be an int, but still -0
1908 output.setNegativeZeroType();
1910 // Ensure that we preserve the sign bit (Math.ceil(-0) -> -0)
1911 const double input = src.getnumber();
1912 const int ceiled = qCeil(input);
1913 if (ceiled == 0 && signBitSet(input)) {
1914 output.setNegativeZeroType();
1916 output.setint(ceiled);
1920 QML_V4_END_INSTR(MathCeilNumber, unaryop)
1922 QML_V4_BEGIN_INSTR(MathPINumber, unaryop)
1924 static const double qmlPI = 2.0 * qAsin(1.0);
1925 Register &output = registers[instr->unaryop.output];
1926 output.setnumber(qmlPI);
1928 QML_V4_END_INSTR(MathPINumber, unaryop)
1930 QML_V4_BEGIN_INSTR(LoadNull, null_value)
1931 registers[instr->null_value.reg].setNull();
1932 QML_V4_END_INSTR(LoadNull, null_value)
1934 QML_V4_BEGIN_INSTR(LoadNumber, number_value)
1935 registers[instr->number_value.reg].setnumber(instr->number_value.value);
1936 QML_V4_END_INSTR(LoadNumber, number_value)
1938 QML_V4_BEGIN_INSTR(LoadInt, int_value)
1939 registers[instr->int_value.reg].setint(instr->int_value.value);
1940 QML_V4_END_INSTR(LoadInt, int_value)
1942 QML_V4_BEGIN_INSTR(LoadBool, bool_value)
1943 registers[instr->bool_value.reg].setbool(instr->bool_value.value);
1944 QML_V4_END_INSTR(LoadBool, bool_value)
1946 QML_V4_BEGIN_INSTR(LoadString, string_value)
1948 Register &output = registers[instr->string_value.reg];
1949 QChar *string = (QChar *)(data + instr->string_value.offset);
1950 new (output.getstringptr()) QString(string, instr->string_value.length);
1951 STRING_REGISTER(instr->string_value.reg);
1953 QML_V4_END_INSTR(LoadString, string_value)
1955 QML_V4_BEGIN_INSTR(EnableV4Test, string_value)
1957 testBindingSource = new QString((QChar *)(data + instr->string_value.offset), instr->string_value.length);
1960 QML_V4_END_INSTR(String, string_value)
1962 QML_V4_BEGIN_INSTR(BitAndInt, binaryop)
1964 registers[instr->binaryop.output].setint(registers[instr->binaryop.left].getint() &
1965 registers[instr->binaryop.right].getint());
1967 QML_V4_END_INSTR(BitAndInt, binaryop)
1969 QML_V4_BEGIN_INSTR(BitOrInt, binaryop)
1971 registers[instr->binaryop.output].setint(registers[instr->binaryop.left].getint() |
1972 registers[instr->binaryop.right].getint());
1974 QML_V4_END_INSTR(BitAndInt, binaryop)
1976 QML_V4_BEGIN_INSTR(BitXorInt, binaryop)
1978 registers[instr->binaryop.output].setint(registers[instr->binaryop.left].getint() ^
1979 registers[instr->binaryop.right].getint());
1981 QML_V4_END_INSTR(BitXorInt, binaryop)
1983 QML_V4_BEGIN_INSTR(AddNumber, binaryop)
1985 registers[instr->binaryop.output].setnumber(registers[instr->binaryop.left].getnumber() +
1986 registers[instr->binaryop.right].getnumber());
1988 QML_V4_END_INSTR(AddNumber, binaryop)
1990 QML_V4_BEGIN_INSTR(AddString, binaryop)
1992 QString &string = *registers[instr->binaryop.output].getstringptr();
1993 if (instr->binaryop.output == instr->binaryop.left) {
1994 string += registers[instr->binaryop.right].getstringptr();
1996 string = *registers[instr->binaryop.left].getstringptr() +
1997 *registers[instr->binaryop.right].getstringptr();
2000 QML_V4_END_INSTR(AddString, binaryop)
2002 QML_V4_BEGIN_INSTR(SubNumber, binaryop)
2004 registers[instr->binaryop.output].setnumber(registers[instr->binaryop.left].getnumber() -
2005 registers[instr->binaryop.right].getnumber());
2007 QML_V4_END_INSTR(SubNumber, binaryop)
2009 QML_V4_BEGIN_INSTR(MulNumber, binaryop)
2011 registers[instr->binaryop.output].setnumber(registers[instr->binaryop.left].getnumber() *
2012 registers[instr->binaryop.right].getnumber());
2014 QML_V4_END_INSTR(MulNumber, binaryop)
2016 QML_V4_BEGIN_INSTR(DivNumber, binaryop)
2018 registers[instr->binaryop.output].setnumber(registers[instr->binaryop.left].getnumber() /
2019 registers[instr->binaryop.right].getnumber());
2021 QML_V4_END_INSTR(DivNumber, binaryop)
2023 QML_V4_BEGIN_INSTR(ModNumber, binaryop)
2025 Register &target = registers[instr->binaryop.output];
2026 const Register &left = registers[instr->binaryop.left];
2027 const Register &right = registers[instr->binaryop.right];
2028 target.setnumber(::fmod(left.getnumber(), right.getnumber()));
2030 QML_V4_END_INSTR(ModInt, binaryop)
2032 QML_V4_BEGIN_INSTR(LShiftInt, binaryop)
2034 registers[instr->binaryop.output].setint(registers[instr->binaryop.left].getint() <<
2035 registers[instr->binaryop.right].getint());
2037 QML_V4_END_INSTR(LShiftInt, binaryop)
2039 QML_V4_BEGIN_INSTR(RShiftInt, binaryop)
2041 registers[instr->binaryop.output].setint(registers[instr->binaryop.left].getint() >>
2042 registers[instr->binaryop.right].getint());
2044 QML_V4_END_INSTR(RShiftInt, binaryop)
2046 QML_V4_BEGIN_INSTR(URShiftInt, binaryop)
2048 registers[instr->binaryop.output].setint((unsigned)registers[instr->binaryop.left].getint() >>
2049 registers[instr->binaryop.right].getint());
2051 QML_V4_END_INSTR(URShiftInt, binaryop)
2053 QML_V4_BEGIN_INSTR(GtNumber, binaryop)
2055 registers[instr->binaryop.output].setbool(registers[instr->binaryop.left].getnumber() >
2056 registers[instr->binaryop.right].getnumber());
2058 QML_V4_END_INSTR(GtNumber, binaryop)
2060 QML_V4_BEGIN_INSTR(LtNumber, binaryop)
2062 registers[instr->binaryop.output].setbool(registers[instr->binaryop.left].getnumber() <
2063 registers[instr->binaryop.right].getnumber());
2065 QML_V4_END_INSTR(LtNumber, binaryop)
2067 QML_V4_BEGIN_INSTR(GeNumber, binaryop)
2069 registers[instr->binaryop.output].setbool(registers[instr->binaryop.left].getnumber() >=
2070 registers[instr->binaryop.right].getnumber());
2072 QML_V4_END_INSTR(GeNumber, binaryop)
2074 QML_V4_BEGIN_INSTR(LeNumber, binaryop)
2076 registers[instr->binaryop.output].setbool(registers[instr->binaryop.left].getnumber() <=
2077 registers[instr->binaryop.right].getnumber());
2079 QML_V4_END_INSTR(LeNumber, binaryop)
2081 QML_V4_BEGIN_INSTR(EqualNumber, binaryop)
2083 registers[instr->binaryop.output].setbool(registers[instr->binaryop.left].getnumber() ==
2084 registers[instr->binaryop.right].getnumber());
2086 QML_V4_END_INSTR(EqualNumber, binaryop)
2088 QML_V4_BEGIN_INSTR(NotEqualNumber, binaryop)
2090 registers[instr->binaryop.output].setbool(registers[instr->binaryop.left].getnumber() !=
2091 registers[instr->binaryop.right].getnumber());
2093 QML_V4_END_INSTR(NotEqualNumber, binaryop)
2095 QML_V4_BEGIN_INSTR(StrictEqualNumber, binaryop)
2097 registers[instr->binaryop.output].setbool(registers[instr->binaryop.left].getnumber() ==
2098 registers[instr->binaryop.right].getnumber());
2100 QML_V4_END_INSTR(StrictEqualNumber, binaryop)
2102 QML_V4_BEGIN_INSTR(StrictNotEqualNumber, binaryop)
2104 registers[instr->binaryop.output].setbool(registers[instr->binaryop.left].getnumber() !=
2105 registers[instr->binaryop.right].getnumber());
2107 QML_V4_END_INSTR(StrictNotEqualNumber, binaryop)
2109 QML_V4_BEGIN_INSTR(GtString, binaryop)
2111 const QString &a = *registers[instr->binaryop.left].getstringptr();
2112 const QString &b = *registers[instr->binaryop.right].getstringptr();
2113 bool result = a > b;
2114 if (instr->binaryop.left == instr->binaryop.output) {
2115 registers[instr->binaryop.output].cleanupString();
2116 MARK_CLEAN_REGISTER(instr->binaryop.output);
2118 registers[instr->binaryop.output].setbool(result);
2120 QML_V4_END_INSTR(GtString, binaryop)
2122 QML_V4_BEGIN_INSTR(LtString, binaryop)
2124 const QString &a = *registers[instr->binaryop.left].getstringptr();
2125 const QString &b = *registers[instr->binaryop.right].getstringptr();
2126 bool result = a < b;
2127 if (instr->binaryop.left == instr->binaryop.output) {
2128 registers[instr->binaryop.output].cleanupString();
2129 MARK_CLEAN_REGISTER(instr->binaryop.output);
2131 registers[instr->binaryop.output].setbool(result);
2133 QML_V4_END_INSTR(LtString, binaryop)
2135 QML_V4_BEGIN_INSTR(GeString, binaryop)
2137 const QString &a = *registers[instr->binaryop.left].getstringptr();
2138 const QString &b = *registers[instr->binaryop.right].getstringptr();
2139 bool result = a >= b;
2140 if (instr->binaryop.left == instr->binaryop.output) {
2141 registers[instr->binaryop.output].cleanupString();
2142 MARK_CLEAN_REGISTER(instr->binaryop.output);
2144 registers[instr->binaryop.output].setbool(result);
2146 QML_V4_END_INSTR(GeString, binaryop)
2148 QML_V4_BEGIN_INSTR(LeString, binaryop)
2150 const QString &a = *registers[instr->binaryop.left].getstringptr();
2151 const QString &b = *registers[instr->binaryop.right].getstringptr();
2152 bool result = a <= b;
2153 if (instr->binaryop.left == instr->binaryop.output) {
2154 registers[instr->binaryop.output].cleanupString();
2155 MARK_CLEAN_REGISTER(instr->binaryop.output);
2157 registers[instr->binaryop.output].setbool(result);
2159 QML_V4_END_INSTR(LeString, binaryop)
2161 QML_V4_BEGIN_INSTR(EqualString, binaryop)
2163 const QString &a = *registers[instr->binaryop.left].getstringptr();
2164 const QString &b = *registers[instr->binaryop.right].getstringptr();
2165 bool result = a == b;
2166 if (instr->binaryop.left == instr->binaryop.output) {
2167 registers[instr->binaryop.output].cleanupString();
2168 MARK_CLEAN_REGISTER(instr->binaryop.output);
2170 registers[instr->binaryop.output].setbool(result);
2172 QML_V4_END_INSTR(EqualString, binaryop)
2174 QML_V4_BEGIN_INSTR(NotEqualString, binaryop)
2176 const QString &a = *registers[instr->binaryop.left].getstringptr();
2177 const QString &b = *registers[instr->binaryop.right].getstringptr();
2178 bool result = a != b;
2179 if (instr->binaryop.left == instr->binaryop.output) {
2180 registers[instr->binaryop.output].cleanupString();
2181 MARK_CLEAN_REGISTER(instr->binaryop.output);
2183 registers[instr->binaryop.output].setbool(result);
2185 QML_V4_END_INSTR(NotEqualString, binaryop)
2187 QML_V4_BEGIN_INSTR(StrictEqualString, binaryop)
2189 const QString &a = *registers[instr->binaryop.left].getstringptr();
2190 const QString &b = *registers[instr->binaryop.right].getstringptr();
2191 bool result = a == b;
2192 if (instr->binaryop.left == instr->binaryop.output) {
2193 registers[instr->binaryop.output].cleanupString();
2194 MARK_CLEAN_REGISTER(instr->binaryop.output);
2196 registers[instr->binaryop.output].setbool(result);
2198 QML_V4_END_INSTR(StrictEqualString, binaryop)
2200 QML_V4_BEGIN_INSTR(StrictNotEqualString, binaryop)
2202 const QString &a = *registers[instr->binaryop.left].getstringptr();
2203 const QString &b = *registers[instr->binaryop.right].getstringptr();
2204 bool result = a != b;
2205 if (instr->binaryop.left == instr->binaryop.output) {
2206 registers[instr->binaryop.output].cleanupString();
2207 MARK_CLEAN_REGISTER(instr->binaryop.output);
2209 registers[instr->binaryop.output].setbool(result);
2211 QML_V4_END_INSTR(StrictNotEqualString, binaryop)
2213 QML_V4_BEGIN_INSTR(EqualObject, binaryop)
2215 const Register &left = registers[instr->binaryop.left];
2216 const Register &right = registers[instr->binaryop.right];
2217 QObject *leftobj = (left.gettype() == NullType) ? 0 : left.getQObject();
2218 QObject *rightobj = (right.gettype() == NullType) ? 0 : right.getQObject();
2219 registers[instr->binaryop.output].setbool(leftobj == rightobj);
2221 QML_V4_END_INSTR(EqualObject, binaryop)
2223 QML_V4_BEGIN_INSTR(NotEqualObject, binaryop)
2225 const Register &left = registers[instr->binaryop.left];
2226 const Register &right = registers[instr->binaryop.right];
2227 QObject *leftobj = (left.gettype() == NullType) ? 0 : left.getQObject();
2228 QObject *rightobj = (right.gettype() == NullType) ? 0 : right.getQObject();
2229 registers[instr->binaryop.output].setbool(leftobj != rightobj);
2231 QML_V4_END_INSTR(NotEqualObject, binaryop)
2233 QML_V4_BEGIN_INSTR(StrictEqualObject, binaryop)
2235 const Register &left = registers[instr->binaryop.left];
2236 const Register &right = registers[instr->binaryop.right];
2237 QObject *leftobj = (left.gettype() == NullType) ? 0 : left.getQObject();
2238 QObject *rightobj = (right.gettype() == NullType) ? 0 : right.getQObject();
2239 registers[instr->binaryop.output].setbool(leftobj == rightobj);
2241 QML_V4_END_INSTR(StrictEqualObject, binaryop)
2243 QML_V4_BEGIN_INSTR(StrictNotEqualObject, binaryop)
2245 const Register &left = registers[instr->binaryop.left];
2246 const Register &right = registers[instr->binaryop.right];
2247 QObject *leftobj = (left.gettype() == NullType) ? 0 : left.getQObject();
2248 QObject *rightobj = (right.gettype() == NullType) ? 0 : right.getQObject();
2249 registers[instr->binaryop.output].setbool(leftobj != rightobj);
2251 QML_V4_END_INSTR(StrictNotEqualObject, binaryop)
2253 QML_V4_BEGIN_INSTR(MathMaxNumber, binaryop)
2255 const Register &left = registers[instr->binaryop.left];
2256 const Register &right = registers[instr->binaryop.right];
2257 Register &output = registers[instr->binaryop.output];
2258 if (left.isUndefined() || right.isUndefined()) {
2259 output.setUndefined();
2261 const double lhs = left.getnumber();
2262 const double rhs = right.getnumber();
2265 // If these are both zero, +0 is greater than -0
2266 if (signBitSet(lhs) && !signBitSet(rhs))
2269 result = qMax(lhs, rhs);
2271 output.setnumber(result);
2274 QML_V4_END_INSTR(MathMaxNumber, binaryop)
2276 QML_V4_BEGIN_INSTR(MathMinNumber, binaryop)
2278 const Register &left = registers[instr->binaryop.left];
2279 const Register &right = registers[instr->binaryop.right];
2280 Register &output = registers[instr->binaryop.output];
2281 if (left.isUndefined() || right.isUndefined()) {
2282 output.setUndefined();
2284 const double lhs = left.getnumber();
2285 const double rhs = right.getnumber();
2288 // If these are both zero, -0 is lesser than +0
2289 if (!signBitSet(lhs) && signBitSet(rhs))
2292 result = qMin(lhs, rhs);
2294 output.setnumber(result);
2297 QML_V4_END_INSTR(MathMinNumber, binaryop)
2299 QML_V4_BEGIN_INSTR(NewString, construct)
2301 Register &output = registers[instr->construct.reg];
2302 new (output.getstringptr()) QString;
2303 STRING_REGISTER(instr->construct.reg);
2305 QML_V4_END_INSTR(NewString, construct)
2307 QML_V4_BEGIN_INSTR(NewUrl, construct)
2309 Register &output = registers[instr->construct.reg];
2310 new (output.geturlptr()) QUrl;
2311 URL_REGISTER(instr->construct.reg);
2313 QML_V4_END_INSTR(NewUrl, construct)
2315 QML_V4_BEGIN_INSTR(Fetch, fetch)
2317 Register ® = registers[instr->fetch.reg];
2319 if (reg.isUndefined())
2320 THROW_EXCEPTION(instr->fetch.exceptionId);
2322 QObject *object = reg.getQObject();
2324 THROW_EXCEPTION(instr->fetch.exceptionId);
2326 if (bindingInvalidated(invalidated, object, context, instr->fetch.index))
2329 const Register::Type valueType = (Register::Type)instr->fetch.valueType;
2330 reg.init(valueType);
2331 if (instr->fetch.valueType >= FirstCleanupType)
2332 MARK_REGISTER(instr->fetch.reg);
2334 QQmlData::flushPendingBinding(object, instr->fetch.index);
2336 void *argv[] = { reg.typeDataPtr(), 0 };
2337 QMetaObject::metacall(object, QMetaObject::ReadProperty, instr->fetch.index, argv);
2338 if (valueType == FloatType) {
2340 const double v = reg.getfloat();
2344 if (instr->fetch.subIndex != static_cast<quint32>(-1))
2345 subscribe(object, instr->fetch.subIndex, instr->fetch.subOffset, context->engine);
2349 QML_V4_END_INSTR(Fetch, fetch)
2351 QML_V4_BEGIN_INSTR(TestV4Store, storetest)
2353 Register &data = registers[instr->storetest.reg];
2354 testBindingResult(*testBindingSource, bindingLine, bindingColumn, context,
2355 scope, data, instr->storetest.regType);
2357 QML_V4_END_INSTR(TestV4Store, storetest)
2359 QML_V4_BEGIN_INSTR(Store, store)
2361 Register &data = registers[instr->store.reg];
2363 if (data.isUndefined())
2364 THROW_EXCEPTION_STR(instr->store.exceptionId, QLatin1String("Unable to assign undefined value"));
2366 if (data.gettype() == QObjectStarType) {
2367 if (QObject *dataObject = data.getQObject()) {
2368 QQmlMetaObject dataMo(dataObject);
2370 QQmlEnginePrivate *ep = QQmlEnginePrivate::get(context->engine);
2372 QQmlMetaObject receiverMo;
2374 if (QQmlData::get(output, false) && QQmlData::get(output, false)->propertyCache) {
2375 QQmlPropertyData *receiver =
2376 QQmlData::get(output, false)->propertyCache->property(instr->store.index);
2377 receiverMo = ep->rawMetaObjectForType(receiver->propType);
2379 QMetaProperty receiver = output->metaObject()->property(instr->store.index);
2380 receiverMo = ep->rawMetaObjectForType(receiver.userType());
2383 // Verify that these types are compatible
2384 if (!QQmlMetaObject::canConvert(dataMo, receiverMo)) {
2385 THROW_EXCEPTION_STR(instr->store.exceptionId, QLatin1String("Unable to assign ") +
2386 QLatin1String(dataMo.className()) +
2387 QLatin1String(" to ") +
2388 QLatin1String(receiverMo.className()));
2393 if (instr->store.valueType == FloatType) {
2394 // cast numbers to floats
2395 const float v = (float) data.getnumber();
2399 if (data.gettype() == V8HandleType) {
2400 // This property must be a VME var property
2401 QQmlVMEMetaObject *vmemo = QQmlVMEMetaObject::get(output);
2403 vmemo->setVMEProperty(instr->store.index, *data.gethandleptr());
2406 void *argv[] = { data.typeDataPtr(), 0, &status, &storeFlags };
2407 QMetaObject::metacall(output, QMetaObject::WriteProperty,
2408 instr->store.index, argv);
2413 QML_V4_END_INSTR(Store, store)
2415 QML_V4_BEGIN_INSTR(Copy, copy)
2416 registers[instr->copy.reg].copy(registers[instr->copy.src]);
2417 if (registers[instr->copy.reg].gettype() >= FirstCleanupType)
2418 MARK_REGISTER(instr->copy.reg);
2419 QML_V4_END_INSTR(Copy, copy)
2421 QML_V4_BEGIN_INSTR(Jump, jump)
2422 if (instr->jump.reg == -1 || !registers[instr->jump.reg].getbool())
2423 code += instr->jump.count;
2424 QML_V4_END_INSTR(Jump, jump)
2426 QML_V4_BEGIN_INSTR(BranchTrue, branchop)
2427 if (registers[instr->branchop.reg].getbool())
2428 code += instr->branchop.offset;
2429 QML_V4_END_INSTR(BranchTrue, branchop)
2431 QML_V4_BEGIN_INSTR(BranchFalse, branchop)
2432 if (! registers[instr->branchop.reg].getbool())
2433 code += instr->branchop.offset;
2434 QML_V4_END_INSTR(BranchFalse, branchop)
2436 QML_V4_BEGIN_INSTR(Branch, branchop)
2437 code += instr->branchop.offset;
2438 QML_V4_END_INSTR(Branch, branchop)
2440 QML_V4_BEGIN_INSTR(Block, blockop)
2441 executedBlocks |= instr->blockop.block;
2442 QML_V4_END_INSTR(Block, blockop)
2444 QML_V4_BEGIN_INSTR(CleanupRegister, cleanup)
2445 registers[instr->cleanup.reg].cleanup();
2446 QML_V4_END_INSTR(CleanupRegister, cleanup)
2448 QML_V4_BEGIN_INSTR(Throw, throwop)
2449 THROW_VALUE_EXCEPTION_STR(instr->throwop.exceptionId, *registers[instr->throwop.message].getstringptr());
2450 QML_V4_END_INSTR(Throw, throwop)
2452 #ifdef QML_THREADED_INTERPRETER
2456 qFatal("QV4: Unknown instruction %d encountered.", instr->common.type);
2463 Q_ASSERT(!"Unreachable code reached");
2467 delete testBindingSource;
2470 while (cleanupRegisterMask) {
2471 if (cleanupRegisterMask & 0x1)
2472 registers[reg].cleanup();
2475 cleanupRegisterMask >>= 1;