1 /****************************************************************************
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
7 ** This file is part of the QtDeclarative module of the Qt Toolkit.
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser General Public
12 ** License version 2.1 as published by the Free Software Foundation and
13 ** appearing in the file LICENSE.LGPL included in the packaging of this
14 ** file. Please review the following information to ensure the GNU Lesser
15 ** General Public License version 2.1 requirements will be met:
16 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
18 ** In addition, as a special exception, Nokia gives you certain additional
19 ** rights. These rights are described in the Nokia Qt LGPL Exception
20 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
22 ** GNU General Public License Usage
23 ** Alternatively, this file may be used under the terms of the GNU General
24 ** Public License version 3.0 as published by the Free Software Foundation
25 ** and appearing in the file LICENSE.GPL included in the packaging of this
26 ** file. Please review the following information to ensure the GNU General
27 ** Public License version 3.0 requirements will be met:
28 ** http://www.gnu.org/copyleft/gpl.html.
31 ** Alternatively, this file may be used in accordance with the terms and
32 ** 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/qdeclarativefastproperties_p.h>
50 #include <private/qdeclarativedebugtrace_p.h>
51 #include <private/qquickanchors_p_p.h> // For AnchorLine
53 #include <QtDeclarative/qdeclarativeinfo.h>
54 #include <QtCore/qnumeric.h>
55 #include <QtCore/qmath.h>
56 #include <math.h> // ::fmod
60 using namespace QDeclarativeJS;
64 typedef QDeclarativeRegisterType Type;
66 void setUndefined() { dataType = UndefinedType; }
67 void setNaN() { setqreal(qSNaN()); }
68 bool isUndefined() const { return dataType == UndefinedType; }
70 void setQObject(QObject *o) { qobjectValue = o; dataType = QObjectStarType; }
71 QObject *getQObject() const { return qobjectValue; }
73 void setqreal(qreal v) { qrealValue = v; dataType = QRealType; }
74 qreal getqreal() const { return qrealValue; }
75 qreal &getqrealref() { return qrealValue; }
77 void setint(int v) { intValue = v; dataType = IntType; }
78 int getint() const { return intValue; }
79 int &getintref() { return intValue; }
81 void setbool(bool v) { boolValue = v; dataType = BoolType; }
82 bool getbool() const { return boolValue; }
83 bool &getboolref() { return boolValue; }
85 QVariant *getvariantptr() { return (QVariant *)typeDataPtr(); }
86 QString *getstringptr() { return (QString *)typeDataPtr(); }
87 QUrl *geturlptr() { return (QUrl *)typeDataPtr(); }
88 const QVariant *getvariantptr() const { return (QVariant *)typeDataPtr(); }
89 const QString *getstringptr() const { return (QString *)typeDataPtr(); }
90 const QUrl *geturlptr() const { return (QUrl *)typeDataPtr(); }
92 void *typeDataPtr() { return (void *)&data; }
93 void *typeMemory() { return (void *)data; }
94 const void *typeDataPtr() const { return (void *)&data; }
95 const void *typeMemory() const { return (void *)data; }
97 Type gettype() const { return dataType; }
98 void settype(Type t) { dataType = t; }
100 Type dataType; // Type of data
102 QObject *qobjectValue;
106 void *data[sizeof(QVariant)];
107 qint64 q_for_alignment_1;
108 double q_for_alignment_2;
111 inline void cleanup();
112 inline void cleanupString();
113 inline void cleanupUrl();
114 inline void cleanupVariant();
116 inline void copy(const Register &other);
117 inline void init(Type type);
118 #ifdef REGISTER_CLEANUP_DEBUG
124 if (dataType >= FirstCleanupType)
125 qWarning("Register leaked of type %d", dataType);
130 void Register::cleanup()
132 if (dataType >= FirstCleanupType) {
133 if (dataType == QStringType) {
134 getstringptr()->~QString();
135 } else if (dataType == QUrlType) {
136 geturlptr()->~QUrl();
137 } else if (dataType == QVariantType) {
138 getvariantptr()->~QVariant();
144 void Register::cleanupString()
146 getstringptr()->~QString();
150 void Register::cleanupUrl()
152 geturlptr()->~QUrl();
156 void Register::cleanupVariant()
158 getvariantptr()->~QVariant();
162 void Register::copy(const Register &other)
165 if (other.dataType >= FirstCleanupType) {
166 if (other.dataType == QStringType)
167 new (getstringptr()) QString(*other.getstringptr());
168 else if (other.dataType == QUrlType)
169 new (geturlptr()) QUrl(*other.geturlptr());
170 else if (other.dataType == QVariantType)
171 new (getvariantptr()) QVariant(*other.getvariantptr());
175 void Register::init(Type type)
178 if (dataType >= FirstCleanupType) {
179 if (dataType == QStringType)
180 new (getstringptr()) QString();
181 else if (dataType == QUrlType)
182 new (geturlptr()) QUrl();
183 else if (dataType == QVariantType)
184 new (getvariantptr()) QVariant();
188 } // end of anonymous namespace
190 QV4Bindings::QV4Bindings(const char *programData,
191 QDeclarativeContextData *context,
192 QDeclarativeRefCount *ref)
193 : subscriptions(0), program(0), dataRef(0), bindings(0)
195 program = (QV4Program *)programData;
197 if (dataRef) dataRef->addref();
200 subscriptions = new Subscription[program->subscriptions];
201 bindings = new Binding[program->bindings];
203 QDeclarativeAbstractExpression::setContext(context);
207 QV4Bindings::~QV4Bindings()
210 delete [] subscriptions; subscriptions = 0;
211 if (dataRef) dataRef->release();
214 QDeclarativeAbstractBinding *QV4Bindings::configBinding(int index, QObject *target,
215 QObject *scope, int property)
217 Binding *rv = bindings + index;
220 rv->property = property;
225 addref(); // This is decremented in Binding::destroy()
230 void QV4Bindings::Binding::setEnabled(bool e, QDeclarativePropertyPrivate::WriteFlags flags)
235 if (e) update(flags);
239 void QV4Bindings::Binding::update(QDeclarativePropertyPrivate::WriteFlags flags)
241 QDeclarativeDebugTrace::startRange(QDeclarativeDebugTrace::Binding);
242 parent->run(this, flags);
243 QDeclarativeDebugTrace::endRange(QDeclarativeDebugTrace::Binding);
246 void QV4Bindings::Binding::destroy()
255 void QV4Bindings::Subscription::subscriptionCallback(QDeclarativeNotifierEndpoint *e)
257 Subscription *s = static_cast<Subscription *>(e);
258 s->bindings->subscriptionNotify(s->method);
261 void QV4Bindings::subscriptionNotify(int id)
263 QV4Program::BindingReferenceList *list = program->signalTable(id);
265 for (quint32 ii = 0; ii < list->count; ++ii) {
266 QV4Program::BindingReference *bindingRef = list->bindings + ii;
268 Binding *binding = bindings + bindingRef->binding;
269 if (binding->executedBlocks & bindingRef->blockMask)
270 run(binding, QDeclarativePropertyPrivate::DontRemoveBinding);
274 void QV4Bindings::run(Binding *binding, QDeclarativePropertyPrivate::WriteFlags flags)
276 if (!binding->enabled)
279 QDeclarativeContextData *context = QDeclarativeAbstractExpression::context();
280 if (!context || !context->isValid())
283 if (binding->updating) {
285 if (binding->property & 0xFFFF0000) {
286 QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(context->engine);
288 QDeclarativeValueType *vt = ep->valueTypes[(binding->property >> 16) & 0xFF];
291 name = QLatin1String(binding->target->metaObject()->property(binding->property & 0xFFFF).name());
292 name.append(QLatin1String("."));
293 name.append(QLatin1String(vt->metaObject()->property(binding->property >> 24).name()));
295 name = QLatin1String(binding->target->metaObject()->property(binding->property).name());
297 qmlInfo(binding->target) << tr("Binding loop detected for property \"%1\"").arg(name);
301 binding->updating = true;
302 if (binding->property & 0xFFFF0000) {
303 QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(context->engine);
305 QDeclarativeValueType *vt = ep->valueTypes[(binding->property >> 16) & 0xFF];
307 vt->read(binding->target, binding->property & 0xFFFF);
309 QObject *target = vt;
310 run(binding->index, binding->executedBlocks, context, binding, binding->scope, target, flags);
312 vt->write(binding->target, binding->property & 0xFFFF, flags);
314 run(binding->index, binding->executedBlocks, context, binding, binding->scope, binding->target, flags);
316 binding->updating = false;
320 void QV4Bindings::unsubscribe(int subIndex)
322 Subscription *sub = (subscriptions + subIndex);
326 void QV4Bindings::subscribeId(QDeclarativeContextData *p, int idIndex, int subIndex)
328 unsubscribe(subIndex);
330 if (p->idValues[idIndex]) {
331 Subscription *sub = (subscriptions + subIndex);
332 sub->bindings = this;
333 sub->method = subIndex;
334 sub->connect(&p->idValues[idIndex].bindings);
338 void QV4Bindings::subscribe(QObject *o, int notifyIndex, int subIndex)
340 Subscription *sub = (subscriptions + subIndex);
341 sub->bindings = this;
342 sub->method = subIndex;
344 sub->connect(o, notifyIndex);
349 // Conversion functions - these MUST match the QtScript expression path
350 inline static qreal toReal(Register *reg, int type, bool *ok = 0)
354 if (type == QMetaType::QReal) {
355 return reg->getqreal();
356 } else if (type == qMetaTypeId<QVariant>()) {
357 return reg->getvariantptr()->toReal();
364 inline static QString toString(Register *reg, int type, bool *ok = 0)
368 if (type == QMetaType::QReal) {
369 return QString::number(reg->getqreal());
370 } else if (type == QMetaType::Int) {
371 return QString::number(reg->getint());
372 } else if (type == qMetaTypeId<QVariant>()) {
373 return reg->getvariantptr()->toString();
374 } else if (type == QMetaType::QString) {
375 return *reg->getstringptr();
382 inline static bool toBool(Register *reg, int type, bool *ok = 0)
386 if (type == QMetaType::Bool) {
387 return reg->getbool();
388 } else if (type == qMetaTypeId<QVariant>()) {
389 return reg->getvariantptr()->toBool();
396 inline static QUrl toUrl(Register *reg, int type, QDeclarativeContextData *context, bool *ok = 0)
401 if (type == qMetaTypeId<QVariant>()) {
402 QVariant *var = reg->getvariantptr();
403 int vt = var->type();
404 if (vt == QVariant::Url) {
406 } else if (vt == QVariant::ByteArray) {
407 base = QUrl(QString::fromUtf8(var->toByteArray()));
408 } else if (vt == QVariant::String) {
409 base = QUrl(var->toString());
414 } else if (type == QMetaType::QString) {
415 base = QUrl(*reg->getstringptr());
421 if (!base.isEmpty() && base.isRelative())
422 return context->url.resolved(base);
427 static bool testCompareVariants(const QVariant &qtscriptRaw, const QVariant &v4)
429 QVariant qtscript = qtscriptRaw;
431 if (qtscript.userType() == v4.userType()) {
432 } else if (qtscript.canConvert((QVariant::Type)v4.userType())) {
433 qtscript.convert((QVariant::Type)v4.userType());
434 } else if (qtscript.userType() == QVariant::Invalid && v4.userType() == QMetaType::QObjectStar) {
435 qtscript = qVariantFromValue<QObject *>(0);
440 int type = qtscript.userType();
442 if (type == qMetaTypeId<QDeclarative1AnchorLine>()) {
443 QDeclarative1AnchorLine la = qvariant_cast<QDeclarative1AnchorLine>(qtscript);
444 QDeclarative1AnchorLine ra = qvariant_cast<QDeclarative1AnchorLine>(v4);
447 } else if (type == qMetaTypeId<QQuickAnchorLine>()) {
448 QQuickAnchorLine la = qvariant_cast<QQuickAnchorLine>(qtscript);
449 QQuickAnchorLine ra = qvariant_cast<QQuickAnchorLine>(v4);
452 } else if (type == QMetaType::Double) {
454 double la = qvariant_cast<double>(qtscript);
455 double lr = qvariant_cast<double>(v4);
457 return la == lr || (qIsNaN(la) && qIsNaN(lr));
459 } else if (type == QMetaType::Float) {
461 float la = qvariant_cast<float>(qtscript);
462 float lr = qvariant_cast<float>(v4);
464 return la == lr || (qIsNaN(la) && qIsNaN(lr));
467 return qtscript == v4;
471 QByteArray testResultToString(const QVariant &result, bool undefined)
483 static void testBindingResult(const QString &binding, int line, int column,
484 QDeclarativeContextData *context, QObject *scope,
485 const Register &result, int resultType)
487 QDeclarativeExpression expression(context->asQDeclarativeContext(), scope, binding);
488 bool isUndefined = false;
489 QVariant value = expression.evaluate(&isUndefined);
491 bool iserror = false;
492 QByteArray qtscriptResult;
495 if (expression.hasError()) {
497 qtscriptResult = "exception";
499 qtscriptResult = testResultToString(value, isUndefined);
502 if (isUndefined && result.isUndefined()) {
504 } else if(isUndefined != result.isUndefined()) {
509 if (!result.isUndefined()) {
510 switch (resultType) {
511 case QMetaType::QString:
512 v4value = *result.getstringptr();
514 case QMetaType::QUrl:
515 v4value = *result.geturlptr();
517 case QMetaType::QObjectStar:
518 v4value = qVariantFromValue<QObject *>(result.getQObject());
520 case QMetaType::Bool:
521 v4value = result.getbool();
524 v4value = result.getint();
526 case QMetaType::QReal:
527 v4value = result.getqreal();
530 if (resultType == qMetaTypeId<QDeclarative1AnchorLine>()) {
531 v4value = qVariantFromValue<QDeclarative1AnchorLine>(*(QDeclarative1AnchorLine *)result.typeDataPtr());
532 } else if (resultType == qMetaTypeId<QQuickAnchorLine>()) {
533 v4value = qVariantFromValue<QQuickAnchorLine>(*(QQuickAnchorLine *)result.typeDataPtr());
536 v4Result = "Unknown V4 type";
540 if (v4Result.isEmpty())
541 v4Result = testResultToString(v4value, result.isUndefined());
543 if (!testCompareVariants(value, v4value))
547 qWarning().nospace() << "QV4: Optimization error @" << context->url.toString().toUtf8().constData() << ":" << line << ":" << column;
549 qWarning().nospace() << " Binding: " << binding;
550 qWarning().nospace() << " QtScript: " << qtscriptResult.constData();
551 qWarning().nospace() << " V4: " << v4Result.constData();
555 static void testBindingException(const QString &binding, int line, int column,
556 QDeclarativeContextData *context, QObject *scope)
558 QDeclarativeExpression expression(context->asQDeclarativeContext(), scope, binding);
559 bool isUndefined = false;
560 QVariant value = expression.evaluate(&isUndefined);
562 if (!expression.hasError()) {
563 QByteArray qtscriptResult = testResultToString(value, isUndefined);
564 qWarning().nospace() << "QV4: Optimization error @" << context->url.toString().toUtf8().constData() << ":" << line << ":" << column;
565 qWarning().nospace() << " Binding: " << binding;
566 qWarning().nospace() << " QtScript: " << qtscriptResult.constData();
567 qWarning().nospace() << " V4: exception";
571 static void throwException(int id, QDeclarativeDelayedError *error,
572 QV4Program *program, QDeclarativeContextData *context,
573 const QString &description = QString())
575 error->error.setUrl(context->url);
576 if (description.isEmpty())
577 error->error.setDescription(QLatin1String("TypeError: Result of expression is not an object"));
579 error->error.setDescription(description);
581 quint64 e = *((quint64 *)(program->data() + program->exceptionDataOffset) + id);
582 error->error.setLine((e >> 32) & 0xFFFFFFFF);
583 error->error.setColumn(e & 0xFFFFFFFF);
585 error->error.setLine(-1);
586 error->error.setColumn(-1);
588 if (!context->engine || !error->addError(QDeclarativeEnginePrivate::get(context->engine)))
589 QDeclarativeEnginePrivate::warning(context->engine, error->error);
592 const qreal QV4Bindings::D32 = 4294967296.0;
594 qint32 QV4Bindings::toInt32(qreal n)
596 if (qIsNaN(n) || qIsInf(n) || (n == 0))
599 double sign = (n < 0) ? -1.0 : 1.0;
600 qreal abs_n = fabs(n);
602 n = ::fmod(sign * ::floor(abs_n), D32);
603 const double D31 = D32 / 2.0;
605 if (sign == -1 && n < -D31)
608 else if (sign != -1 && n >= D31)
614 inline quint32 QV4Bindings::toUint32(qreal n)
616 if (qIsNaN(n) || qIsInf(n) || (n == 0))
619 double sign = (n < 0) ? -1.0 : 1.0;
620 qreal abs_n = fabs(n);
622 n = ::fmod(sign * ::floor(abs_n), D32);
630 #define THROW_EXCEPTION_STR(id, str) { \
631 if (testBinding) testBindingException(*testBindingSource, bindingLine, bindingColumn, context, scope); \
632 throwException((id), error, program, context, (str)); \
633 goto exceptionExit; \
636 #define THROW_EXCEPTION(id) THROW_EXCEPTION_STR(id, QString())
638 #define MARK_REGISTER(reg) cleanupRegisterMask |= (1 << (reg))
639 #define MARK_CLEAN_REGISTER(reg) cleanupRegisterMask &= ~(1 << (reg))
641 #define STRING_REGISTER(reg) { \
642 registers[(reg)].settype(QStringType); \
643 MARK_REGISTER(reg); \
646 #define URL_REGISTER(reg) { \
647 registers[(reg)].settype(QUrlType); \
648 MARK_REGISTER(reg); \
651 #define VARIANT_REGISTER(reg) { \
652 registers[(reg)].settype(QVariantType); \
653 MARK_REGISTER(reg); \
656 #ifdef QML_THREADED_INTERPRETER
657 void **QV4Bindings::getDecodeInstrTable()
659 static void **decode_instr;
661 QV4Bindings *dummy = new QV4Bindings(0, 0, 0);
662 quint32 executedBlocks = 0;
663 dummy->run(0, executedBlocks, 0, 0, 0, 0,
664 QDeclarativePropertyPrivate::BypassInterceptor,
672 void QV4Bindings::run(int instrIndex, quint32 &executedBlocks,
673 QDeclarativeContextData *context, QDeclarativeDelayedError *error,
674 QObject *scope, QObject *output,
675 QDeclarativePropertyPrivate::WriteFlags storeFlags
676 #ifdef QML_THREADED_INTERPRETER
681 #ifdef QML_THREADED_INTERPRETER
683 static void *decode_instr[] = {
684 FOR_EACH_V4_INSTR(QML_V4_INSTR_ADDR)
687 *table = decode_instr;
693 error->removeError();
695 Register registers[32];
696 quint32 cleanupRegisterMask = 0;
700 const char *code = program->instructions();
701 code += instrIndex * QML_V4_INSTR_SIZE(Jump, jump);
702 const V4Instr *instr = reinterpret_cast<const V4Instr *>(code);
704 const char *data = program->data();
706 QString *testBindingSource = 0;
707 bool testBinding = false;
709 int bindingColumn = 0;
711 #ifdef QML_THREADED_INTERPRETER
712 goto *instr->common.code;
715 switch (instr->common.type) {
718 QML_V4_BEGIN_INSTR(Noop, common)
719 QML_V4_END_INSTR(Noop, common)
721 QML_V4_BEGIN_INSTR(BindingId, id)
722 bindingLine = instr->id.line;
723 bindingColumn = instr->id.column;
724 QML_V4_END_INSTR(BindingId, id)
726 QML_V4_BEGIN_INSTR(SubscribeId, subscribeop)
727 subscribeId(context, instr->subscribeop.index, instr->subscribeop.offset);
728 QML_V4_END_INSTR(SubscribeId, subscribeop)
730 QML_V4_BEGIN_INSTR(Subscribe, subscribeop)
733 const Register &object = registers[instr->subscribeop.reg];
734 if (!object.isUndefined()) o = object.getQObject();
735 subscribe(o, instr->subscribeop.index, instr->subscribeop.offset);
737 QML_V4_END_INSTR(Subscribe, subscribeop)
739 QML_V4_BEGIN_INSTR(FetchAndSubscribe, fetchAndSubscribe)
741 Register ® = registers[instr->fetchAndSubscribe.reg];
743 if (reg.isUndefined())
744 THROW_EXCEPTION(instr->fetchAndSubscribe.exceptionId);
746 QObject *object = reg.getQObject();
750 int subIdx = instr->fetchAndSubscribe.subscription;
751 Subscription *sub = 0;
753 sub = (subscriptions + subIdx);
754 sub->bindings = this;
755 sub->method = subIdx;
757 reg.init((Register::Type)instr->fetchAndSubscribe.valueType);
758 if (instr->fetchAndSubscribe.valueType >= FirstCleanupType)
759 MARK_REGISTER(instr->fetchAndSubscribe.reg);
760 QDeclarativeFastProperties::instance()->accessor(instr->fetchAndSubscribe.function)(object, reg.typeDataPtr(), sub);
763 QML_V4_END_INSTR(FetchAndSubscribe, fetchAndSubscribe)
765 QML_V4_BEGIN_INSTR(LoadId, load)
766 registers[instr->load.reg].setQObject(context->idValues[instr->load.index].data());
767 QML_V4_END_INSTR(LoadId, load)
769 QML_V4_BEGIN_INSTR(LoadScope, load)
770 registers[instr->load.reg].setQObject(scope);
771 QML_V4_END_INSTR(LoadScope, load)
773 QML_V4_BEGIN_INSTR(LoadRoot, load)
774 registers[instr->load.reg].setQObject(context->contextObject);
775 QML_V4_END_INSTR(LoadRoot, load)
777 QML_V4_BEGIN_INSTR(LoadAttached, attached)
779 const Register &input = registers[instr->attached.reg];
780 Register &output = registers[instr->attached.output];
781 if (input.isUndefined())
782 THROW_EXCEPTION(instr->attached.exceptionId);
784 QObject *object = registers[instr->attached.reg].getQObject();
786 output.setUndefined();
788 QObject *attached = qmlAttachedPropertiesObjectById(instr->attached.id, input.getQObject(), true);
790 output.setQObject(attached);
793 QML_V4_END_INSTR(LoadAttached, attached)
795 QML_V4_BEGIN_INSTR(UnaryNot, unaryop)
797 registers[instr->unaryop.output].setbool(!registers[instr->unaryop.src].getbool());
799 QML_V4_END_INSTR(UnaryNot, unaryop)
801 QML_V4_BEGIN_INSTR(UnaryMinusReal, unaryop)
803 registers[instr->unaryop.output].setqreal(-registers[instr->unaryop.src].getqreal());
805 QML_V4_END_INSTR(UnaryMinusReal, unaryop)
807 QML_V4_BEGIN_INSTR(UnaryMinusInt, unaryop)
809 registers[instr->unaryop.output].setint(-registers[instr->unaryop.src].getint());
811 QML_V4_END_INSTR(UnaryMinusInt, unaryop)
813 QML_V4_BEGIN_INSTR(UnaryPlusReal, unaryop)
815 registers[instr->unaryop.output].setqreal(+registers[instr->unaryop.src].getqreal());
817 QML_V4_END_INSTR(UnaryPlusReal, unaryop)
819 QML_V4_BEGIN_INSTR(UnaryPlusInt, unaryop)
821 registers[instr->unaryop.output].setint(+registers[instr->unaryop.src].getint());
823 QML_V4_END_INSTR(UnaryPlusInt, unaryop)
825 QML_V4_BEGIN_INSTR(ConvertBoolToInt, unaryop)
827 const Register &src = registers[instr->unaryop.src];
828 Register &output = registers[instr->unaryop.output];
829 if (src.isUndefined()) output.setUndefined();
830 else output.setint(src.getbool());
832 QML_V4_END_INSTR(ConvertBoolToInt, unaryop)
834 QML_V4_BEGIN_INSTR(ConvertBoolToReal, unaryop)
836 const Register &src = registers[instr->unaryop.src];
837 Register &output = registers[instr->unaryop.output];
838 if (src.isUndefined()) output.setUndefined();
839 else output.setqreal(src.getbool());
841 QML_V4_END_INSTR(ConvertBoolToReal, unaryop)
843 QML_V4_BEGIN_INSTR(ConvertBoolToString, unaryop)
845 const Register &src = registers[instr->unaryop.src];
846 Register &output = registers[instr->unaryop.output];
847 if (src.isUndefined()) {
848 output.setUndefined();
850 new (output.getstringptr()) QString(QLatin1String(src.getbool() ? "true" : "false"));
851 STRING_REGISTER(instr->unaryop.output);
854 QML_V4_END_INSTR(ConvertBoolToString, unaryop)
856 QML_V4_BEGIN_INSTR(ConvertIntToBool, unaryop)
858 const Register &src = registers[instr->unaryop.src];
859 Register &output = registers[instr->unaryop.output];
860 if (src.isUndefined()) output.setUndefined();
861 else output.setbool(src.getint());
863 QML_V4_END_INSTR(ConvertIntToBool, unaryop)
865 QML_V4_BEGIN_INSTR(ConvertIntToReal, unaryop)
867 const Register &src = registers[instr->unaryop.src];
868 Register &output = registers[instr->unaryop.output];
869 if (src.isUndefined()) output.setUndefined();
870 else output.setqreal(qreal(src.getint()));
872 QML_V4_END_INSTR(ConvertIntToReal, unaryop)
874 QML_V4_BEGIN_INSTR(ConvertIntToString, unaryop)
876 const Register &src = registers[instr->unaryop.src];
877 Register &output = registers[instr->unaryop.output];
878 if (src.isUndefined()) {
879 output.setUndefined();
881 new (output.getstringptr()) QString(QString::number(src.getint()));
882 STRING_REGISTER(instr->unaryop.output);
885 QML_V4_END_INSTR(ConvertIntToString, unaryop)
887 QML_V4_BEGIN_INSTR(ConvertRealToBool, unaryop)
889 const Register &src = registers[instr->unaryop.src];
890 Register &output = registers[instr->unaryop.output];
891 if (src.isUndefined()) output.setUndefined();
892 else output.setbool(src.getqreal() != 0);
894 QML_V4_END_INSTR(ConvertRealToBool, unaryop)
896 QML_V4_BEGIN_INSTR(ConvertRealToInt, unaryop)
898 const Register &src = registers[instr->unaryop.src];
899 Register &output = registers[instr->unaryop.output];
900 if (src.isUndefined()) output.setUndefined();
901 else output.setint(toInt32(src.getqreal()));
903 QML_V4_END_INSTR(ConvertRealToInt, unaryop)
905 QML_V4_BEGIN_INSTR(ConvertRealToString, unaryop)
907 const Register &src = registers[instr->unaryop.src];
908 Register &output = registers[instr->unaryop.output];
910 if (src.isUndefined()) {
911 output.setUndefined();
913 new (output.getstringptr()) QString(QString::number(src.getqreal()));
914 STRING_REGISTER(instr->unaryop.output);
917 QML_V4_END_INSTR(ConvertRealToString, unaryop)
919 QML_V4_BEGIN_INSTR(ConvertStringToBool, unaryop)
921 const Register &src = registers[instr->unaryop.src];
922 Register &output = registers[instr->unaryop.output];
924 if (src.isUndefined()) {
925 output.setUndefined();
927 // Delegate the conversion. This is pretty fast and it doesn't require a QScriptEngine.
928 // Ideally we should just call the methods in the QScript namespace directly.
929 QJSValue tmp(*src.getstringptr());
930 if (instr->unaryop.src == instr->unaryop.output) {
931 output.cleanupString();
932 MARK_CLEAN_REGISTER(instr->unaryop.output);
934 output.setbool(tmp.toBool());
937 QML_V4_END_INSTR(ConvertStringToBool, unaryop)
939 QML_V4_BEGIN_INSTR(ConvertStringToInt, unaryop)
941 const Register &src = registers[instr->unaryop.src];
942 Register &output = registers[instr->unaryop.output];
944 if (src.isUndefined()) {
945 output.setUndefined();
947 // Delegate the conversion. This is pretty fast and it doesn't require a QScriptEngine.
948 // Ideally we should just call the methods in the QScript namespace directly.
949 QJSValue tmp(*src.getstringptr());
950 if (instr->unaryop.src == instr->unaryop.output) {
951 output.cleanupString();
952 MARK_CLEAN_REGISTER(instr->unaryop.output);
954 output.setint(tmp.toInt32());
957 QML_V4_END_INSTR(ConvertStringToInt, unaryop)
959 QML_V4_BEGIN_INSTR(ConvertStringToReal, unaryop)
961 const Register &src = registers[instr->unaryop.src];
962 Register &output = registers[instr->unaryop.output];
964 if (src.isUndefined()) {
965 output.setUndefined();
967 // Delegate the conversion. This is pretty fast and it doesn't require a QScriptEngine.
968 // Ideally we should just call the methods in the QScript namespace directly.
969 QJSValue tmp(*src.getstringptr());
970 if (instr->unaryop.src == instr->unaryop.output) {
971 output.cleanupString();
972 MARK_CLEAN_REGISTER(instr->unaryop.output);
974 output.setqreal(tmp.toNumber());
977 QML_V4_END_INSTR(ConvertStringToReal, unaryop)
979 QML_V4_BEGIN_INSTR(MathSinReal, unaryop)
981 const Register &src = registers[instr->unaryop.src];
982 Register &output = registers[instr->unaryop.output];
983 if (src.isUndefined()) output.setUndefined();
984 else output.setqreal(qSin(src.getqreal()));
986 QML_V4_END_INSTR(MathSinReal, unaryop)
988 QML_V4_BEGIN_INSTR(MathCosReal, unaryop)
990 const Register &src = registers[instr->unaryop.src];
991 Register &output = registers[instr->unaryop.output];
992 if (src.isUndefined()) output.setUndefined();
993 else output.setqreal(qCos(src.getqreal()));
995 QML_V4_END_INSTR(MathCosReal, unaryop)
997 QML_V4_BEGIN_INSTR(MathRoundReal, unaryop)
999 const Register &src = registers[instr->unaryop.src];
1000 Register &output = registers[instr->unaryop.output];
1001 if (src.isUndefined()) output.setUndefined();
1002 else output.setint(qRound(src.getqreal()));
1004 QML_V4_END_INSTR(MathRoundReal, unaryop)
1006 QML_V4_BEGIN_INSTR(MathFloorReal, unaryop)
1008 const Register &src = registers[instr->unaryop.src];
1009 Register &output = registers[instr->unaryop.output];
1010 if (src.isUndefined()) output.setUndefined();
1011 else output.setint(qFloor(src.getqreal()));
1013 QML_V4_END_INSTR(MathFloorReal, unaryop)
1015 QML_V4_BEGIN_INSTR(MathPIReal, unaryop)
1017 static const qreal qmlPI = 2.0 * qAsin(1.0);
1018 Register &output = registers[instr->unaryop.output];
1019 output.setqreal(qmlPI);
1021 QML_V4_END_INSTR(MathPIReal, unaryop)
1023 QML_V4_BEGIN_INSTR(LoadReal, real_value)
1024 registers[instr->real_value.reg].setqreal(instr->real_value.value);
1025 QML_V4_END_INSTR(LoadReal, real_value)
1027 QML_V4_BEGIN_INSTR(LoadInt, int_value)
1028 registers[instr->int_value.reg].setint(instr->int_value.value);
1029 QML_V4_END_INSTR(LoadInt, int_value)
1031 QML_V4_BEGIN_INSTR(LoadBool, bool_value)
1032 registers[instr->bool_value.reg].setbool(instr->bool_value.value);
1033 QML_V4_END_INSTR(LoadBool, bool_value)
1035 QML_V4_BEGIN_INSTR(LoadString, string_value)
1037 Register &output = registers[instr->string_value.reg];
1038 QChar *string = (QChar *)(data + instr->string_value.offset);
1039 new (output.getstringptr()) QString(string, instr->string_value.length);
1040 STRING_REGISTER(instr->string_value.reg);
1042 QML_V4_END_INSTR(LoadString, string_value)
1044 QML_V4_BEGIN_INSTR(EnableV4Test, string_value)
1046 testBindingSource = new QString((QChar *)(data + instr->string_value.offset), instr->string_value.length);
1049 QML_V4_END_INSTR(String, string_value)
1051 QML_V4_BEGIN_INSTR(BitAndInt, binaryop)
1053 registers[instr->binaryop.output].setint(registers[instr->binaryop.left].getint() &
1054 registers[instr->binaryop.right].getint());
1056 QML_V4_END_INSTR(BitAndInt, binaryop)
1058 QML_V4_BEGIN_INSTR(BitOrInt, binaryop)
1060 registers[instr->binaryop.output].setint(registers[instr->binaryop.left].getint() |
1061 registers[instr->binaryop.right].getint());
1063 QML_V4_END_INSTR(BitAndInt, binaryop)
1065 QML_V4_BEGIN_INSTR(BitXorInt, binaryop)
1067 registers[instr->binaryop.output].setint(registers[instr->binaryop.left].getint() ^
1068 registers[instr->binaryop.right].getint());
1070 QML_V4_END_INSTR(BitXorInt, binaryop)
1072 QML_V4_BEGIN_INSTR(AddReal, binaryop)
1074 registers[instr->binaryop.output].setqreal(registers[instr->binaryop.left].getqreal() +
1075 registers[instr->binaryop.right].getqreal());
1077 QML_V4_END_INSTR(AddReal, binaryop)
1079 QML_V4_BEGIN_INSTR(AddString, binaryop)
1081 QString &string = *registers[instr->binaryop.output].getstringptr();
1082 if (instr->binaryop.output == instr->binaryop.left) {
1083 string += registers[instr->binaryop.right].getstringptr();
1085 string = *registers[instr->binaryop.left].getstringptr() +
1086 *registers[instr->binaryop.right].getstringptr();
1089 QML_V4_END_INSTR(AddString, binaryop)
1091 QML_V4_BEGIN_INSTR(SubReal, binaryop)
1093 registers[instr->binaryop.output].setqreal(registers[instr->binaryop.left].getqreal() -
1094 registers[instr->binaryop.right].getqreal());
1096 QML_V4_END_INSTR(SubReal, binaryop)
1098 QML_V4_BEGIN_INSTR(MulReal, binaryop)
1100 registers[instr->binaryop.output].setqreal(registers[instr->binaryop.left].getqreal() *
1101 registers[instr->binaryop.right].getqreal());
1103 QML_V4_END_INSTR(MulReal, binaryop)
1105 QML_V4_BEGIN_INSTR(DivReal, binaryop)
1107 registers[instr->binaryop.output].setqreal(registers[instr->binaryop.left].getqreal() /
1108 registers[instr->binaryop.right].getqreal());
1110 QML_V4_END_INSTR(DivReal, binaryop)
1112 QML_V4_BEGIN_INSTR(ModReal, binaryop)
1114 Register &target = registers[instr->binaryop.output];
1115 const Register &left = registers[instr->binaryop.left];
1116 const Register &right = registers[instr->binaryop.right];
1117 if (QMetaType::QReal == QMetaType::Float)
1118 target.setqreal(::fmodf(left.getqreal(), right.getqreal()));
1120 target.setqreal(::fmod(left.getqreal(), right.getqreal()));
1122 QML_V4_END_INSTR(ModInt, binaryop)
1124 QML_V4_BEGIN_INSTR(LShiftInt, binaryop)
1126 registers[instr->binaryop.output].setint(registers[instr->binaryop.left].getint() <<
1127 registers[instr->binaryop.right].getint());
1129 QML_V4_END_INSTR(LShiftInt, binaryop)
1131 QML_V4_BEGIN_INSTR(RShiftInt, binaryop)
1133 registers[instr->binaryop.output].setint(registers[instr->binaryop.left].getint() >>
1134 registers[instr->binaryop.right].getint());
1136 QML_V4_END_INSTR(RShiftInt, binaryop)
1138 QML_V4_BEGIN_INSTR(URShiftInt, binaryop)
1140 registers[instr->binaryop.output].setint((unsigned)registers[instr->binaryop.left].getint() >>
1141 registers[instr->binaryop.right].getint());
1143 QML_V4_END_INSTR(URShiftInt, binaryop)
1145 QML_V4_BEGIN_INSTR(GtReal, binaryop)
1147 registers[instr->binaryop.output].setbool(registers[instr->binaryop.left].getqreal() >
1148 registers[instr->binaryop.right].getqreal());
1150 QML_V4_END_INSTR(GtReal, binaryop)
1152 QML_V4_BEGIN_INSTR(LtReal, binaryop)
1154 registers[instr->binaryop.output].setbool(registers[instr->binaryop.left].getqreal() <
1155 registers[instr->binaryop.right].getqreal());
1157 QML_V4_END_INSTR(LtReal, binaryop)
1159 QML_V4_BEGIN_INSTR(GeReal, binaryop)
1161 registers[instr->binaryop.output].setbool(registers[instr->binaryop.left].getqreal() >=
1162 registers[instr->binaryop.right].getqreal());
1164 QML_V4_END_INSTR(GeReal, binaryop)
1166 QML_V4_BEGIN_INSTR(LeReal, binaryop)
1168 registers[instr->binaryop.output].setbool(registers[instr->binaryop.left].getqreal() <=
1169 registers[instr->binaryop.right].getqreal());
1171 QML_V4_END_INSTR(LeReal, binaryop)
1173 QML_V4_BEGIN_INSTR(EqualReal, binaryop)
1175 registers[instr->binaryop.output].setbool(registers[instr->binaryop.left].getqreal() ==
1176 registers[instr->binaryop.right].getqreal());
1178 QML_V4_END_INSTR(EqualReal, binaryop)
1180 QML_V4_BEGIN_INSTR(NotEqualReal, binaryop)
1182 registers[instr->binaryop.output].setbool(registers[instr->binaryop.left].getqreal() !=
1183 registers[instr->binaryop.right].getqreal());
1185 QML_V4_END_INSTR(NotEqualReal, binaryop)
1187 QML_V4_BEGIN_INSTR(StrictEqualReal, binaryop)
1189 registers[instr->binaryop.output].setbool(registers[instr->binaryop.left].getqreal() ==
1190 registers[instr->binaryop.right].getqreal());
1192 QML_V4_END_INSTR(StrictEqualReal, binaryop)
1194 QML_V4_BEGIN_INSTR(StrictNotEqualReal, binaryop)
1196 registers[instr->binaryop.output].setbool(registers[instr->binaryop.left].getqreal() !=
1197 registers[instr->binaryop.right].getqreal());
1199 QML_V4_END_INSTR(StrictNotEqualReal, binaryop)
1201 QML_V4_BEGIN_INSTR(GtString, binaryop)
1203 const QString &a = *registers[instr->binaryop.left].getstringptr();
1204 const QString &b = *registers[instr->binaryop.right].getstringptr();
1205 bool result = a > b;
1206 if (instr->binaryop.left == instr->binaryop.output) {
1207 registers[instr->binaryop.output].cleanupString();
1208 MARK_CLEAN_REGISTER(instr->binaryop.output);
1210 registers[instr->binaryop.output].setbool(result);
1212 QML_V4_END_INSTR(GtString, binaryop)
1214 QML_V4_BEGIN_INSTR(LtString, binaryop)
1216 const QString &a = *registers[instr->binaryop.left].getstringptr();
1217 const QString &b = *registers[instr->binaryop.right].getstringptr();
1218 bool result = a < b;
1219 if (instr->binaryop.left == instr->binaryop.output) {
1220 registers[instr->binaryop.output].cleanupString();
1221 MARK_CLEAN_REGISTER(instr->binaryop.output);
1223 registers[instr->binaryop.output].setbool(result);
1225 QML_V4_END_INSTR(LtString, binaryop)
1227 QML_V4_BEGIN_INSTR(GeString, binaryop)
1229 const QString &a = *registers[instr->binaryop.left].getstringptr();
1230 const QString &b = *registers[instr->binaryop.right].getstringptr();
1231 bool result = a >= b;
1232 if (instr->binaryop.left == instr->binaryop.output) {
1233 registers[instr->binaryop.output].cleanupString();
1234 MARK_CLEAN_REGISTER(instr->binaryop.output);
1236 registers[instr->binaryop.output].setbool(result);
1238 QML_V4_END_INSTR(GeString, binaryop)
1240 QML_V4_BEGIN_INSTR(LeString, binaryop)
1242 const QString &a = *registers[instr->binaryop.left].getstringptr();
1243 const QString &b = *registers[instr->binaryop.right].getstringptr();
1244 bool result = a <= b;
1245 if (instr->binaryop.left == instr->binaryop.output) {
1246 registers[instr->binaryop.output].cleanupString();
1247 MARK_CLEAN_REGISTER(instr->binaryop.output);
1249 registers[instr->binaryop.output].setbool(result);
1251 QML_V4_END_INSTR(LeString, binaryop)
1253 QML_V4_BEGIN_INSTR(EqualString, binaryop)
1255 const QString &a = *registers[instr->binaryop.left].getstringptr();
1256 const QString &b = *registers[instr->binaryop.right].getstringptr();
1257 bool result = a == b;
1258 if (instr->binaryop.left == instr->binaryop.output) {
1259 registers[instr->binaryop.output].cleanupString();
1260 MARK_CLEAN_REGISTER(instr->binaryop.output);
1262 registers[instr->binaryop.output].setbool(result);
1264 QML_V4_END_INSTR(EqualString, binaryop)
1266 QML_V4_BEGIN_INSTR(NotEqualString, binaryop)
1268 const QString &a = *registers[instr->binaryop.left].getstringptr();
1269 const QString &b = *registers[instr->binaryop.right].getstringptr();
1270 bool result = a != b;
1271 if (instr->binaryop.left == instr->binaryop.output) {
1272 registers[instr->binaryop.output].cleanupString();
1273 MARK_CLEAN_REGISTER(instr->binaryop.output);
1275 registers[instr->binaryop.output].setbool(result);
1277 QML_V4_END_INSTR(NotEqualString, binaryop)
1279 QML_V4_BEGIN_INSTR(StrictEqualString, binaryop)
1281 const QString &a = *registers[instr->binaryop.left].getstringptr();
1282 const QString &b = *registers[instr->binaryop.right].getstringptr();
1283 bool result = a == b;
1284 if (instr->binaryop.left == instr->binaryop.output) {
1285 registers[instr->binaryop.output].cleanupString();
1286 MARK_CLEAN_REGISTER(instr->binaryop.output);
1288 registers[instr->binaryop.output].setbool(result);
1290 QML_V4_END_INSTR(StrictEqualString, binaryop)
1292 QML_V4_BEGIN_INSTR(StrictNotEqualString, binaryop)
1294 const QString &a = *registers[instr->binaryop.left].getstringptr();
1295 const QString &b = *registers[instr->binaryop.right].getstringptr();
1296 bool result = a != b;
1297 if (instr->binaryop.left == instr->binaryop.output) {
1298 registers[instr->binaryop.output].cleanupString();
1299 MARK_CLEAN_REGISTER(instr->binaryop.output);
1301 registers[instr->binaryop.output].setbool(result);
1303 QML_V4_END_INSTR(StrictNotEqualString, binaryop)
1305 QML_V4_BEGIN_INSTR(NewString, construct)
1307 Register &output = registers[instr->construct.reg];
1308 new (output.getstringptr()) QString;
1309 STRING_REGISTER(instr->construct.reg);
1311 QML_V4_END_INSTR(NewString, construct)
1313 QML_V4_BEGIN_INSTR(NewUrl, construct)
1315 Register &output = registers[instr->construct.reg];
1316 new (output.geturlptr()) QUrl;
1317 URL_REGISTER(instr->construct.reg);
1319 QML_V4_END_INSTR(NewUrl, construct)
1321 QML_V4_BEGIN_INSTR(Fetch, fetch)
1323 Register ® = registers[instr->fetch.reg];
1325 if (reg.isUndefined())
1326 THROW_EXCEPTION(instr->fetch.exceptionId);
1328 QObject *object = reg.getQObject();
1330 THROW_EXCEPTION(instr->fetch.exceptionId);
1332 reg.init((Register::Type)instr->fetch.valueType);
1333 if (instr->fetch.valueType >= FirstCleanupType)
1334 MARK_REGISTER(instr->fetch.reg);
1335 void *argv[] = { reg.typeDataPtr(), 0 };
1336 QMetaObject::metacall(object, QMetaObject::ReadProperty, instr->fetch.index, argv);
1339 QML_V4_END_INSTR(Fetch, fetch)
1341 QML_V4_BEGIN_INSTR(TestV4Store, storetest)
1343 Register &data = registers[instr->storetest.reg];
1344 testBindingResult(*testBindingSource, bindingLine, bindingColumn, context,
1345 scope, data, instr->storetest.regType);
1347 QML_V4_END_INSTR(TestV4Store, storetest)
1349 QML_V4_BEGIN_INSTR(Store, store)
1351 Register &data = registers[instr->store.reg];
1353 if (data.isUndefined())
1354 THROW_EXCEPTION_STR(instr->store.exceptionId, QLatin1String("Unable to assign undefined value"));
1357 void *argv[] = { data.typeDataPtr(), 0, &status, &storeFlags };
1358 QMetaObject::metacall(output, QMetaObject::WriteProperty,
1359 instr->store.index, argv);
1363 QML_V4_END_INSTR(Store, store)
1365 QML_V4_BEGIN_INSTR(Copy, copy)
1366 registers[instr->copy.reg].copy(registers[instr->copy.src]);
1367 if (registers[instr->copy.reg].gettype() >= FirstCleanupType)
1368 MARK_REGISTER(instr->copy.reg);
1369 QML_V4_END_INSTR(Copy, copy)
1371 QML_V4_BEGIN_INSTR(Jump, jump)
1372 if (instr->jump.reg == -1 || !registers[instr->jump.reg].getbool())
1373 code += instr->jump.count;
1374 QML_V4_END_INSTR(Jump, jump)
1376 QML_V4_BEGIN_INSTR(BranchTrue, branchop)
1377 if (registers[instr->branchop.reg].getbool())
1378 code += instr->branchop.offset;
1379 QML_V4_END_INSTR(BranchTrue, branchop)
1381 QML_V4_BEGIN_INSTR(BranchFalse, branchop)
1382 if (! registers[instr->branchop.reg].getbool())
1383 code += instr->branchop.offset;
1384 QML_V4_END_INSTR(BranchFalse, branchop)
1386 QML_V4_BEGIN_INSTR(Branch, branchop)
1387 code += instr->branchop.offset;
1388 QML_V4_END_INSTR(Branch, branchop)
1390 QML_V4_BEGIN_INSTR(Block, blockop)
1391 executedBlocks |= instr->blockop.block;
1392 QML_V4_END_INSTR(Block, blockop)
1394 // XXX not applicable in v8
1395 QML_V4_BEGIN_INSTR(InitString, initstring)
1396 // if (!identifiers[instr->initstring.offset].identifier) {
1397 // quint32 len = *(quint32 *)(data + instr->initstring.dataIdx);
1398 // QChar *strdata = (QChar *)(data + instr->initstring.dataIdx + sizeof(quint32));
1400 // QString str = QString::fromRawData(strdata, len);
1402 // // identifiers[instr->initstring.offset] = engine->objectClass->createPersistentIdentifier(str);
1404 QML_V4_END_INSTR(InitString, initstring)
1406 QML_V4_BEGIN_INSTR(CleanupRegister, cleanup)
1407 registers[instr->cleanup.reg].cleanup();
1408 QML_V4_END_INSTR(CleanupRegister, cleanup)
1410 #ifdef QML_THREADED_INTERPRETER
1414 qFatal("QV4: Unknown instruction %d encountered.", instr->common.type);
1421 Q_ASSERT(!"Unreachable code reached");
1425 delete testBindingSource;
1428 while (cleanupRegisterMask) {
1429 if (cleanupRegisterMask & 0x1)
1430 registers[reg].cleanup();
1433 cleanupRegisterMask >>= 1;