author | Dan Gohman <sunfish@google.com> |
Tue, 15 Oct 2013 20:49:44 -0700 | |
changeset 150872 | 8f0ebd310f1d0ef9d2d25b2a56b520b264ea13c3 |
parent 150871 | 29a1d64653e8af4d5adfdf9116605c017638caaa |
child 150873 | eba7271a9bee4b06a0c894b10c8ab48764cf68cd |
push id | 25469 |
push user | cbook@mozilla.com |
push date | Wed, 16 Oct 2013 10:46:01 +0000 |
treeherder | autoland@afae5911a1e0 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | nbp |
bugs | 925586 |
milestone | 27.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/js/src/jit/LIR-Common.h +++ b/js/src/jit/LIR-Common.h @@ -2022,18 +2022,18 @@ class LBitOpI : public LInstructionHelpe public: LIR_HEADER(BitOpI) LBitOpI(JSOp op) : op_(op) { } const char *extraName() const { - if (bitop() == JSOP_URSH && mir_->toUrsh()->canOverflow()) - return "UrshCanOverflow"; + if (bitop() == JSOP_URSH && mir_->toUrsh()->bailoutsDisabled()) + return "ursh:BailoutsDisabled"; return js_CodeName[op_]; } JSOp bitop() const { return op_; } };
--- a/js/src/jit/MIR.cpp +++ b/js/src/jit/MIR.cpp @@ -1461,19 +1461,19 @@ bool MMul::canOverflow() { if (isTruncated()) return false; return !range() || !range()->hasInt32Bounds(); } bool -MUrsh::canOverflow() +MUrsh::fallible() { - if (!canOverflow_) + if (bailoutsDisabled()) return false; return !range() || !range()->hasInt32Bounds(); } static inline bool KnownNonStringPrimitive(MDefinition *op) { return !op->mightBeType(MIRType_Object) @@ -2008,17 +2008,24 @@ MUrsh::New(MDefinition *left, MDefinitio return new MUrsh(left, right); } MUrsh * MUrsh::NewAsmJS(MDefinition *left, MDefinition *right) { MUrsh *ins = new MUrsh(left, right); ins->specializeForAsmJS(); - ins->canOverflow_ = false; + + // Since Ion has no UInt32 type, we use Int32 and we have a special + // exception to the type rules: we can return values in + // (INT32_MIN,UINT32_MAX] and still claim that we have an Int32 type + // without bailing out. This is necessary because Ion has no UInt32 + // type and we can't have bailouts in asm.js code. + ins->bailoutsDisabled_ = true; + return ins; } MResumePoint * MResumePoint::New(MBasicBlock *block, jsbytecode *pc, MResumePoint *parent, Mode mode) { MResumePoint *resume = new MResumePoint(block, pc, parent, mode); if (!resume->init())
--- a/js/src/jit/MIR.h +++ b/js/src/jit/MIR.h @@ -553,17 +553,18 @@ class MDefinition : public MNode } public: // Opcode testing and casts. # define OPCODE_CASTS(opcode) \ bool is##opcode() const { \ return op() == Op_##opcode; \ } \ - inline M##opcode *to##opcode(); + inline M##opcode *to##opcode(); \ + inline const M##opcode *to##opcode() const; MIR_OPCODE_LIST(OPCODE_CASTS) # undef OPCODE_CASTS inline MInstruction *toInstruction(); bool isInstruction() const { return !isPhi(); } @@ -3237,21 +3238,21 @@ class MRsh : public MShiftInstruction // x >> 0 => x return getOperand(0); } void computeRange(); }; class MUrsh : public MShiftInstruction { - bool canOverflow_; + bool bailoutsDisabled_; MUrsh(MDefinition *left, MDefinition *right) : MShiftInstruction(left, right), - canOverflow_(true) + bailoutsDisabled_(false) { } public: INSTRUCTION_HEADER(Ursh) static MUrsh *New(MDefinition *left, MDefinition *right); static MUrsh *NewAsmJS(MDefinition *left, MDefinition *right); MDefinition *foldIfZero(size_t operand) { @@ -3259,21 +3260,21 @@ class MUrsh : public MShiftInstruction if (operand == 0) return getOperand(0); return this; } void infer(BaselineInspector *inspector, jsbytecode *pc); - bool canOverflow(); - - bool fallible() { - return canOverflow(); - } + bool bailoutsDisabled() const { + return bailoutsDisabled_; + } + + bool fallible(); void computeRange(); }; class MBinaryArithInstruction : public MBinaryInstruction, public ArithPolicy { @@ -8941,16 +8942,21 @@ class MAsmJSCheckOverRecursed : public M #undef INSTRUCTION_HEADER // Implement opcode casts now that the compiler can see the inheritance. #define OPCODE_CASTS(opcode) \ M##opcode *MDefinition::to##opcode() \ { \ JS_ASSERT(is##opcode()); \ return static_cast<M##opcode *>(this); \ + } \ + const M##opcode *MDefinition::to##opcode() const \ + { \ + JS_ASSERT(is##opcode()); \ + return static_cast<const M##opcode *>(this); \ } MIR_OPCODE_LIST(OPCODE_CASTS) #undef OPCODE_CASTS MDefinition *MNode::toDefinition() { JS_ASSERT(isDefinition()); return (MDefinition *)this;
--- a/js/src/jit/RangeAnalysis.cpp +++ b/js/src/jit/RangeAnalysis.cpp @@ -431,16 +431,24 @@ Range::Range(const MDefinition *def) case MIRType_None: MOZ_ASSUME_UNREACHABLE("Asking for the range of an instruction with no value"); default: setUnknown(); break; } } + // As a special case, MUrsh is permitted to claim a result type of + // MIRType_Int32 while actually returning values in [0,UINT32_MAX] without + // bailouts. If range analysis hasn't ruled out values in + // (INT32_MAX,UINT32_MAX], set the range to be conservatively correct for + // use as either a uint32 or an int32. + if (!hasInt32UpperBound() && def->isUrsh() && def->toUrsh()->bailoutsDisabled()) + lower_ = INT32_MIN; + assertInvariants(); } static inline bool MissingAnyInt32Bounds(const Range *lhs, const Range *rhs) { return !lhs->hasInt32LowerBound() || !lhs->hasInt32UpperBound() || !rhs->hasInt32LowerBound() || !rhs->hasInt32UpperBound(); @@ -1067,18 +1075,16 @@ MUrsh::computeRange() right.wrapAroundToShiftCount(); setRange(Range::ursh(&left, &right)); } else { int32_t c = rhs->toConstant()->value().toInt32(); setRange(Range::ursh(&left, c)); } JS_ASSERT(range()->lower() >= 0); - if (type() == MIRType_Int32 && !range()->hasInt32UpperBound()) - range()->extendUInt32ToInt32Min(); } void MAbs::computeRange() { if (specialization_ != MIRType_Int32 && specialization_ != MIRType_Double) return;
--- a/js/src/jit/RangeAnalysis.h +++ b/js/src/jit/RangeAnalysis.h @@ -512,24 +512,16 @@ class Range : public TempObject { // If this range exceeds [0, 32) range, at either or both ends, change // it to the [0, 32) range. Otherwise do nothing. void wrapAroundToShiftCount(); // If this range exceeds [0, 1] range, at either or both ends, change // it to the [0, 1] range. Otherwise do nothing. void wrapAroundToBoolean(); - // As we lack support of MIRType_UInt32, we need to work around the int32 - // representation by doing an overflow while keeping the upper infinity to - // repesent the fact that the value might reach bigger numbers. - void extendUInt32ToInt32Min() { - JS_ASSERT(!hasInt32UpperBound()); - lower_ = JSVAL_INT_MIN; - } - const SymbolicBound *symbolicLower() const { return symbolicLower_; } const SymbolicBound *symbolicUpper() const { return symbolicUpper_; } void setSymbolicLower(SymbolicBound *bound) {
--- a/js/src/jit/arm/CodeGenerator-arm.cpp +++ b/js/src/jit/arm/CodeGenerator-arm.cpp @@ -902,17 +902,17 @@ CodeGeneratorARM::visitShiftI(LShiftI *i masm.ma_mov(lhs, dest); break; case JSOP_URSH: if (shift) { masm.ma_lsr(Imm32(shift), lhs, dest); } else { // x >>> 0 can overflow. masm.ma_mov(lhs, dest); - if (ins->mir()->toUrsh()->canOverflow()) { + if (ins->mir()->toUrsh()->fallible()) { masm.ma_cmp(dest, Imm32(0)); if (!bailoutIf(Assembler::LessThan, ins->snapshot())) return false; } } break; default: MOZ_ASSUME_UNREACHABLE("Unexpected shift op"); @@ -927,17 +927,17 @@ CodeGeneratorARM::visitShiftI(LShiftI *i case JSOP_LSH: masm.ma_lsl(dest, lhs, dest); break; case JSOP_RSH: masm.ma_asr(dest, lhs, dest); break; case JSOP_URSH: masm.ma_lsr(dest, lhs, dest); - if (ins->mir()->toUrsh()->canOverflow()) { + if (ins->mir()->toUrsh()->fallible()) { // x >>> 0 can overflow. masm.ma_cmp(dest, Imm32(0)); if (!bailoutIf(Assembler::LessThan, ins->snapshot())) return false; } break; default: MOZ_ASSUME_UNREACHABLE("Unexpected shift op");
--- a/js/src/jit/shared/CodeGenerator-x86-shared.cpp +++ b/js/src/jit/shared/CodeGenerator-x86-shared.cpp @@ -1099,17 +1099,17 @@ CodeGeneratorX86Shared::visitShiftI(LShi break; case JSOP_RSH: if (shift) masm.sarl(Imm32(shift), lhs); break; case JSOP_URSH: if (shift) { masm.shrl(Imm32(shift), lhs); - } else if (ins->mir()->toUrsh()->canOverflow()) { + } else if (ins->mir()->toUrsh()->fallible()) { // x >>> 0 can overflow. masm.testl(lhs, lhs); if (!bailoutIf(Assembler::Signed, ins->snapshot())) return false; } break; default: MOZ_ASSUME_UNREACHABLE("Unexpected shift op"); @@ -1120,17 +1120,17 @@ CodeGeneratorX86Shared::visitShiftI(LShi case JSOP_LSH: masm.shll_cl(lhs); break; case JSOP_RSH: masm.sarl_cl(lhs); break; case JSOP_URSH: masm.shrl_cl(lhs); - if (ins->mir()->toUrsh()->canOverflow()) { + if (ins->mir()->toUrsh()->fallible()) { // x >>> 0 can overflow. masm.testl(lhs, lhs); if (!bailoutIf(Assembler::Signed, ins->snapshot())) return false; } break; default: MOZ_ASSUME_UNREACHABLE("Unexpected shift op");