Fix crash in QUrl-to-int conversion in v4
authorChris Adams <christopher.adams@nokia.com>
Thu, 29 Mar 2012 05:15:23 +0000 (15:15 +1000)
committerQt by Nokia <qt-info@nokia.com>
Fri, 30 Mar 2012 05:54:14 +0000 (07:54 +0200)
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 <michael.brasser@nokia.com>
13 files changed:
src/qml/qml/v4/qv4compiler.cpp
src/qml/qml/v4/qv4instruction_p.h
tests/auto/qml/v4/data/conversions.1.qml [new file with mode: 0644]
tests/auto/qml/v4/data/conversions.2.qml [new file with mode: 0644]
tests/auto/qml/v4/data/conversions.3.qml [new file with mode: 0644]
tests/auto/qml/v4/data/conversions.4.qml [new file with mode: 0644]
tests/auto/qml/v4/data/conversions.5.qml [new file with mode: 0644]
tests/auto/qml/v4/data/conversions.6.qml [new file with mode: 0644]
tests/auto/qml/v4/data/conversions.7.qml [new file with mode: 0644]
tests/auto/qml/v4/data/conversions.8.qml [new file with mode: 0644]
tests/auto/qml/v4/testtypes.cpp
tests/auto/qml/v4/testtypes.h
tests/auto/qml/v4/tst_v4.cpp

index 9354209..ba7c2ed 100644 (file)
@@ -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;
             }
index 239cb36..6b09a67 100644 (file)
@@ -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<int Instr>
-class V4InstrData : public V4InstrMeta<Instr>::DataType
+class Q_AUTOTEST_EXPORT V4InstrData : public V4InstrMeta<Instr>::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 (file)
index 0000000..b3abde7
--- /dev/null
@@ -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 (file)
index 0000000..2fd0453
--- /dev/null
@@ -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 (file)
index 0000000..66f0761
--- /dev/null
@@ -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 (file)
index 0000000..ccf0035
--- /dev/null
@@ -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 (file)
index 0000000..26dc3b7
--- /dev/null
@@ -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 (file)
index 0000000..573b227
--- /dev/null
@@ -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 (file)
index 0000000..5112b06
--- /dev/null
@@ -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 (file)
index 0000000..18bf160
--- /dev/null
@@ -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)
+}
index c879cf2..80ccf00 100644 (file)
@@ -46,4 +46,5 @@ void registerTypes()
 {
     qmlRegisterType<ResultObject>("Qt.v4", 1,0, "Result");
     qmlRegisterType<NestedObject>();
+    qmlRegisterType<ConversionObject>("Qt.v4", 1, 0, "Conversion");
 }
index 18b5b27..04dd82e 100644 (file)
@@ -42,6 +42,8 @@
 #define TESTTYPES_H
 
 #include <QtCore/qobject.h>
+#include <QtCore/qurl.h>
+#include <QVector3D>
 
 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
index 47fa10b..ccd7ea7 100644 (file)
@@ -46,6 +46,7 @@
 #include <QtQml/qqmlcomponent.h>
 #include <QtCore/qdebug.h>
 #include <QtGui/qcolor.h>
+#include <QtCore/qnumeric.h>
 
 #include <private/qv4compiler_p.h>
 
@@ -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<QUrl>("file");
+    QTest::addColumn<QStringList>("warnings");
+    QTest::addColumn<bool>("boolProp");
+    QTest::addColumn<int>("intProp");
+    QTest::addColumn<float>("floatProp");
+    QTest::addColumn<double>("doubleProp");
+    QTest::addColumn<qreal>("qrealProp");
+    QTest::addColumn<QString>("qstringProp");
+    QTest::addColumn<QUrl>("qurlProp");
+    QTest::addColumn<QVector3D>("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<bool>(boolProp));
+    QCOMPARE(o->property("intProp"), QVariant::fromValue<int>(intProp));
+    QCOMPARE(o->property("floatProp"), QVariant::fromValue<float>(floatProp));
+    QCOMPARE(o->property("doubleProp"), QVariant::fromValue<double>(doubleProp));
+    QCOMPARE(o->property("qrealProp"), QVariant::fromValue<qreal>(qrealProp));
+    QCOMPARE(o->property("qstringProp"), QVariant::fromValue<QString>(qstringProp));
+    QCOMPARE(o->property("qurlProp"), QVariant::fromValue<QUrl>(qurlProp));
+    QCOMPARE(o->property("vec3Prop"), QVariant::fromValue<QVector3D>(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 <private/qv4instruction_p.h>
+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<QQmlJS::V4Instr::I> 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::Type>(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"