Bug 1487022 - Fix repeated bailouts when constant-folding a never-ran 1/0. r=tcampbell

Depends on D8446

Differential Revision: https://phabricator.services.mozilla.com/D6067

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Ashley Hauck 2018-10-31 17:31:03 +00:00
Родитель cc606364e6
Коммит 0262b6528c
4 изменённых файлов: 34 добавлений и 17 удалений

Просмотреть файл

@ -2929,12 +2929,14 @@ class ICUnaryArith_Fallback : public ICFallbackStub
extra_ = 0;
}
static const uint16_t SAW_DOUBLE_RESULT_BIT = 0x1;
public:
bool sawDoubleResult() {
return extra_;
bool sawDoubleResult() const {
return extra_ & SAW_DOUBLE_RESULT_BIT;
}
void setSawDoubleResult() {
extra_ = 1;
extra_ |= SAW_DOUBLE_RESULT_BIT;
}
// Compiler for this stub kind.

Просмотреть файл

@ -760,18 +760,26 @@ BaselineInspector::hasSeenNonStringIterMore(jsbytecode* pc)
return stub->toIteratorMore_Fallback()->hasNonStringResult();
}
// defaultIfEmpty: if we've not seen *anything* (neither double nor non-double),
// return this value. This can happen with, for example, a never-taken branch
// inside a hot loop.
bool
BaselineInspector::hasSeenDoubleResult(jsbytecode* pc)
BaselineInspector::hasSeenDoubleResult(jsbytecode* pc, bool defaultIfEmpty)
{
if (!hasBaselineScript()) {
return false;
}
const ICEntry& entry = icEntryFromPC(pc);
ICStub* stub = entry.fallbackStub();
ICFallbackStub* stub = entry.fallbackStub();
MOZ_ASSERT(stub->isUnaryArith_Fallback() || stub->isBinaryArith_Fallback());
// If no attached stubs, and no failures, then this IC has never been executed.
if (stub->state().numOptimizedStubs() == 0 && !entry.fallbackStub()->state().hasFailures()) {
return defaultIfEmpty;
}
if (stub->isUnaryArith_Fallback()) {
return stub->toUnaryArith_Fallback()->sawDoubleResult();
}

Просмотреть файл

@ -124,7 +124,7 @@ class BaselineInspector
bool hasSeenNegativeIndexGetElement(jsbytecode* pc);
bool hasSeenAccessedGetter(jsbytecode* pc);
bool hasSeenDoubleResult(jsbytecode* pc);
bool hasSeenDoubleResult(jsbytecode* pc, bool defaultIfEmpty);
bool hasSeenNonStringIterMore(jsbytecode* pc);
MOZ_MUST_USE bool isOptimizableConstStringSplit(jsbytecode* pc, JSString** strOut,

Просмотреть файл

@ -98,7 +98,7 @@ MDefinition::PrintOpcodeName(GenericPrinter& out, Opcode op)
#endif
static MConstant*
EvaluateConstantOperands(TempAllocator& alloc, MBinaryInstruction* ins, bool* ptypeChange = nullptr)
EvaluateConstantOperands(TempAllocator& alloc, MBinaryInstruction* ins)
{
MDefinition* left = ins->getOperand(0);
MDefinition* right = ins->getOperand(1);
@ -189,9 +189,6 @@ EvaluateConstantOperands(TempAllocator& alloc, MBinaryInstruction* ins, bool* pt
// denominator), decline folding.
MOZ_ASSERT(ins->type() == MIRType::Int32);
if (!retVal.isInt32()) {
if (ptypeChange) {
*ptypeChange = true;
}
return nullptr;
}
@ -2722,7 +2719,9 @@ MUrsh::infer(BaselineInspector* inspector, jsbytecode* pc)
return;
}
if (inspector->hasSeenDoubleResult(pc)) {
// defaultIfEmpty: if we haven't seen anything, assume no double has been seen:
// unsigned right shift only produces a double if the result overflows a signed int32, which is rare.
if (inspector->hasSeenDoubleResult(pc, /* defaultIfEmpty: */ false)) {
specialization_ = MIRType::Double;
setResultType(MIRType::Double);
return;
@ -2940,10 +2939,19 @@ MBinaryArithInstruction::setNumberSpecialization(TempAllocator& alloc, BaselineI
// Try to specialize as int32.
if (getOperand(0)->type() == MIRType::Int32 && getOperand(1)->type() == MIRType::Int32) {
bool seenDouble = inspector->hasSeenDoubleResult(pc);
// The defaultIfEmpty logic here is a little complex, so here's some pseudocode:
// If both arguments are integers, and this code/IC has never been ran:
// If opcode is Div:
// Assume the result is a double. (i.e. int/int division usually produces a double)
// Else (if opcode is not Div):
// Assume the result is an int. (i.e. int (op) int usually produces an int)
// Note, however, if we assume an int incorrectly (e.g. an int+int addition that
// overflows), we might bailout repeatedly. The "repeated bailout, let's not ion
// compile this" logic should catch this scenario.
bool defaultIfEmpty = op() == Opcode::Div;
bool seenDouble = inspector->hasSeenDoubleResult(pc, defaultIfEmpty);
// Use int32 specialization if the operation doesn't overflow on its
// constant operands and if the operation has never overflowed.
if (!seenDouble && !constantDoubleResult(alloc)) {
setInt32Specialization();
}
@ -2953,9 +2961,8 @@ MBinaryArithInstruction::setNumberSpecialization(TempAllocator& alloc, BaselineI
bool
MBinaryArithInstruction::constantDoubleResult(TempAllocator& alloc)
{
bool typeChange = false;
EvaluateConstantOperands(alloc, this, &typeChange);
return typeChange;
MConstant* constantResult = EvaluateConstantOperands(alloc, this);
return constantResult != nullptr && constantResult->type() == MIRType::Double;
}
MDefinition*