mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 799818 part 2 - Handle unknown double as input of a table switch. r=djvj,h4writer
This commit is contained in:
parent
31ec5c25f7
commit
45f634660f
@ -361,6 +361,49 @@ CodeGenerator::visitGoto(LGoto *lir)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
CodeGenerator::visitTableSwitch(LTableSwitch *ins)
|
||||||
|
{
|
||||||
|
MTableSwitch *mir = ins->mir();
|
||||||
|
Label *defaultcase = mir->getDefault()->lir()->label();
|
||||||
|
const LAllocation *temp;
|
||||||
|
|
||||||
|
if (ins->index()->isDouble()) {
|
||||||
|
temp = ins->tempInt();
|
||||||
|
|
||||||
|
// The input is a double, so try and convert it to an integer.
|
||||||
|
// If it does not fit in an integer, take the default case.
|
||||||
|
emitDoubleToInt32(ToFloatRegister(ins->index()), ToRegister(temp), defaultcase, false);
|
||||||
|
} else {
|
||||||
|
temp = ins->index();
|
||||||
|
}
|
||||||
|
|
||||||
|
return emitTableSwitchDispatch(mir, ToRegister(temp), ToRegisterOrInvalid(ins->tempPointer()));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
CodeGenerator::visitTableSwitchV(LTableSwitchV *ins)
|
||||||
|
{
|
||||||
|
MTableSwitch *mir = ins->mir();
|
||||||
|
Label *defaultcase = mir->getDefault()->lir()->label();
|
||||||
|
|
||||||
|
Register index = ToRegister(ins->tempInt());
|
||||||
|
ValueOperand value = ToValue(ins, LTableSwitchV::Index);
|
||||||
|
Register tag = masm.extractTag(value, index);
|
||||||
|
masm.branchTestNumber(Assembler::NotEqual, tag, defaultcase);
|
||||||
|
|
||||||
|
Label isInt;
|
||||||
|
masm.branchTestInt32(Assembler::Equal, tag, &isInt);
|
||||||
|
{
|
||||||
|
FloatRegister floatIndex = ToFloatRegister(ins->tempFloat());
|
||||||
|
masm.unboxDouble(value, floatIndex);
|
||||||
|
emitDoubleToInt32(floatIndex, index, defaultcase, false);
|
||||||
|
}
|
||||||
|
masm.bind(&isInt);
|
||||||
|
|
||||||
|
return emitTableSwitchDispatch(mir, index, ToRegisterOrInvalid(ins->tempPointer()));
|
||||||
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
CodeGenerator::visitParameter(LParameter *lir)
|
CodeGenerator::visitParameter(LParameter *lir)
|
||||||
{
|
{
|
||||||
|
@ -45,6 +45,8 @@ class CodeGenerator : public CodeGeneratorSpecific
|
|||||||
bool visitNop(LNop *lir);
|
bool visitNop(LNop *lir);
|
||||||
bool visitOsiPoint(LOsiPoint *lir);
|
bool visitOsiPoint(LOsiPoint *lir);
|
||||||
bool visitGoto(LGoto *lir);
|
bool visitGoto(LGoto *lir);
|
||||||
|
bool visitTableSwitch(LTableSwitch *ins);
|
||||||
|
bool visitTableSwitchV(LTableSwitchV *ins);
|
||||||
bool visitParameter(LParameter *lir);
|
bool visitParameter(LParameter *lir);
|
||||||
bool visitCallee(LCallee *lir);
|
bool visitCallee(LCallee *lir);
|
||||||
bool visitStart(LStart *lir);
|
bool visitStart(LStart *lir);
|
||||||
|
@ -20,6 +20,7 @@
|
|||||||
_(Parameter) \
|
_(Parameter) \
|
||||||
_(Callee) \
|
_(Callee) \
|
||||||
_(TableSwitch) \
|
_(TableSwitch) \
|
||||||
|
_(TableSwitchV) \
|
||||||
_(Goto) \
|
_(Goto) \
|
||||||
_(NewArray) \
|
_(NewArray) \
|
||||||
_(NewObject) \
|
_(NewObject) \
|
||||||
|
@ -67,6 +67,44 @@ LIRGenerator::visitGoto(MGoto *ins)
|
|||||||
return add(new LGoto(ins->target()));
|
return add(new LGoto(ins->target()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
LIRGenerator::visitTableSwitch(MTableSwitch *tableswitch)
|
||||||
|
{
|
||||||
|
MDefinition *opd = tableswitch->getOperand(0);
|
||||||
|
|
||||||
|
// There should be at least 1 successor. The default case!
|
||||||
|
JS_ASSERT(tableswitch->numSuccessors() > 0);
|
||||||
|
|
||||||
|
// If there are no cases, the default case is always taken.
|
||||||
|
if (tableswitch->numSuccessors() == 1)
|
||||||
|
return add(new LGoto(tableswitch->getDefault()));
|
||||||
|
|
||||||
|
// If we don't know the type.
|
||||||
|
if (opd->type() == MIRType_Value) {
|
||||||
|
LTableSwitchV *lir = newLTableSwitchV(tableswitch);
|
||||||
|
if (!useBox(lir, LTableSwitchV::InputValue, opd))
|
||||||
|
return false;
|
||||||
|
return add(lir);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Case indices are numeric, so other types will always go to the default case.
|
||||||
|
if (opd->type() != MIRType_Int32 && opd->type() != MIRType_Double)
|
||||||
|
return add(new LGoto(tableswitch->getDefault()));
|
||||||
|
|
||||||
|
// Return an LTableSwitch, capable of handling either an integer or
|
||||||
|
// floating-point index.
|
||||||
|
LAllocation index;
|
||||||
|
LDefinition tempInt;
|
||||||
|
if (opd->type() == MIRType_Int32) {
|
||||||
|
index = useRegisterAtStart(opd);
|
||||||
|
tempInt = tempCopy(opd, 0);
|
||||||
|
} else {
|
||||||
|
index = useRegister(opd);
|
||||||
|
tempInt = temp(LDefinition::GENERAL);
|
||||||
|
}
|
||||||
|
return add(newLTableSwitch(index, tempInt, tableswitch));
|
||||||
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
LIRGenerator::visitCheckOverRecursed(MCheckOverRecursed *ins)
|
LIRGenerator::visitCheckOverRecursed(MCheckOverRecursed *ins)
|
||||||
{
|
{
|
||||||
|
@ -77,6 +77,7 @@ class LIRGenerator : public LIRGeneratorSpecific
|
|||||||
bool visitParameter(MParameter *param);
|
bool visitParameter(MParameter *param);
|
||||||
bool visitCallee(MCallee *callee);
|
bool visitCallee(MCallee *callee);
|
||||||
bool visitGoto(MGoto *ins);
|
bool visitGoto(MGoto *ins);
|
||||||
|
bool visitTableSwitch(MTableSwitch *tableswitch);
|
||||||
bool visitNewSlots(MNewSlots *ins);
|
bool visitNewSlots(MNewSlots *ins);
|
||||||
bool visitNewArray(MNewArray *ins);
|
bool visitNewArray(MNewArray *ins);
|
||||||
bool visitNewObject(MNewObject *ins);
|
bool visitNewObject(MNewObject *ins);
|
||||||
|
@ -695,8 +695,7 @@ class MControlInstruction : public MInstruction
|
|||||||
};
|
};
|
||||||
|
|
||||||
class MTableSwitch
|
class MTableSwitch
|
||||||
: public MControlInstruction,
|
: public MControlInstruction
|
||||||
public TableSwitchPolicy
|
|
||||||
{
|
{
|
||||||
// The successors of the tableswitch
|
// The successors of the tableswitch
|
||||||
// - First successor = the default case
|
// - First successor = the default case
|
||||||
@ -800,10 +799,6 @@ class MTableSwitch
|
|||||||
size_t numOperands() const {
|
size_t numOperands() const {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
TypePolicy *typePolicy() {
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
template <size_t Arity, size_t Successors>
|
template <size_t Arity, size_t Successors>
|
||||||
|
@ -222,28 +222,6 @@ BitwisePolicy::adjustInputs(MInstruction *ins)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
|
||||||
TableSwitchPolicy::adjustInputs(MInstruction *ins)
|
|
||||||
{
|
|
||||||
MDefinition *in = ins->getOperand(0);
|
|
||||||
MInstruction *replace;
|
|
||||||
|
|
||||||
// Tableswitch can consume all types, except:
|
|
||||||
// - Value: unbox to int32
|
|
||||||
switch (in->type()) {
|
|
||||||
case MIRType_Value:
|
|
||||||
replace = MUnbox::New(in, MIRType_Int32, MUnbox::Fallible);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
ins->block()->insertBefore(ins, replace);
|
|
||||||
ins->replaceOperand(0, replace);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
bool
|
||||||
PowPolicy::adjustInputs(MInstruction *ins)
|
PowPolicy::adjustInputs(MInstruction *ins)
|
||||||
{
|
{
|
||||||
|
@ -75,12 +75,6 @@ class BitwisePolicy : public BoxInputsPolicy
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class TableSwitchPolicy : public BoxInputsPolicy
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
bool adjustInputs(MInstruction *def);
|
|
||||||
};
|
|
||||||
|
|
||||||
class ComparePolicy : public BoxInputsPolicy
|
class ComparePolicy : public BoxInputsPolicy
|
||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
|
@ -26,20 +26,20 @@ using namespace js::ion;
|
|||||||
|
|
||||||
class DeferredJumpTable : public DeferredData
|
class DeferredJumpTable : public DeferredData
|
||||||
{
|
{
|
||||||
LTableSwitch *lswitch;
|
MTableSwitch *mswitch;
|
||||||
BufferOffset off;
|
BufferOffset off;
|
||||||
MacroAssembler *masm;
|
MacroAssembler *masm;
|
||||||
public:
|
public:
|
||||||
DeferredJumpTable(LTableSwitch *lswitch, BufferOffset off_, MacroAssembler *masm_)
|
DeferredJumpTable(MTableSwitch *mswitch, BufferOffset off_, MacroAssembler *masm_)
|
||||||
: lswitch(lswitch), off(off_), masm(masm_)
|
: mswitch(mswitch), off(off_), masm(masm_)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
void copy(IonCode *code, uint8 *ignore__) const {
|
void copy(IonCode *code, uint8 *ignore__) const {
|
||||||
void **jumpData = (void **)(((char*)code->raw()) + masm->actualOffset(off).getOffset());
|
void **jumpData = (void **)(((char*)code->raw()) + masm->actualOffset(off).getOffset());
|
||||||
int numCases = lswitch->mir()->numCases();
|
int numCases = mswitch->numCases();
|
||||||
// For every case write the pointer to the start in the table
|
// For every case write the pointer to the start in the table
|
||||||
for (int j = 0; j < numCases; j++) {
|
for (int j = 0; j < numCases; j++) {
|
||||||
LBlock *caseblock = lswitch->mir()->getCase(numCases - 1 - j)->lir();
|
LBlock *caseblock = mswitch->getCase(numCases - 1 - j)->lir();
|
||||||
Label *caseheader = caseblock->label();
|
Label *caseheader = caseblock->label();
|
||||||
|
|
||||||
uint32 offset = caseheader->offset();
|
uint32 offset = caseheader->offset();
|
||||||
@ -841,7 +841,8 @@ CodeGeneratorARM::visitMoveGroup(LMoveGroup *group)
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
CodeGeneratorARM::visitTableSwitch(LTableSwitch *ins)
|
CodeGeneratorARM::emitTableSwitchDispatch(MTableSwitch *mir, const Register &index,
|
||||||
|
const Register &base)
|
||||||
{
|
{
|
||||||
// the code generated by this is utter hax.
|
// the code generated by this is utter hax.
|
||||||
// the end result looks something like:
|
// the end result looks something like:
|
||||||
@ -869,29 +870,16 @@ CodeGeneratorARM::visitTableSwitch(LTableSwitch *ins)
|
|||||||
// unhandled case is the default case (both out of range high and out of range low)
|
// unhandled case is the default case (both out of range high and out of range low)
|
||||||
// I then insert a branch to default case into the extra slot, which ensures
|
// I then insert a branch to default case into the extra slot, which ensures
|
||||||
// we don't attempt to execute the address table.
|
// we don't attempt to execute the address table.
|
||||||
MTableSwitch *mir = ins->mir();
|
Label *defaultcase = mir->getDefault()->lir()->label();
|
||||||
Label *defaultcase = mir->getDefault()->lir()->label();
|
|
||||||
const LAllocation *temp;
|
|
||||||
|
|
||||||
if (ins->index()->isDouble()) {
|
|
||||||
temp = ins->tempInt();
|
|
||||||
|
|
||||||
// The input is a double, so try and convert it to an integer.
|
|
||||||
// If it does not fit in an integer, take the default case.
|
|
||||||
emitDoubleToInt32(ToFloatRegister(ins->index()), ToRegister(temp), defaultcase, false);
|
|
||||||
} else {
|
|
||||||
temp = ins->index();
|
|
||||||
}
|
|
||||||
|
|
||||||
int32 cases = mir->numCases();
|
int32 cases = mir->numCases();
|
||||||
Register tempReg = ToRegister(temp);
|
|
||||||
// Lower value with low value
|
// Lower value with low value
|
||||||
masm.ma_sub(tempReg, Imm32(mir->low()), tempReg, SetCond);
|
masm.ma_sub(index, Imm32(mir->low()), index, SetCond);
|
||||||
masm.ma_rsb(tempReg, Imm32(cases - 1), tempReg, SetCond, Assembler::Unsigned);
|
masm.ma_rsb(index, Imm32(cases - 1), index, SetCond, Assembler::Unsigned);
|
||||||
AutoForbidPools afp(&masm);
|
AutoForbidPools afp(&masm);
|
||||||
masm.ma_ldr(DTRAddr(pc, DtrRegImmShift(tempReg, LSL, 2)), pc, Offset, Assembler::Unsigned);
|
masm.ma_ldr(DTRAddr(pc, DtrRegImmShift(index, LSL, 2)), pc, Offset, Assembler::Unsigned);
|
||||||
masm.ma_b(defaultcase);
|
masm.ma_b(defaultcase);
|
||||||
DeferredJumpTable *d = new DeferredJumpTable(ins, masm.nextOffset(), &masm);
|
DeferredJumpTable *d = new DeferredJumpTable(mir, masm.nextOffset(), &masm);
|
||||||
masm.as_jumpPool(cases);
|
masm.as_jumpPool(cases);
|
||||||
|
|
||||||
if (!masm.addDeferredData(d, 0))
|
if (!masm.addDeferredData(d, 0))
|
||||||
|
@ -64,6 +64,8 @@ class CodeGeneratorARM : public CodeGeneratorShared
|
|||||||
// true, and the false block if |cond| is false.
|
// true, and the false block if |cond| is false.
|
||||||
void emitBranch(Assembler::Condition cond, MBasicBlock *ifTrue, MBasicBlock *ifFalse);
|
void emitBranch(Assembler::Condition cond, MBasicBlock *ifTrue, MBasicBlock *ifFalse);
|
||||||
|
|
||||||
|
bool emitTableSwitchDispatch(MTableSwitch *mir, const Register &index, const Register &base);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// Instruction visitors.
|
// Instruction visitors.
|
||||||
virtual bool visitMinMaxD(LMinMaxD *ins);
|
virtual bool visitMinMaxD(LMinMaxD *ins);
|
||||||
@ -99,7 +101,6 @@ class CodeGeneratorARM : public CodeGeneratorShared
|
|||||||
virtual bool visitMathD(LMathD *math);
|
virtual bool visitMathD(LMathD *math);
|
||||||
virtual bool visitFloor(LFloor *lir);
|
virtual bool visitFloor(LFloor *lir);
|
||||||
virtual bool visitRound(LRound *lir);
|
virtual bool visitRound(LRound *lir);
|
||||||
virtual bool visitTableSwitch(LTableSwitch *ins);
|
|
||||||
virtual bool visitTruncateDToInt32(LTruncateDToInt32 *ins);
|
virtual bool visitTruncateDToInt32(LTruncateDToInt32 *ins);
|
||||||
|
|
||||||
// Out of line visitors.
|
// Out of line visitors.
|
||||||
|
@ -200,6 +200,41 @@ class LTableSwitch : public LInstructionHelper<0, 1, 1>
|
|||||||
const LAllocation *tempInt() {
|
const LAllocation *tempInt() {
|
||||||
return getTemp(0)->output();
|
return getTemp(0)->output();
|
||||||
}
|
}
|
||||||
|
// This is added to share the same CodeGenerator prefixes.
|
||||||
|
const LAllocation *tempPointer() {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Takes a tableswitch with an integer to decide
|
||||||
|
class LTableSwitchV : public LInstructionHelper<0, BOX_PIECES, 2>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
LIR_HEADER(TableSwitchV);
|
||||||
|
|
||||||
|
LTableSwitchV(const LDefinition &inputCopy, const LDefinition &floatCopy,
|
||||||
|
MTableSwitch *ins)
|
||||||
|
{
|
||||||
|
setTemp(0, inputCopy);
|
||||||
|
setTemp(1, floatCopy);
|
||||||
|
setMir(ins);
|
||||||
|
}
|
||||||
|
|
||||||
|
MTableSwitch *mir() const {
|
||||||
|
return mir_->toTableSwitch();
|
||||||
|
}
|
||||||
|
|
||||||
|
static const size_t InputValue = 0;
|
||||||
|
|
||||||
|
const LAllocation *tempInt() {
|
||||||
|
return getTemp(0)->output();
|
||||||
|
}
|
||||||
|
const LAllocation *tempFloat() {
|
||||||
|
return getTemp(1)->output();
|
||||||
|
}
|
||||||
|
const LAllocation *tempPointer() {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Guard against an object's shape.
|
// Guard against an object's shape.
|
||||||
|
@ -281,34 +281,17 @@ LIRGeneratorARM::visitPowHalf(MPowHalf *ins)
|
|||||||
return defineReuseInput(lir, ins, 0);
|
return defineReuseInput(lir, ins, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
LTableSwitch *
|
||||||
LIRGeneratorARM::visitTableSwitch(MTableSwitch *tableswitch)
|
LIRGeneratorARM::newLTableSwitch(const LAllocation &in, const LDefinition &inputCopy,
|
||||||
|
MTableSwitch *tableswitch)
|
||||||
{
|
{
|
||||||
MDefinition *opd = tableswitch->getOperand(0);
|
return new LTableSwitch(in, inputCopy, tableswitch);
|
||||||
|
}
|
||||||
|
|
||||||
// There should be at least 1 successor. The default case!
|
LTableSwitchV *
|
||||||
JS_ASSERT(tableswitch->numSuccessors() > 0);
|
LIRGeneratorARM::newLTableSwitchV(MTableSwitch *tableswitch)
|
||||||
|
{
|
||||||
// If there are no cases, the default case is always taken.
|
return new LTableSwitchV(temp(), tempFloat(), tableswitch);
|
||||||
if (tableswitch->numSuccessors() == 1)
|
|
||||||
return add(new LGoto(tableswitch->getDefault()));
|
|
||||||
|
|
||||||
// Case indices are numeric, so other types will always go to the default case.
|
|
||||||
if (opd->type() != MIRType_Int32 && opd->type() != MIRType_Double)
|
|
||||||
return add(new LGoto(tableswitch->getDefault()));
|
|
||||||
|
|
||||||
// Return an LTableSwitch, capable of handling either an integer or
|
|
||||||
// floating-point index.
|
|
||||||
LAllocation index;
|
|
||||||
LDefinition tempInt;
|
|
||||||
if (opd->type() == MIRType_Int32) {
|
|
||||||
index = useRegisterAtStart(opd);
|
|
||||||
tempInt = tempCopy(opd, 0);
|
|
||||||
} else {
|
|
||||||
index = useRegister(opd);
|
|
||||||
tempInt = temp(LDefinition::GENERAL);
|
|
||||||
}
|
|
||||||
return add(new LTableSwitch(index, tempInt, tableswitch));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
|
@ -48,7 +48,10 @@ class LIRGeneratorARM : public LIRGeneratorShared
|
|||||||
bool lowerModI(MMod *mod);
|
bool lowerModI(MMod *mod);
|
||||||
bool lowerMulI(MMul *mul, MDefinition *lhs, MDefinition *rhs);
|
bool lowerMulI(MMul *mul, MDefinition *lhs, MDefinition *rhs);
|
||||||
bool visitPowHalf(MPowHalf *ins);
|
bool visitPowHalf(MPowHalf *ins);
|
||||||
bool visitTableSwitch(MTableSwitch *tableswitch);
|
|
||||||
|
LTableSwitch *newLTableSwitch(const LAllocation &in, const LDefinition &inputCopy,
|
||||||
|
MTableSwitch *ins);
|
||||||
|
LTableSwitchV *newLTableSwitchV(MTableSwitch *ins);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
bool visitConstant(MConstant *ins);
|
bool visitConstant(MConstant *ins);
|
||||||
|
@ -41,6 +41,12 @@ ToRegister(const LDefinition *def)
|
|||||||
return ToRegister(*def->output());
|
return ToRegister(*def->output());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline Register
|
||||||
|
ToRegisterOrInvalid(const LAllocation *a)
|
||||||
|
{
|
||||||
|
return a ? ToRegister(*a) : InvalidReg;
|
||||||
|
}
|
||||||
|
|
||||||
static inline FloatRegister
|
static inline FloatRegister
|
||||||
ToFloatRegister(const LAllocation &a)
|
ToFloatRegister(const LAllocation &a)
|
||||||
{
|
{
|
||||||
|
@ -22,19 +22,19 @@ namespace ion {
|
|||||||
|
|
||||||
class DeferredJumpTable : public DeferredData
|
class DeferredJumpTable : public DeferredData
|
||||||
{
|
{
|
||||||
LTableSwitch *lswitch;
|
MTableSwitch *mswitch;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
DeferredJumpTable(LTableSwitch *lswitch)
|
DeferredJumpTable(MTableSwitch *mswitch)
|
||||||
: lswitch(lswitch)
|
: mswitch(mswitch)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
void copy(IonCode *code, uint8 *buffer) const {
|
void copy(IonCode *code, uint8 *buffer) const {
|
||||||
void **jumpData = (void **)buffer;
|
void **jumpData = (void **)buffer;
|
||||||
|
|
||||||
// For every case write the pointer to the start in the table
|
// For every case write the pointer to the start in the table
|
||||||
for (size_t j = 0; j < lswitch->mir()->numCases(); j++) {
|
for (size_t j = 0; j < mswitch->numCases(); j++) {
|
||||||
LBlock *caseblock = lswitch->mir()->getCase(j)->lir();
|
LBlock *caseblock = mswitch->getCase(j)->lir();
|
||||||
Label *caseheader = caseblock->label();
|
Label *caseheader = caseblock->label();
|
||||||
|
|
||||||
uint32 offset = caseheader->offset();
|
uint32 offset = caseheader->offset();
|
||||||
@ -933,40 +933,28 @@ CodeGeneratorX86Shared::visitMoveGroup(LMoveGroup *group)
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
CodeGeneratorX86Shared::visitTableSwitch(LTableSwitch *ins)
|
CodeGeneratorX86Shared::emitTableSwitchDispatch(MTableSwitch *mir, const Register &index,
|
||||||
|
const Register &base)
|
||||||
{
|
{
|
||||||
MTableSwitch *mir = ins->mir();
|
|
||||||
Label *defaultcase = mir->getDefault()->lir()->label();
|
Label *defaultcase = mir->getDefault()->lir()->label();
|
||||||
const LAllocation *temp;
|
|
||||||
|
|
||||||
if (ins->index()->isDouble()) {
|
|
||||||
temp = ins->tempInt();
|
|
||||||
|
|
||||||
// The input is a double, so try and convert it to an integer.
|
|
||||||
// If it does not fit in an integer, take the default case.
|
|
||||||
emitDoubleToInt32(ToFloatRegister(ins->index()), ToRegister(temp), defaultcase, false);
|
|
||||||
} else {
|
|
||||||
temp = ins->index();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Lower value with low value
|
// Lower value with low value
|
||||||
if (mir->low() != 0)
|
if (mir->low() != 0)
|
||||||
masm.subl(Imm32(mir->low()), ToRegister(temp));
|
masm.subl(Imm32(mir->low()), index);
|
||||||
|
|
||||||
// Jump to default case if input is out of range
|
// Jump to default case if input is out of range
|
||||||
int32 cases = mir->numCases();
|
int32 cases = mir->numCases();
|
||||||
masm.cmpl(ToRegister(temp), Imm32(cases));
|
masm.cmpl(index, Imm32(cases));
|
||||||
masm.j(AssemblerX86Shared::AboveOrEqual, defaultcase);
|
masm.j(AssemblerX86Shared::AboveOrEqual, defaultcase);
|
||||||
|
|
||||||
// Create a JumpTable that during linking will get written.
|
// Create a JumpTable that during linking will get written.
|
||||||
DeferredJumpTable *d = new DeferredJumpTable(ins);
|
DeferredJumpTable *d = new DeferredJumpTable(mir);
|
||||||
if (!masm.addDeferredData(d, (1 << ScalePointer) * cases))
|
if (!masm.addDeferredData(d, (1 << ScalePointer) * cases))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// Compute the position where a pointer to the right case stands.
|
// Compute the position where a pointer to the right case stands.
|
||||||
const LAllocation *base = ins->tempPointer();
|
masm.mov(d->label(), base);
|
||||||
masm.mov(d->label(), ToRegister(base));
|
Operand pointer = Operand(base, index, ScalePointer);
|
||||||
Operand pointer = Operand(ToRegister(base), ToRegister(temp), ScalePointer);
|
|
||||||
|
|
||||||
// Jump to the right case
|
// Jump to the right case
|
||||||
masm.jmp(pointer);
|
masm.jmp(pointer);
|
||||||
|
@ -80,6 +80,8 @@ class CodeGeneratorX86Shared : public CodeGeneratorShared
|
|||||||
NaNCond ifNaN = NaN_Unexpected);
|
NaNCond ifNaN = NaN_Unexpected);
|
||||||
void emitBranch(Assembler::DoubleCondition cond, MBasicBlock *ifTrue, MBasicBlock *ifFalse);
|
void emitBranch(Assembler::DoubleCondition cond, MBasicBlock *ifTrue, MBasicBlock *ifFalse);
|
||||||
|
|
||||||
|
bool emitTableSwitchDispatch(MTableSwitch *mir, const Register &index, const Register &base);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CodeGeneratorX86Shared(MIRGenerator *gen, LIRGraph &graph);
|
CodeGeneratorX86Shared(MIRGenerator *gen, LIRGraph &graph);
|
||||||
|
|
||||||
@ -111,7 +113,6 @@ class CodeGeneratorX86Shared : public CodeGeneratorShared
|
|||||||
virtual bool visitMathD(LMathD *math);
|
virtual bool visitMathD(LMathD *math);
|
||||||
virtual bool visitFloor(LFloor *lir);
|
virtual bool visitFloor(LFloor *lir);
|
||||||
virtual bool visitRound(LRound *lir);
|
virtual bool visitRound(LRound *lir);
|
||||||
virtual bool visitTableSwitch(LTableSwitch *ins);
|
|
||||||
virtual bool visitGuardShape(LGuardShape *guard);
|
virtual bool visitGuardShape(LGuardShape *guard);
|
||||||
virtual bool visitGuardClass(LGuardClass *guard);
|
virtual bool visitGuardClass(LGuardClass *guard);
|
||||||
virtual bool visitTruncateDToInt32(LTruncateDToInt32 *ins);
|
virtual bool visitTruncateDToInt32(LTruncateDToInt32 *ins);
|
||||||
|
@ -117,6 +117,38 @@ class LTableSwitch : public LInstructionHelper<0, 1, 2>
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Takes a tableswitch with a value to decide
|
||||||
|
class LTableSwitchV : public LInstructionHelper<0, BOX_PIECES, 3>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
LIR_HEADER(TableSwitchV);
|
||||||
|
|
||||||
|
LTableSwitchV(const LDefinition &inputCopy, const LDefinition &floatCopy,
|
||||||
|
const LDefinition &jumpTablePointer, MTableSwitch *ins)
|
||||||
|
{
|
||||||
|
setTemp(0, inputCopy);
|
||||||
|
setTemp(1, floatCopy);
|
||||||
|
setTemp(2, jumpTablePointer);
|
||||||
|
setMir(ins);
|
||||||
|
}
|
||||||
|
|
||||||
|
MTableSwitch *mir() const {
|
||||||
|
return mir_->toTableSwitch();
|
||||||
|
}
|
||||||
|
|
||||||
|
static const size_t InputValue = 0;
|
||||||
|
|
||||||
|
const LAllocation *tempInt() {
|
||||||
|
return getTemp(0)->output();
|
||||||
|
}
|
||||||
|
const LAllocation *tempFloat() {
|
||||||
|
return getTemp(1)->output();
|
||||||
|
}
|
||||||
|
const LAllocation *tempPointer() {
|
||||||
|
return getTemp(2)->output();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// Guard against an object's shape.
|
// Guard against an object's shape.
|
||||||
class LGuardShape : public LInstructionHelper<0, 1, 0>
|
class LGuardShape : public LInstructionHelper<0, 1, 0>
|
||||||
{
|
{
|
||||||
|
@ -12,34 +12,17 @@
|
|||||||
using namespace js;
|
using namespace js;
|
||||||
using namespace js::ion;
|
using namespace js::ion;
|
||||||
|
|
||||||
bool
|
LTableSwitch *
|
||||||
LIRGeneratorX86Shared::visitTableSwitch(MTableSwitch *tableswitch)
|
LIRGeneratorX86Shared::newLTableSwitch(const LAllocation &in, const LDefinition &inputCopy,
|
||||||
|
MTableSwitch *tableswitch)
|
||||||
{
|
{
|
||||||
MDefinition *opd = tableswitch->getOperand(0);
|
return new LTableSwitch(in, inputCopy, temp(), tableswitch);
|
||||||
|
}
|
||||||
|
|
||||||
// There should be at least 1 successor. The default case!
|
LTableSwitchV *
|
||||||
JS_ASSERT(tableswitch->numSuccessors() > 0);
|
LIRGeneratorX86Shared::newLTableSwitchV(MTableSwitch *tableswitch)
|
||||||
|
{
|
||||||
// If there are no cases, the default case is always taken.
|
return new LTableSwitchV(temp(), tempFloat(), temp(), tableswitch);
|
||||||
if (tableswitch->numSuccessors() == 1)
|
|
||||||
return add(new LGoto(tableswitch->getDefault()));
|
|
||||||
|
|
||||||
// Case indices are numeric, so other types will always go to the default case.
|
|
||||||
if (opd->type() != MIRType_Int32 && opd->type() != MIRType_Double)
|
|
||||||
return add(new LGoto(tableswitch->getDefault()));
|
|
||||||
|
|
||||||
// Return an LTableSwitch, capable of handling either an integer or
|
|
||||||
// floating-point index.
|
|
||||||
LAllocation index;
|
|
||||||
LDefinition tempInt;
|
|
||||||
if (opd->type() == MIRType_Int32) {
|
|
||||||
index = useRegisterAtStart(opd);
|
|
||||||
tempInt = tempCopy(opd, 0);
|
|
||||||
} else {
|
|
||||||
index = useRegister(opd);
|
|
||||||
tempInt = temp(LDefinition::GENERAL);
|
|
||||||
}
|
|
||||||
return add(new LTableSwitch(index, tempInt, temp(LDefinition::GENERAL), tableswitch));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
|
@ -20,7 +20,10 @@ class LIRGeneratorX86Shared : public LIRGeneratorShared
|
|||||||
: LIRGeneratorShared(gen, graph, lirGraph)
|
: LIRGeneratorShared(gen, graph, lirGraph)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
bool visitTableSwitch(MTableSwitch *tableswitch);
|
LTableSwitch *newLTableSwitch(const LAllocation &in, const LDefinition &inputCopy,
|
||||||
|
MTableSwitch *ins);
|
||||||
|
LTableSwitchV *newLTableSwitchV(MTableSwitch *ins);
|
||||||
|
|
||||||
bool visitRecompileCheck(MRecompileCheck *ins);
|
bool visitRecompileCheck(MRecompileCheck *ins);
|
||||||
bool visitInterruptCheck(MInterruptCheck *ins);
|
bool visitInterruptCheck(MInterruptCheck *ins);
|
||||||
bool visitGuardShape(MGuardShape *ins);
|
bool visitGuardShape(MGuardShape *ins);
|
||||||
|
Loading…
Reference in New Issue
Block a user