зеркало из https://github.com/mozilla/gecko-dev.git
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:
Родитель
cc606364e6
Коммит
0262b6528c
|
@ -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*
|
||||
|
|
Загрузка…
Ссылка в новой задаче