Bug 907333 - IonMonkey: Add MAssertRange. r=h4writer

This commit is contained in:
Nicolas Pierron 2013-08-26 14:32:38 -07:00
parent 66f51dcf4a
commit f3d6d4154b
12 changed files with 198 additions and 49 deletions

View File

@ -7274,11 +7274,8 @@ CodeGenerator::visitAsmJSCheckOverRecursed(LAsmJSCheckOverRecursed *lir)
}
bool
CodeGenerator::visitRangeAssert(LRangeAssert *ins)
CodeGenerator::emitAssertRangeI(Range *r, Register input)
{
Register input = ToRegister(ins->input());
Range *r = ins->range();
// Check the lower bound.
if (r->lower() != INT32_MIN) {
Label success;
@ -7303,12 +7300,8 @@ CodeGenerator::visitRangeAssert(LRangeAssert *ins)
}
bool
CodeGenerator::visitDoubleRangeAssert(LDoubleRangeAssert *ins)
CodeGenerator::emitAssertRangeD(Range *r, FloatRegister input, FloatRegister temp)
{
FloatRegister input = ToFloatRegister(ins->input());
FloatRegister temp = ToFloatRegister(ins->temp());
Range *r = ins->range();
// Check the lower bound.
if (!r->isLowerInfinite()) {
Label success;
@ -7353,5 +7346,58 @@ CodeGenerator::visitDoubleRangeAssert(LDoubleRangeAssert *ins)
return true;
}
bool
CodeGenerator::visitAssertRangeI(LAssertRangeI *ins)
{
Register input = ToRegister(ins->input());
Range *r = ins->range();
return emitAssertRangeI(r, input);
}
bool
CodeGenerator::visitAssertRangeD(LAssertRangeD *ins)
{
FloatRegister input = ToFloatRegister(ins->input());
FloatRegister temp = ToFloatRegister(ins->temp());
Range *r = ins->range();
return emitAssertRangeD(r, input, temp);
}
bool
CodeGenerator::visitAssertRangeV(LAssertRangeV *ins)
{
Range *r = ins->range();
const ValueOperand value = ToValue(ins, LAssertRangeV::Input);
Register tag = masm.splitTagForTest(value);
Label done;
{
Label isNotInt32;
masm.branchTestInt32(Assembler::NotEqual, tag, &isNotInt32);
Register unboxInt32 = ToTempUnboxRegister(ins->temp());
Register input = masm.extractInt32(value, unboxInt32);
emitAssertRangeI(r, input);
masm.jump(&done);
masm.bind(&isNotInt32);
}
{
Label isNotDouble;
masm.branchTestDouble(Assembler::Equal, tag, &isNotDouble);
FloatRegister input = ToFloatRegister(ins->floatTemp1());
FloatRegister temp = ToFloatRegister(ins->floatTemp2());
masm.unboxDouble(value, input);
emitAssertRangeD(r, input, temp);
masm.jump(&done);
masm.bind(&isNotDouble);
}
masm.breakpoint();
masm.bind(&done);
return true;
}
} // namespace ion
} // namespace js

View File

@ -301,8 +301,9 @@ class CodeGenerator : public CodeGeneratorSpecific
bool visitNameIC(OutOfLineUpdateCache *ool, NameIC *ic);
bool visitCallsiteCloneIC(OutOfLineUpdateCache *ool, CallsiteCloneIC *ic);
bool visitRangeAssert(LRangeAssert *ins);
bool visitDoubleRangeAssert(LDoubleRangeAssert *ins);
bool visitAssertRangeI(LAssertRangeI *ins);
bool visitAssertRangeD(LAssertRangeD *ins);
bool visitAssertRangeV(LAssertRangeV *ins);
IonScriptCounts *extractUnassociatedScriptCounts() {
IonScriptCounts *counts = unassociatedScriptCounts_;
@ -354,6 +355,9 @@ class CodeGenerator : public CodeGeneratorSpecific
// Bailout if an element about to be written to is a hole.
bool emitStoreHoleCheck(Register elements, const LAllocation *index, LSnapshot *snapshot);
bool emitAssertRangeI(Range *r, Register input);
bool emitAssertRangeD(Range *r, FloatRegister input, FloatRegister temp);
// Script counts created when compiling code with no associated JSScript.
IonScriptCounts *unassociatedScriptCounts_;

View File

@ -1331,7 +1331,7 @@ OptimizeMIR(MIRGenerator *mir)
if (mir->shouldCancel("RA Beta"))
return false;
if (!r.analyze())
if (!r.analyze() || !r.addRangeAssertions())
return false;
IonSpewPass("Range Analysis");
AssertExtendedGraphCoherency(graph);

View File

@ -4923,16 +4923,12 @@ class LAsmJSCheckOverRecursed : public LInstructionHelper<0, 0, 0>
}
};
class LRangeAssert : public LInstructionHelper<0, 1, 0>
class LAssertRangeI : public LInstructionHelper<0, 1, 0>
{
Range range_;
public:
LIR_HEADER(RangeAssert)
LIR_HEADER(AssertRangeI)
LRangeAssert(const LAllocation &input, Range r)
: range_(r)
{
LAssertRangeI(const LAllocation &input) {
setOperand(0, input);
}
@ -4940,21 +4936,20 @@ class LRangeAssert : public LInstructionHelper<0, 1, 0>
return getOperand(0);
}
MAssertRange *mir() {
return mir_->toAssertRange();
}
Range *range() {
return &range_;
return mir()->range();
}
};
class LDoubleRangeAssert : public LInstructionHelper<0, 1, 1>
class LAssertRangeD : public LInstructionHelper<0, 1, 1>
{
Range range_;
public:
LIR_HEADER(DoubleRangeAssert)
LIR_HEADER(AssertRangeD)
LDoubleRangeAssert(const LAllocation &input, const LDefinition &temp, Range r)
: range_(r)
{
LAssertRangeD(const LAllocation &input, const LDefinition &temp) {
setOperand(0, input);
setTemp(0, temp);
}
@ -4967,8 +4962,44 @@ class LDoubleRangeAssert : public LInstructionHelper<0, 1, 1>
return getTemp(0);
}
MAssertRange *mir() {
return mir_->toAssertRange();
}
Range *range() {
return &range_;
return mir()->range();
}
};
class LAssertRangeV : public LInstructionHelper<0, BOX_PIECES, 3>
{
public:
LIR_HEADER(AssertRangeV)
LAssertRangeV(const LDefinition &temp, const LDefinition &floatTemp1,
const LDefinition &floatTemp2)
{
setTemp(0, temp);
setTemp(1, floatTemp1);
setTemp(2, floatTemp2);
}
static const size_t Input = 0;
const LDefinition *temp() {
return getTemp(0);
}
const LDefinition *floatTemp1() {
return getTemp(1);
}
const LDefinition *floatTemp2() {
return getTemp(2);
}
MAssertRange *mir() {
return mir_->toAssertRange();
}
Range *range() {
return mir()->range();
}
};

View File

@ -245,8 +245,9 @@
_(AsmJSCall) \
_(AsmJSCheckOverRecursed) \
_(CheckInterruptPar) \
_(RangeAssert) \
_(DoubleRangeAssert)
_(AssertRangeI) \
_(AssertRangeD) \
_(AssertRangeV)
#if defined(JS_CPU_X86)
# include "jit/x86/LOpcodes-x86.h"

View File

@ -2447,6 +2447,36 @@ LIRGenerator::visitGuardString(MGuardString *ins)
return redefine(ins, ins->input());
}
bool
LIRGenerator::visitAssertRange(MAssertRange *ins)
{
MDefinition *input = ins->input();
LInstruction *lir = NULL;
switch (input->type()) {
case MIRType_Int32:
lir = new LAssertRangeI(useRegisterAtStart(input));
break;
case MIRType_Double:
lir = new LAssertRangeD(useRegister(input), tempFloat());
break;
case MIRType_Value:
lir = new LAssertRangeV(tempToUnbox(), tempFloat(), tempFloat());
if (!useBox(lir, LAssertRangeV::Input, input))
return false;
break;
default:
MOZ_ASSUME_UNREACHABLE("Unexpected Range for MIRType");
break;
}
lir->setMir(ins);
return add(lir);
}
bool
LIRGenerator::visitCallGetProperty(MCallGetProperty *ins)
{
@ -2935,25 +2965,6 @@ LIRGenerator::visitInstruction(MInstruction *ins)
return false;
}
// Check the computed range for this instruction, if the option is set. Note
// that this code is quite invasive; it adds numerous additional
// instructions for each MInstruction with a computed range, and it uses
// registers, so it also affects register allocation.
if (js_IonOptions.checkRangeAnalysis) {
if (Range *r = ins->range()) {
switch (ins->type()) {
case MIRType_Int32:
add(new LRangeAssert(useRegisterAtStart(ins), *r));
break;
case MIRType_Double:
add(new LDoubleRangeAssert(useRegister(ins), tempFloat(), *r));
break;
default:
break;
}
}
}
return true;
}

View File

@ -206,6 +206,7 @@ class LIRGenerator : public LIRGeneratorSpecific
bool visitGuardClass(MGuardClass *ins);
bool visitGuardObject(MGuardObject *ins);
bool visitGuardString(MGuardString *ins);
bool visitAssertRange(MAssertRange *ins);
bool visitCallGetProperty(MCallGetProperty *ins);
bool visitDeleteProperty(MDeleteProperty *ins);
bool visitGetNameCache(MGetNameCache *ins);

View File

@ -2227,6 +2227,29 @@ class MGuardString
}
};
class MAssertRange
: public MUnaryInstruction
{
MAssertRange(MDefinition *ins)
: MUnaryInstruction(ins)
{
setGuard();
setMovable();
setResultType(MIRType_None);
}
public:
INSTRUCTION_HEADER(AssertRange)
static MAssertRange *New(MDefinition *ins) {
return new MAssertRange(ins);
}
AliasSet getAliasSet() const {
return AliasSet::None();
}
};
// Caller-side allocation of |this| for |new|:
// Given a templateobject, construct |this| for JSOP_NEW
class MCreateThisWithTemplate

View File

@ -74,6 +74,7 @@ namespace ion {
_(Unbox) \
_(GuardObject) \
_(GuardString) \
_(AssertRange) \
_(ToDouble) \
_(ToInt32) \
_(TruncateToInt32) \

View File

@ -200,6 +200,7 @@ class ParallelSafetyVisitor : public MInstructionVisitor
SAFE_OP(GuardShape)
SAFE_OP(GuardObjectType)
SAFE_OP(GuardClass)
SAFE_OP(AssertRange)
SAFE_OP(ArrayLength)
SAFE_OP(TypedArrayLength)
SAFE_OP(TypedArrayElements)

View File

@ -1612,6 +1612,35 @@ RangeAnalysis::analyze()
return true;
}
bool
RangeAnalysis::addRangeAssertions()
{
if (!js_IonOptions.checkRangeAnalysis)
return true;
// Check the computed range for this instruction, if the option is set. Note
// that this code is quite invasive; it adds numerous additional
// instructions for each MInstruction with a computed range, and it uses
// registers, so it also affects register allocation.
for (ReversePostorderIterator iter(graph_.rpoBegin()); iter != graph_.rpoEnd(); iter++) {
MBasicBlock *block = *iter;
for (MInstructionIterator iter(block->begin()); iter != block->end(); iter++) {
MInstruction *ins = *iter;
Range *r = ins->range();
if (!r || ins->isAssertRange() || ins->isBeta())
continue;
MAssertRange *guard = MAssertRange::New(ins);
guard->setRange(new Range(*r));
block->insertAfter(ins, guard);
}
}
return true;
}
///////////////////////////////////////////////////////////////////////////////
// Range based Truncation
///////////////////////////////////////////////////////////////////////////////

View File

@ -81,6 +81,7 @@ class RangeAnalysis
graph_(graph) {}
bool addBetaNobes();
bool analyze();
bool addRangeAssertions();
bool removeBetaNobes();
bool truncate();