Baseline JIT: Save accumulator in toInt32LhsAcc()

toInt32LhsAcc convertes both the lhs and the accumulator to int32. If
the accumulator is not saved, a GC run during the conversion of the lhs
might trash its value.

Fixes: QTBUG-74058
Change-Id: Ic42693061c7d483bb430d77bcc095de6ff9a6843
Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
This commit is contained in:
Ulf Hermann 2019-03-14 10:42:19 +01:00
parent f4649ebfe5
commit 0dd884aca1
2 changed files with 28 additions and 16 deletions

View File

@ -208,17 +208,20 @@ public:
isNumber.link(this);
}
// this converts both the lhs and the accumulator to int32
void toInt32LhsAcc(Address lhs, RegisterID lhsTarget)
{
load64(lhs, lhsTarget);
urshift64(lhsTarget, TrustedImm32(Value::QuickType_Shift), ScratchRegister2);
auto lhsIsInt = branch32(Equal, TrustedImm32(Value::QT_Int), ScratchRegister2);
pushAligned(AccumulatorRegister);
const Address accumulatorStackAddress(JSStackFrameRegister,
offsetof(CallData, accumulator));
storeAccumulator(accumulatorStackAddress);
move(lhsTarget, registerForArg(0));
callHelper(toInt32Helper);
move(ReturnValueRegister, lhsTarget);
popAligned(AccumulatorRegister);
loadAccumulator(accumulatorStackAddress);
lhsIsInt.link(this);
urshift64(AccumulatorRegister, TrustedImm32(Value::QuickType_Shift), ScratchRegister2);
@ -498,6 +501,7 @@ public:
isNumber.link(this);
}
// this converts both the lhs and the accumulator to int32
void toInt32LhsAcc(Address lhs, RegisterID lhsTarget)
{
bool accumulatorNeedsSaving = AccumulatorRegisterValue == ReturnValueRegisterValue
@ -510,32 +514,28 @@ public:
auto lhsIsInt = jump();
lhsIsNotInt.link(this);
if (accumulatorNeedsSaving) {
push(AccumulatorRegisterTag);
push(AccumulatorRegisterValue);
}
// Save accumulator from being garbage collected, no matter if we will reuse the register.
const Address accumulatorStackAddress(JSStackFrameRegister,
offsetof(CallData, accumulator));
storeAccumulator(accumulatorStackAddress);
if (ArgInRegCount < 2) {
if (!accumulatorNeedsSaving)
subPtr(TrustedImm32(2 * PointerSize), StackPointerRegister);
subPtr(TrustedImm32(2 * PointerSize), StackPointerRegister);
push(lhsTarget);
load32(lhs, lhsTarget);
push(lhsTarget);
} else {
if (accumulatorNeedsSaving)
subPtr(TrustedImm32(2 * PointerSize), StackPointerRegister);
move(lhsTarget, registerForArg(1));
load32(lhs, registerForArg(0));
}
callHelper(toInt32Helper);
move(ReturnValueRegisterValue, lhsTarget);
if (accumulatorNeedsSaving) {
addPtr(TrustedImm32(2 * PointerSize), StackPointerRegister);
pop(AccumulatorRegisterValue);
pop(AccumulatorRegisterTag);
} else if (ArgInRegCount < 2) {
if (ArgInRegCount < 2)
addPtr(TrustedImm32(4 * PointerSize), StackPointerRegister);
}
if (accumulatorNeedsSaving) // otherwise it's still the same
loadAccumulator(accumulatorStackAddress);
lhsIsInt.link(this);

View File

@ -365,6 +365,7 @@ private slots:
void numberToStringWithRadix();
void tailCallWithArguments();
void deleteSparseInIteration();
void saveAccumulatorBeforeToInt32();
private:
// static void propertyVarWeakRefCallback(v8::Persistent<v8::Value> object, void* parameter);
@ -8929,6 +8930,17 @@ void tst_qqmlecmascript::deleteSparseInIteration()
QCOMPARE(value.property("2").toInt(), 4096);
}
void tst_qqmlecmascript::saveAccumulatorBeforeToInt32()
{
QJSEngine engine;
// Infinite recursion produces a range error, but should not crash.
// Also, any GC runs in between should not trash the temporary results of "a+a".
const QJSValue value = engine.evaluate("function a(){a(a&a+a)}a()");
QVERIFY(value.isError());
QCOMPARE(value.toString(), QLatin1String("RangeError: Maximum call stack size exceeded."));
}
QTEST_MAIN(tst_qqmlecmascript)
#include "tst_qqmlecmascript.moc"