From dc0136b8ba25c60f24fece5959d5487cea18b250 Mon Sep 17 00:00:00 2001 From: Erik Verbruggen Date: Fri, 9 Mar 2018 13:04:53 +0100 Subject: Fix JITted code for jump strict-not-equal undefined on 32bit The generated code for jump-on-strict-not-equal-undefined used the same logic (but with inverted conditions) as the equal case. For equality, one can jump to else if the value parts are not the same. So, for not-equal, if the value parts are the same, it would jump to the else block if they are the same. Meaning, an encoded int value of 0 (which is strict-not-equal to undefined) would end up being evaluated as equal. Task-number: QTBUG-66832 Change-Id: I5c6b8e9b11be53ae21a7164e0a1e0cbfd204f401 Reviewed-by: Simon Hausmann (cherry picked from commit 86702c3be53fda404ebe331207f9062675c952e0) --- src/qml/jit/qv4assembler_p.h | 37 ++++++++++++++++------ .../auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp | 21 ++++++++++++ 2 files changed, 48 insertions(+), 10 deletions(-) diff --git a/src/qml/jit/qv4assembler_p.h b/src/qml/jit/qv4assembler_p.h index 8b5b307e84..87f73ccd6f 100644 --- a/src/qml/jit/qv4assembler_p.h +++ b/src/qml/jit/qv4assembler_p.h @@ -294,21 +294,38 @@ struct RegisterSizeDependentAssemblerloadAddress(scratchRegister, right); - as->load32(tagAddr, tagRegister); - Jump j = as->branch32(JITAssembler::invert(cond), tagRegister, TrustedImm32(0)); - as->addPatch(falseBlock, j); - - tagAddr.offset += 4; - as->load32(tagAddr, tagRegister); - const TrustedImm32 tag(QV4::Value::Managed_Type_Internal); Q_ASSERT(nextBlock == as->nextBlock()); Q_UNUSED(nextBlock); - as->generateCJumpOnCompare(cond, tagRegister, tag, currentBlock, trueBlock, falseBlock); + + const typename JITAssembler::TrustedImm32 undefinedTag(QV4::Value::Managed_Type_Internal); + const typename JITAssembler::TrustedImm32 undefinedValue(0); + + typename JITAssembler::Pointer varAddr = as->loadAddress(scratchRegister, right); + typename JITAssembler::Pointer tagAddr = varAddr; + tagAddr.offset += 4; + const typename JITAssembler::RegisterID tagReg = varReg; + + if (cond == JITAssembler::Equal) { + as->load32(tagAddr, tagReg); + // if the tags are not the same, we can fail already: + Jump j = as->branch32(JITAssembler::NotEqual, tagReg, undefinedTag); + as->addPatch(falseBlock, j); + as->load32(varAddr, varReg); + // ok, tags are the same, so if the values are the same then we're done + as->generateCJumpOnCompare(JITAssembler::Equal, varReg, undefinedValue, currentBlock, trueBlock, falseBlock); + } else { // strict not equal: + as->load32(varAddr, varReg); + // if the values are not the same, we're done + Jump j = as->branch32(JITAssembler::NotEqual, varReg, undefinedValue); + as->addPatch(trueBlock, j); + as->load32(tagAddr, tagReg); + // ok, so the values are the same, now check the tags + as->generateCJumpOnCompare(JITAssembler::NotEqual, tagReg, undefinedTag, currentBlock, trueBlock, falseBlock); + } } static void convertVarToSInt32(JITAssembler *as, IR::Expr *source, IR::Expr *target) diff --git a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp index 6318b12f9f..172fb8f91c 100644 --- a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp +++ b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp @@ -340,6 +340,7 @@ private slots: void qtbug_60547(); void anotherNaN(); void callPropertyOnUndefined(); + void jumpStrictNotEqualUndefined(); private: // static void propertyVarWeakRefCallback(v8::Persistent object, void* parameter); @@ -8294,6 +8295,26 @@ void tst_qqmlecmascript::callPropertyOnUndefined() QVERIFY(!v.isError()); // well, more importantly: this shouldn't fail on an assert. } +void tst_qqmlecmascript::jumpStrictNotEqualUndefined() +{ + QJSEngine engine; + QJSValue v = engine.evaluate(QString::fromLatin1( + "var ok = 0\n" + "var foo = 0\n" + "if (foo !== void 1)\n" + " ++ok;\n" + "else\n" + " --ok;\n" + "if (foo === void 1)\n" + " --ok;\n" + "else\n" + " ++ok;\n" + "ok\n" + )); + QVERIFY(!v.isError()); + QCOMPARE(v.toInt(), 2); +} + QTEST_MAIN(tst_qqmlecmascript) #include "tst_qqmlecmascript.moc" -- cgit v1.2.3