From: Chris Adams Date: Thu, 29 Mar 2012 05:15:23 +0000 (+1000) Subject: Fix crash in QUrl-to-int conversion in v4 X-Git-Url: http://git.silmor.de/gitweb/?a=commitdiff_plain;h=bb5afc485d68b2ef779f858d461160c0634c3020;p=konrad%2Fqtdeclarative.git Fix crash in QUrl-to-int conversion in v4 Also adds various unit tests for other conversion operations. Note that many of the conversion operations produce the wrong results, and have been marked with QTBUG-24706. Task-number: QTBUG-24706 Change-Id: Id96a7409e31f2e889dce6b501247f58b59fa6a98 Reviewed-by: Michael Brasser --- diff --git a/src/qml/qml/v4/qv4compiler.cpp b/src/qml/qml/v4/qv4compiler.cpp index 9354209..ba7c2ed 100644 --- a/src/qml/qml/v4/qv4compiler.cpp +++ b/src/qml/qml/v4/qv4compiler.cpp @@ -940,10 +940,9 @@ void QV4CompilerPrivate::visitMove(IR::Move *s) // generate a UrlToString conversion and fix // the type of the source expression. V4Instr conv; - conv.unaryop.output = V4Instr::ConvertUrlToString; + conv.unaryop.output = src; conv.unaryop.src = src; - gen(opcode, conv); - + gen(V4Instr::ConvertUrlToString, conv); sourceTy = IR::StringType; break; } diff --git a/src/qml/qml/v4/qv4instruction_p.h b/src/qml/qml/v4/qv4instruction_p.h index 239cb36..6b09a67 100644 --- a/src/qml/qml/v4/qv4instruction_p.h +++ b/src/qml/qml/v4/qv4instruction_p.h @@ -192,7 +192,7 @@ class QQmlNotifier; namespace QQmlJS { -union V4Instr { +union Q_AUTOTEST_EXPORT V4Instr { enum Type { FOR_EACH_V4_INSTR(QML_V4_INSTR_ENUM) }; @@ -400,11 +400,11 @@ FOR_EACH_V4_INSTR(QML_V4_INSTR_META_TEMPLATE); #undef QML_V4_INSTR_META_TEMPLATE template -class V4InstrData : public V4InstrMeta::DataType +class Q_AUTOTEST_EXPORT V4InstrData : public V4InstrMeta::DataType { }; -class Bytecode +class Q_AUTOTEST_EXPORT Bytecode { Q_DISABLE_COPY(Bytecode) diff --git a/tests/auto/qml/v4/data/conversions.1.qml b/tests/auto/qml/v4/data/conversions.1.qml new file mode 100644 index 0000000..b3abde7 --- /dev/null +++ b/tests/auto/qml/v4/data/conversions.1.qml @@ -0,0 +1,13 @@ +import Qt.v4 1.0 + +Conversion { + // test assigning bool prop to other proptypes. + boolProp: true + intProp: boolProp + floatProp: boolProp + doubleProp: boolProp + qrealProp: boolProp + qstringProp: boolProp + qurlProp: boolProp + vec3Prop: Qt.vector3d(boolProp, boolProp, boolProp) +} diff --git a/tests/auto/qml/v4/data/conversions.2.qml b/tests/auto/qml/v4/data/conversions.2.qml new file mode 100644 index 0000000..2fd0453 --- /dev/null +++ b/tests/auto/qml/v4/data/conversions.2.qml @@ -0,0 +1,13 @@ +import Qt.v4 1.0 + +Conversion { + // test assigning int prop to other proptypes. + boolProp: intProp + intProp: 4 + floatProp: intProp + doubleProp: intProp + qrealProp: intProp + qstringProp: intProp + qurlProp: intProp + vec3Prop: Qt.vector3d(intProp, intProp, intProp) +} diff --git a/tests/auto/qml/v4/data/conversions.3.qml b/tests/auto/qml/v4/data/conversions.3.qml new file mode 100644 index 0000000..66f0761 --- /dev/null +++ b/tests/auto/qml/v4/data/conversions.3.qml @@ -0,0 +1,13 @@ +import Qt.v4 1.0 + +Conversion { + // test assigning float prop to other proptypes. + boolProp: floatProp + intProp: floatProp + floatProp: 4.4 + doubleProp: floatProp + qrealProp: floatProp + qstringProp: floatProp + qurlProp: floatProp + vec3Prop: Qt.vector3d(floatProp, floatProp, floatProp) +} diff --git a/tests/auto/qml/v4/data/conversions.4.qml b/tests/auto/qml/v4/data/conversions.4.qml new file mode 100644 index 0000000..ccf0035 --- /dev/null +++ b/tests/auto/qml/v4/data/conversions.4.qml @@ -0,0 +1,13 @@ +import Qt.v4 1.0 + +Conversion { + // test assigning double prop to other prop types + boolProp: doubleProp + intProp: doubleProp + floatProp: doubleProp + doubleProp: 4.444444444 + qrealProp: doubleProp + qstringProp: doubleProp + qurlProp: doubleProp + vec3Prop: Qt.vector3d(doubleProp, doubleProp, doubleProp) +} diff --git a/tests/auto/qml/v4/data/conversions.5.qml b/tests/auto/qml/v4/data/conversions.5.qml new file mode 100644 index 0000000..26dc3b7 --- /dev/null +++ b/tests/auto/qml/v4/data/conversions.5.qml @@ -0,0 +1,13 @@ +import Qt.v4 1.0 + +Conversion { + // test assigning qreal prop to other prop types + boolProp: qrealProp + intProp: qrealProp + floatProp: qrealProp + doubleProp: qrealProp + qrealProp: 4.44 + qstringProp: qrealProp + qurlProp: qrealProp + vec3Prop: Qt.vector3d(qrealProp, qrealProp, qrealProp) +} diff --git a/tests/auto/qml/v4/data/conversions.6.qml b/tests/auto/qml/v4/data/conversions.6.qml new file mode 100644 index 0000000..573b227 --- /dev/null +++ b/tests/auto/qml/v4/data/conversions.6.qml @@ -0,0 +1,13 @@ +import Qt.v4 1.0 + +Conversion { + // test assigning string prop to other proptypes. + boolProp: qstringProp + intProp: qstringProp + floatProp: qstringProp + doubleProp: qstringProp + qrealProp: qstringProp + qstringProp: "4" + qurlProp: qstringProp + vec3Prop: Qt.vector3d(qstringProp, qstringProp, qstringProp) +} diff --git a/tests/auto/qml/v4/data/conversions.7.qml b/tests/auto/qml/v4/data/conversions.7.qml new file mode 100644 index 0000000..5112b06 --- /dev/null +++ b/tests/auto/qml/v4/data/conversions.7.qml @@ -0,0 +1,13 @@ +import Qt.v4 1.0 + +Conversion { + // test assigning url prop to other proptypes. + boolProp: qurlProp + intProp: qurlProp + floatProp: qurlProp + doubleProp: qurlProp + qrealProp: qurlProp + qstringProp: qurlProp + qurlProp: "4" + vec3Prop: Qt.vector3d(qurlProp, qurlProp, qurlProp) +} diff --git a/tests/auto/qml/v4/data/conversions.8.qml b/tests/auto/qml/v4/data/conversions.8.qml new file mode 100644 index 0000000..18bf160 --- /dev/null +++ b/tests/auto/qml/v4/data/conversions.8.qml @@ -0,0 +1,13 @@ +import Qt.v4 1.0 + +Conversion { + // test assigning vector prop to other proptypes. + boolProp: vec3Prop + intProp: vec3Prop + floatProp: vec3Prop + doubleProp: vec3Prop + qrealProp: vec3Prop + qstringProp: vec3Prop + qurlProp: vec3Prop + vec3Prop: Qt.vector3d(4, 4, 4) +} diff --git a/tests/auto/qml/v4/testtypes.cpp b/tests/auto/qml/v4/testtypes.cpp index c879cf2..80ccf00 100644 --- a/tests/auto/qml/v4/testtypes.cpp +++ b/tests/auto/qml/v4/testtypes.cpp @@ -46,4 +46,5 @@ void registerTypes() { qmlRegisterType("Qt.v4", 1,0, "Result"); qmlRegisterType(); + qmlRegisterType("Qt.v4", 1, 0, "Conversion"); } diff --git a/tests/auto/qml/v4/testtypes.h b/tests/auto/qml/v4/testtypes.h index 18b5b27..04dd82e 100644 --- a/tests/auto/qml/v4/testtypes.h +++ b/tests/auto/qml/v4/testtypes.h @@ -42,6 +42,8 @@ #define TESTTYPES_H #include +#include +#include class NestedObject : public QObject { @@ -80,6 +82,61 @@ private: NestedObject m_nested2; }; +class ConversionObject : public QObject +{ + Q_OBJECT + + Q_PROPERTY(bool boolProp READ boolProp WRITE setBoolProp NOTIFY boolPropChanged) + Q_PROPERTY(int intProp READ intProp WRITE setIntProp NOTIFY intPropChanged) + Q_PROPERTY(float floatProp READ floatProp WRITE setFloatProp NOTIFY floatPropChanged) + Q_PROPERTY(double doubleProp READ doubleProp WRITE setDoubleProp NOTIFY doublePropChanged) + Q_PROPERTY(qreal qrealProp READ qrealProp WRITE setQrealProp NOTIFY qrealPropChanged) + Q_PROPERTY(QString qstringProp READ qstringProp WRITE setQstringProp NOTIFY qstringPropChanged) + Q_PROPERTY(QUrl qurlProp READ qurlProp WRITE setQurlProp NOTIFY qurlPropChanged) + Q_PROPERTY(QVector3D vec3Prop READ vec3Prop WRITE setVec3Prop NOTIFY vec3PropChanged) + +public: + ConversionObject() : m_boolProp(false), m_intProp(0), m_floatProp(0.0), m_doubleProp(0.0), m_qrealProp(0.0) {} + ~ConversionObject() {} + + bool boolProp() const { return m_boolProp; } + void setBoolProp(bool v) { m_boolProp = v; emit boolPropChanged(); } + int intProp() const { return m_intProp; } + void setIntProp(int v) { m_intProp = v; emit intPropChanged(); } + float floatProp() const { return m_floatProp; } + void setFloatProp(float v) { m_floatProp = v; emit floatPropChanged(); } + double doubleProp() const { return m_doubleProp; } + void setDoubleProp(double v) { m_doubleProp = v; emit doublePropChanged(); } + qreal qrealProp() const { return m_qrealProp; } + void setQrealProp(qreal v) { m_qrealProp = v; emit qrealPropChanged(); } + QString qstringProp() const { return m_qstringProp; } + void setQstringProp(const QString& v) { m_qstringProp = v; emit qstringPropChanged(); } + QUrl qurlProp() const { return m_qurlProp; } + void setQurlProp(const QUrl& v) { m_qurlProp = v; emit qurlPropChanged(); } + QVector3D vec3Prop() const { return m_vec3Prop; } + void setVec3Prop(const QVector3D& v) { m_vec3Prop = v; emit vec3PropChanged(); } + +signals: + void boolPropChanged(); + void intPropChanged(); + void floatPropChanged(); + void doublePropChanged(); + void qrealPropChanged(); + void qstringPropChanged(); + void qurlPropChanged(); + void vec3PropChanged(); + +private: + bool m_boolProp; + int m_intProp; + float m_floatProp; + double m_doubleProp; + qreal m_qrealProp; + QString m_qstringProp; + QUrl m_qurlProp; + QVector3D m_vec3Prop; +}; + void registerTypes(); #endif // TESTTYPES_H diff --git a/tests/auto/qml/v4/tst_v4.cpp b/tests/auto/qml/v4/tst_v4.cpp index 47fa10b..ccd7ea7 100644 --- a/tests/auto/qml/v4/tst_v4.cpp +++ b/tests/auto/qml/v4/tst_v4.cpp @@ -46,6 +46,7 @@ #include #include #include +#include #include @@ -83,6 +84,11 @@ private slots: void mathMin(); void moduleApi(); + void conversions_data(); + void conversions(); + + void debuggingDumpInstructions(); // this test should be last. + private: QQmlEngine engine; }; @@ -135,6 +141,14 @@ void tst_v4::qtscript_data() QTest::newRow("unary minus") << "unaryMinus.qml"; QTest::newRow("null qobject") << "nullQObject.qml"; QTest::newRow("qobject -> bool") << "objectToBool.qml"; + //QTest::newRow("conversion from bool") << "conversions.1.qml"; // QTBUG-24706 + //QTest::newRow("conversion from int") << "conversions.2.qml"; // QTBUG-24706 + QTest::newRow("conversion from float") << "conversions.3.qml"; + //QTest::newRow("conversion from double") << "conversions.4.qml"; // QTBUG-24706 + //QTest::newRow("conversion from real") << "conversions.5.qml"; // QTBUG-24706 + //QTest::newRow("conversion from string") << "conversions.6.qml"; // QTBUG-24706 + //QTest::newRow("conversion from url") << "conversions.7.qml"; // QTBUG-24706 + QTest::newRow("conversion from vec3") << "conversions.8.qml"; } void tst_v4::unnecessaryReeval() @@ -630,6 +644,306 @@ void tst_v4::moduleApi() delete o; } +void tst_v4::conversions_data() +{ + QTest::addColumn("file"); + QTest::addColumn("warnings"); + QTest::addColumn("boolProp"); + QTest::addColumn("intProp"); + QTest::addColumn("floatProp"); + QTest::addColumn("doubleProp"); + QTest::addColumn("qrealProp"); + QTest::addColumn("qstringProp"); + QTest::addColumn("qurlProp"); + QTest::addColumn("vec3Prop"); + + QTest::newRow("from bool") << testFileUrl("conversions.1.qml") + << (QStringList()) + << true + << (int)true + << (float)1.0 + << (double)1.0 + << (qreal)1.0 + << QString(QLatin1String("true")) + << QUrl(testFileUrl("").toString() + QString(QLatin1String("true"))) + << QVector3D(1, 1, 1); + + QTest::newRow("from integer") << testFileUrl("conversions.2.qml") + << (QStringList()) + << (bool)4 + << 4 + << (float)4.0 + << (double)4.0 + << (qreal)4.0 + << QString(QLatin1String("4")) + << QUrl(testFileUrl("").toString() + QString(QLatin1String("4"))) + << QVector3D(4, 4, 4); + + QTest::newRow("from float") << testFileUrl("conversions.3.qml") + << (QStringList() << (testFileUrl("conversions.3.qml").toString() + QLatin1String(":11: Unable to assign double to QUrl"))) + << (bool)4.4 + << (int)4.4 + << (float)4.4 + << (double)((float)4.4) + << (qreal)((float)4.4) + << QString::number((double)((float)4.4), 'g', 15) + << QUrl() // cannot assign double to url. + << QVector3D(4.4, 4.4, 4.4); + + QTest::newRow("from double") << testFileUrl("conversions.4.qml") + << (QStringList()) + << (bool)4.444444444 + << (int)4.444444444 + << (float)4.444444444 + << (double)4.444444444 + << (qreal)4.444444444 + << QString::number((double)4.444444444) + << QUrl(testFileUrl("").toString() + QString::number((double)4.444444444)) + << QVector3D(4.444444444, 4.444444444, 4.444444444); + + QTest::newRow("from qreal") << testFileUrl("conversions.5.qml") + << (QStringList()) + << (bool)4.44 + << (int)4.44 + << (float)4.44 + << (double)4.44 + << (qreal)4.44 + << QString(QLatin1String("4.44")) + << QUrl(testFileUrl("").toString() + QString(QLatin1String("4.44"))) + << QVector3D(4.44, 4.44, 4.44); + + QTest::newRow("from string") << testFileUrl("conversions.6.qml") + << (QStringList()) + << true + << 4 + << (float)4.0 + << (double)4.0 + << (qreal)4.0 + << QString(QLatin1String("4")) + << QUrl(testFileUrl("").toString() + QString(QLatin1String("4"))) + << QVector3D(4, 4, 4); + + /* + //XXX TODO: QTBUG-24706 + QTest::newRow("from url") << testFileUrl("conversions.7.qml") + << (QStringList() << (testFileUrl("conversions.7.qml").toString() + QLatin1String(":7: Unable to assign QUrl to float"))) + << true + << 0 // a url like "4" actually gets the value "file:///path/to/test/4" + << (float)0 // and the url.toString().toInt()/toDouble() of that is zero/qQNaN(). + << (double)0 + << (qreal)0 + << QString(testFileUrl("").toString() + QString(QLatin1String("4"))) + << QUrl(testFileUrl("").toString() + QString(QLatin1String("4"))) + << QVector3D(0, 0, 0); + */ + + QTest::newRow("from vector") << testFileUrl("conversions.8.qml") + << (QStringList() << (testFileUrl("conversions.8.qml").toString() + QLatin1String(":11: Unable to assign QVector3D to QUrl")) + << (testFileUrl("conversions.8.qml").toString() + QLatin1String(":10: Unable to assign QVector3D to QString")) + << (testFileUrl("conversions.8.qml").toString() + QLatin1String(":9: Unable to assign QVector3D to double")) + << (testFileUrl("conversions.8.qml").toString() + QLatin1String(":8: Unable to assign QVector3D to double")) + << (testFileUrl("conversions.8.qml").toString() + QLatin1String(":7: Unable to assign QVector3D to float")) + << (testFileUrl("conversions.8.qml").toString() + QLatin1String(":6: Unable to assign QVector3D to int"))) + << true // non-null therefore true + << (int)0 // the other values should be the default-ctor values. + << (float)0 + << (double)0 + << (qreal)0 + << QString() + << QUrl() + << QVector3D(4, 4, 4); // except this one. +} + +void tst_v4::conversions() +{ + QFETCH(QUrl, file); + QFETCH(QStringList, warnings); + QFETCH(bool, boolProp); + QFETCH(int, intProp); + QFETCH(float, floatProp); + QFETCH(double, doubleProp); + QFETCH(qreal, qrealProp); + QFETCH(QString, qstringProp); + QFETCH(QUrl, qurlProp); + QFETCH(QVector3D, vec3Prop); + + foreach (const QString &w, warnings) + QTest::ignoreMessage(QtWarningMsg, qPrintable(w)); + + QQmlComponent component(&engine, file); + QObject *o = component.create(); + QVERIFY(o != 0); + QCOMPARE(o->property("boolProp"), QVariant::fromValue(boolProp)); + QCOMPARE(o->property("intProp"), QVariant::fromValue(intProp)); + QCOMPARE(o->property("floatProp"), QVariant::fromValue(floatProp)); + QCOMPARE(o->property("doubleProp"), QVariant::fromValue(doubleProp)); + QCOMPARE(o->property("qrealProp"), QVariant::fromValue(qrealProp)); + QCOMPARE(o->property("qstringProp"), QVariant::fromValue(qstringProp)); + QCOMPARE(o->property("qurlProp"), QVariant::fromValue(qurlProp)); + QCOMPARE(o->property("vec3Prop"), QVariant::fromValue(vec3Prop)); + delete o; +} + + +static QStringList messages; +static void msgHandler(QtMsgType, const char *msg) +{ + messages << QLatin1String(msg); +} + +static QByteArray getAddress(int address) +{ + return QByteArray::number(address); +} + +static QByteArray getLeading(int address) +{ + QByteArray leading; + if (address != -1) { + leading = getAddress(address); + leading.prepend(QByteArray(8 - leading.count(), ' ')); + } + return leading; +} + +#include +void tst_v4::debuggingDumpInstructions() +{ + QStringList expectedPreAddress; + expectedPreAddress << "\t\tNoop"; + expectedPreAddress << "\t0:0:"; + expectedPreAddress << "\t\tSubscribe\t\tObject_Reg(0) Notify_Signal(0) -> Subscribe_Slot(0)"; + expectedPreAddress << "\t\tSubscribeId\t\tId_Offset(0) -> Subscribe_Slot(0)"; + expectedPreAddress << "\t\tFetchAndSubscribe\tObject_Reg(0) Fast_Accessor(0x0) -> Output_Reg(0) Subscription_Slot(0)"; + expectedPreAddress << "\t\tLoadId\t\t\tId_Offset(0) -> Output_Reg(0)"; + expectedPreAddress << "\t\tLoadScope\t\t-> Output_Reg(0)"; + expectedPreAddress << "\t\tLoadRoot\t\t-> Output_Reg(0)"; + expectedPreAddress << "\t\tLoadModuleObject\t\t) -> Output_Reg(0)"; + expectedPreAddress << "\t\tLoadAttached\t\tObject_Reg(0) Attached_Index(0) -> Output_Reg(0)"; + expectedPreAddress << "\t\tUnaryNot\t\tInput_Reg(0) -> Output_Reg(0)"; + expectedPreAddress << "\t\tUnaryMinusReal\t\tInput_Reg(0) -> Output_Reg(0)"; + expectedPreAddress << "\t\tUnaryMinusInt\t\tInput_Reg(0) -> Output_Reg(0)"; + expectedPreAddress << "\t\tUnaryPlusReal\t\tInput_Reg(0) -> Output_Reg(0)"; + expectedPreAddress << "\t\tUnaryPlusInt\t\tInput_Reg(0) -> Output_Reg(0)"; + expectedPreAddress << "\t\tConvertBoolToInt\tInput_Reg(0) -> Output_Reg(0)"; + expectedPreAddress << "\t\tConvertBoolToReal\tInput_Reg(0) -> Output_Reg(0)"; + expectedPreAddress << "\t\tConvertBoolToString\tInput_Reg(0) -> Output_Reg(0)"; + expectedPreAddress << "\t\tConvertIntToBool\tInput_Reg(0) -> Output_Reg(0)"; + expectedPreAddress << "\t\tConvertIntToReal\tInput_Reg(0) -> Output_Reg(0)"; + expectedPreAddress << "\t\tConvertIntToString\tInput_Reg(0) -> Output_Reg(0)"; + expectedPreAddress << "\t\tConvertRealToBool\tInput_Reg(0) -> Output_Reg(0)"; + expectedPreAddress << "\t\tConvertRealToInt\tInput_Reg(0) -> Output_Reg(0)"; + expectedPreAddress << "\t\tConvertRealToString\tInput_Reg(0) -> Output_Reg(0)"; + expectedPreAddress << "\t\tConvertStringToBool\tInput_Reg(0) -> Output_Reg(0)"; + expectedPreAddress << "\t\tConvertStringToInt\tInput_Reg(0) -> Output_Reg(0)"; + expectedPreAddress << "\t\tConvertStringToReal\tInput_Reg(0) -> Output_Reg(0)"; + expectedPreAddress << "\t\tConvertStringToUrl\tInput_Reg(0) -> Output_Reg(0)"; + expectedPreAddress << "\t\tConvertStringToColor\tInput_Reg(0) -> Output_Reg(0)"; + expectedPreAddress << "\t\tConvertUrlToBool\tInput_Reg(0) -> Output_Reg(0)"; + expectedPreAddress << "\t\tConvertUrlToString\tInput_Reg(0) -> Output_Reg(0)"; + expectedPreAddress << "\t\tConvertColorToBool\tInput_Reg(0) -> Output_Reg(0)"; + expectedPreAddress << "\t\tConvertColorToString\tInput_Reg(0) -> Output_Reg(0)"; + expectedPreAddress << "\t\tConvertObjectToBool\tInput_Reg(0) -> Output_Reg(0)"; + expectedPreAddress << "\t\tConvertNullToObject\tInput_Reg(0) -> Output_Reg(0)"; + expectedPreAddress << "\t\tResolveUrl\t\tInput_Reg(0) -> Output_Reg(0)"; + expectedPreAddress << "\t\tMathSinReal\t\tInput_Reg(0) -> Output_Reg(0)"; + expectedPreAddress << "\t\tMathCosReal\t\tInput_Reg(0) -> Output_Reg(0)"; + expectedPreAddress << "\t\tMathAbsReal\t\tInput_Reg(0) -> Output_Reg(0)"; + expectedPreAddress << "\t\tMathRoundReal\t\tInput_Reg(0) -> Output_Reg(0)"; + expectedPreAddress << "\t\tMathFloorReal\t\tInput_Reg(0) -> Output_Reg(0)"; + expectedPreAddress << "\t\tMathCeilReal\t\tInput_Reg(0) -> Output_Reg(0)"; + expectedPreAddress << "\t\tMathPIReal\t\tInput_Reg(0) -> Output_Reg(0)"; + expectedPreAddress << "\t\tLoadNull\t\tConstant(null) -> Output_Reg(0)"; + expectedPreAddress << "\t\tLoadReal\t\tConstant(0) -> Output_Reg(0)"; + expectedPreAddress << "\t\tLoadInt\t\t\tConstant(0) -> Output_Reg(0)"; + expectedPreAddress << "\t\tLoadBool\t\tConstant(false) -> Output_Reg(0)"; + expectedPreAddress << "\t\tLoadString\t\tString_DataIndex(0) String_Length(0) -> Output_Register(0)"; + expectedPreAddress << "\t\tEnableV4Test\t\tString_DataIndex(0) String_Length(0)"; + expectedPreAddress << "\t\tTestV4Store\t\tInput_Reg(0) Reg_Type(0)"; + expectedPreAddress << "\t\tBitAndInt\t\tInput_Reg(0) Input_Reg(0) -> Output_Reg(0)"; + expectedPreAddress << "\t\tBitOrInt\t\tInput_Reg(0) Input_Reg(0) -> Output_Reg(0)"; + expectedPreAddress << "\t\tBitXorInt\t\tInput_Reg(0) Input_Reg(0) -> Output_Reg(0)"; + expectedPreAddress << "\t\tAddReal\t\t\tInput_Reg(0) Input_Reg(0) -> Output_Reg(0)"; + expectedPreAddress << "\t\tAddString\t\tInput_Reg(0) Input_Reg(0) -> Output_Reg(0)"; + expectedPreAddress << "\t\tSubReal\t\t\tInput_Reg(0) Input_Reg(0) -> Output_Reg(0)"; + expectedPreAddress << "\t\tMulReal\t\t\tInput_Reg(0) Input_Reg(0) -> Output_Reg(0)"; + expectedPreAddress << "\t\tDivReal\t\t\tInput_Reg(0) Input_Reg(0) -> Output_Reg(0)"; + expectedPreAddress << "\t\tModReal\t\t\tInput_Reg(0) Input_Reg(0) -> Output_Reg(0)"; + expectedPreAddress << "\t\tLShiftInt\t\tInput_Reg(0) Input_Reg(0) -> Output_Reg(0)"; + expectedPreAddress << "\t\tRShiftInt\t\tInput_Reg(0) Input_Reg(0) -> Output_Reg(0)"; + expectedPreAddress << "\t\tURShiftInt\t\tInput_Reg(0) Input_Reg(0) -> Output_Reg(0)"; + expectedPreAddress << "\t\tGtReal\t\t\tInput_Reg(0) Input_Reg(0) -> Output_Reg(0)"; + expectedPreAddress << "\t\tLtReal\t\t\tInput_Reg(0) Input_Reg(0) -> Output_Reg(0)"; + expectedPreAddress << "\t\tGeReal\t\t\tInput_Reg(0) Input_Reg(0) -> Output_Reg(0)"; + expectedPreAddress << "\t\tLeReal\t\t\tInput_Reg(0) Input_Reg(0) -> Output_Reg(0)"; + expectedPreAddress << "\t\tEqualReal\t\tInput_Reg(0) Input_Reg(0) -> Output_Reg(0)"; + expectedPreAddress << "\t\tNotEqualReal\t\tInput_Reg(0) Input_Reg(0) -> Output_Reg(0)"; + expectedPreAddress << "\t\tStrictEqualReal\t\tInput_Reg(0) Input_Reg(0) -> Output_Reg(0)"; + expectedPreAddress << "\t\tStrictNotEqualReal\tInput_Reg(0) Input_Reg(0) -> Output_Reg(0)"; + expectedPreAddress << "\t\tGtString\t\tInput_Reg(0) Input_Reg(0) -> Output_Reg(0)"; + expectedPreAddress << "\t\tLtString\t\tInput_Reg(0) Input_Reg(0) -> Output_Reg(0)"; + expectedPreAddress << "\t\tGeString\t\tInput_Reg(0) Input_Reg(0) -> Output_Reg(0)"; + expectedPreAddress << "\t\tLeString\t\tInput_Reg(0) Input_Reg(0) -> Output_Reg(0)"; + expectedPreAddress << "\t\tEqualString\t\tInput_Reg(0) Input_Reg(0) -> Output_Reg(0)"; + expectedPreAddress << "\t\tNotEqualString\t\tInput_Reg(0) Input_Reg(0) -> Output_Reg(0)"; + expectedPreAddress << "\t\tStrictEqualString\tInput_Reg(0) Input_Reg(0) -> Output_Reg(0)"; + expectedPreAddress << "\t\tStrictNotEqualString\tInput_Reg(0) Input_Reg(0) -> Output_Reg(0)"; + expectedPreAddress << "\t\tEqualObject\t\tInput_Reg(0) Input_Reg(0) -> Output_Reg(0)"; + expectedPreAddress << "\t\tNotEqualObject\t\tInput_Reg(0) Input_Reg(0) -> Output_Reg(0)"; + expectedPreAddress << "\t\tStrictEqualObject\tInput_Reg(0) Input_Reg(0) -> Output_Reg(0)"; + expectedPreAddress << "\t\tStrictNotEqualObject\tInput_Reg(0) Input_Reg(0) -> Output_Reg(0)"; + expectedPreAddress << "\t\tMathMaxReal\tInput_Reg(0) Input_Reg(0) -> Output_Reg(0)"; + expectedPreAddress << "\t\tMathMinReal\tInput_Reg(0) Input_Reg(0) -> Output_Reg(0)"; + expectedPreAddress << "\t\tNewString\t\tRegister(0)"; + expectedPreAddress << "\t\tNewUrl\t\t\tRegister(0)"; + expectedPreAddress << "\t\tCleanupRegister\t\tRegister(0)"; + expectedPreAddress << "\t\tCopy\t\t\tInput_Reg(0) -> Output_Reg(0)"; + expectedPreAddress << "\t\tFetch\t\t\tObject_Reg(0) Property_Index(0) -> Output_Reg(0)"; + expectedPreAddress << "\t\tStore\t\t\tInput_Reg(0) -> Object_Reg(0) Property_Index(0)"; + expectedPreAddress << "\t\tJump\t\t\tAddress(UNIT_TEST_JUMP_ADDRESS) [if false == Input_Reg(0)]"; //(address + size() + i->jump.count) + expectedPreAddress << "\t\tBranchTrue\t\tAddress(UNIT_TEST_BRANCH_ADDRESS) [if true == Input_Reg(0)]"; //(address + size() + i->branchop.offset) + expectedPreAddress << "\t\tBranchFalse\t\tAddress(UNIT_TEST_BRANCH_ADDRESS) [if false == Input_Reg(0)]"; //(address + size() + i->branchop.offset) + expectedPreAddress << "\t\tBranch\t\t\tAddress(UNIT_TEST_BRANCH_ADDRESS)"; //(address + size() + i->branchop.offset) + expectedPreAddress << "\t\tBlock\t\t\tMask(0)"; + expectedPreAddress << "\t\tInitString\t\tString_DataIndex(0) -> String_Slot(0)"; + QStringList expected; + + messages = QStringList(); + QtMsgHandler old = qInstallMsgHandler(msgHandler); + + QQmlJS::Bytecode bc; +#define DUMP_INSTR_IN_UNIT_TEST(I, FMT) { QQmlJS::V4InstrData i; memset(&i, 0, sizeof(i)); bc.append(i); } + FOR_EACH_V4_INSTR(DUMP_INSTR_IN_UNIT_TEST); +#undef DUMP_INSTR_IN_UNIT_TEST // NOTE: we memset in order to ensure stable output. + const char *start = bc.constData(); + const char *end = start + bc.size(); + const char *codeAddr = start; + int whichExpected = 0; +#define DUMP_INSTR_SIZE_IN_UNIT_TEST(I, FMT) { \ + QString currExpected = expectedPreAddress.at(whichExpected++); \ + currExpected.prepend(getLeading(codeAddr - start)); \ + expected.append(currExpected); \ + codeAddr += QQmlJS::V4Instr::size(static_cast(QQmlJS::V4Instr::I)); \ + } + FOR_EACH_V4_INSTR(DUMP_INSTR_SIZE_IN_UNIT_TEST); +#undef DUMP_INSTR_SIZE_IN_UNIT_TEST // so that we generate the correct address for each instruction comparison + bc.dump(start, end); + + // ensure that the output was expected. + qInstallMsgHandler(old); + QCOMPARE(messages.count(), expected.count()); + for (int ii = 0; ii < messages.count(); ++ii) { + // Calculating the destination address of a null jump/branch instruction is tricky + // so instead we simply don't compare that part of those instructions. + QRegExp ignoreAddress("\\bAddress\\((\\w*)\\)"); + ignoreAddress.setMinimal(true); + QString expectOut = expected.at(ii); expectOut.replace(ignoreAddress, ""); + QString actualOut = messages.at(ii); actualOut.replace(ignoreAddress, ""); + QCOMPARE(actualOut, expectOut); + } +} + + QTEST_MAIN(tst_v4) #include "tst_v4.moc"