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: Id27bb44eccbf39608ae8cebab634c8bcd4c8adfc
Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
This commit is contained in:
Erik Verbruggen 2018-03-09 10:56:21 +01:00
parent 10647ce9da
commit e2218f8b5c
2 changed files with 50 additions and 12 deletions

View File

@ -1869,24 +1869,41 @@ bool InstructionSelection::visitCJumpStrictUndefined(IR::Binop *binop,
return true;
}
const Assembler::RegisterID varReg = Assembler::ReturnValueRegister;
#ifdef QV4_USE_64_BIT_VALUE_ENCODING
Assembler::RelationalCondition cond = binop->op == IR::OpStrictEqual ? Assembler::Equal
: Assembler::NotEqual;
const Assembler::RegisterID tagReg = Assembler::ReturnValueRegister;
#ifdef QV4_USE_64_BIT_VALUE_ENCODING
Assembler::Pointer addr = _as->loadAddress(Assembler::ScratchRegister, varSrc);
_as->load64(addr, tagReg);
const Assembler::TrustedImm64 tag(0);
Assembler::Pointer varAddr = _as->loadAddress(Assembler::ScratchRegister, varSrc);
_as->load64(varAddr, varReg);
const Assembler::TrustedImm64 undefined(0);
_as->generateCJumpOnCompare(cond, varReg, undefined, _block, trueBlock, falseBlock);
#else // !QV4_USE_64_BIT_VALUE_ENCODING
Assembler::Pointer tagAddr = _as->loadAddress(Assembler::ScratchRegister, varSrc);
_as->load32(tagAddr, tagReg);
Assembler::Jump j = _as->branch32(Assembler::invert(cond), tagReg, Assembler::TrustedImm32(0));
_as->addPatch(falseBlock, j);
const Assembler::TrustedImm32 undefinedTag(QV4::Value::Managed_Type_Internal);
const Assembler::TrustedImm32 undefinedValue(0);
Assembler::Pointer varAddr = _as->loadAddress(Assembler::ScratchRegister, varSrc);
Assembler::Pointer tagAddr = varAddr;
tagAddr.offset += 4;
const Assembler::RegisterID tagReg = varReg;
if (binop->op == IR::OpStrictEqual) {
_as->load32(tagAddr, tagReg);
const Assembler::TrustedImm32 tag(QV4::Value::Managed_Type_Internal);
// if the tags are not the same, we can fail already:
Assembler::Jump j = _as->branch32(Assembler::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(Assembler::Equal, varReg, undefinedValue, _block, trueBlock, falseBlock);
} else { // strict not equal:
_as->load32(varAddr, varReg);
// if the values are not the same, we're done
Assembler::Jump j = _as->branch32(Assembler::NotEqual, varReg, undefinedValue);
_as->addPatch(trueBlock, j);
_as->load32(tagAddr, tagReg);
// ok, so the values are the same, now check the tags
_as->generateCJumpOnCompare(Assembler::NotEqual, tagReg, undefinedTag, _block, trueBlock, falseBlock);
}
#endif
_as->generateCJumpOnCompare(cond, tagReg, tag, _block, trueBlock, falseBlock);
return true;
}

View File

@ -334,6 +334,7 @@ private slots:
void qtbug_54589();
void qtbug_54687();
void stringify_qtbug_50592();
void jumpStrictNotEqualUndefined();
private:
// static void propertyVarWeakRefCallback(v8::Persistent<v8::Value> object, void* parameter);
@ -8061,6 +8062,26 @@ void tst_qqmlecmascript::stringify_qtbug_50592()
QCOMPARE(obj->property("source").toString(), QString::fromLatin1("http://example.org/some_nonexistant_image.png"));
}
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"