Bug 799818 part 2 - Handle unknown double as input of a table switch. r=djvj,h4writer
authorNicolas B. Pierron <nicolas.b.pierron@mozilla.com>
Fri, 19 Oct 2012 14:30:38 -0700
changeset 110957 31ab0fe92304517353cb63626de2c855b14befda
parent 110956 9011919fcf00bebcefb67740c431e9b21fd6a914
child 110958 0498e3bb74bdc6aabad86ac10d9c376bdd8a654e
push id93
push usernmatsakis@mozilla.com
push dateWed, 31 Oct 2012 21:26:57 +0000
reviewersdjvj, h4writer
bugs799818
milestone19.0a1
Bug 799818 part 2 - Handle unknown double as input of a table switch. r=djvj,h4writer
js/src/ion/CodeGenerator.cpp
js/src/ion/CodeGenerator.h
js/src/ion/LOpcodes.h
js/src/ion/Lowering.cpp
js/src/ion/Lowering.h
js/src/ion/MIR.h
js/src/ion/TypePolicy.cpp
js/src/ion/TypePolicy.h
js/src/ion/arm/CodeGenerator-arm.cpp
js/src/ion/arm/CodeGenerator-arm.h
js/src/ion/arm/LIR-arm.h
js/src/ion/arm/Lowering-arm.cpp
js/src/ion/arm/Lowering-arm.h
js/src/ion/shared/CodeGenerator-shared-inl.h
js/src/ion/shared/CodeGenerator-x86-shared.cpp
js/src/ion/shared/CodeGenerator-x86-shared.h
js/src/ion/shared/LIR-x86-shared.h
js/src/ion/shared/Lowering-x86-shared.cpp
js/src/ion/shared/Lowering-x86-shared.h
--- a/js/src/ion/CodeGenerator.cpp
+++ b/js/src/ion/CodeGenerator.cpp
@@ -357,16 +357,59 @@ CodeGenerator::visitGoto(LGoto *lir)
     if (isNextBlock(target))
         return true;
 
     masm.jump(target->label());
     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
 CodeGenerator::visitParameter(LParameter *lir)
 {
     return true;
 }
 
 bool
 CodeGenerator::visitCallee(LCallee *lir)
 {
--- a/js/src/ion/CodeGenerator.h
+++ b/js/src/ion/CodeGenerator.h
@@ -40,16 +40,18 @@ class CodeGenerator : public CodeGenerat
 
   public:
     bool generate();
 
     bool visitLabel(LLabel *lir);
     bool visitNop(LNop *lir);
     bool visitOsiPoint(LOsiPoint *lir);
     bool visitGoto(LGoto *lir);
+    bool visitTableSwitch(LTableSwitch *ins);
+    bool visitTableSwitchV(LTableSwitchV *ins);
     bool visitParameter(LParameter *lir);
     bool visitCallee(LCallee *lir);
     bool visitStart(LStart *lir);
     bool visitReturn(LReturn *ret);
     bool visitDefVar(LDefVar *lir);
     bool visitOsrEntry(LOsrEntry *lir);
     bool visitOsrScopeChain(LOsrScopeChain *lir);
     bool visitStackArgT(LStackArgT *lir);
--- a/js/src/ion/LOpcodes.h
+++ b/js/src/ion/LOpcodes.h
@@ -15,16 +15,17 @@
     _(MoveGroup)                    \
     _(Integer)                      \
     _(Pointer)                      \
     _(Double)                       \
     _(Value)                        \
     _(Parameter)                    \
     _(Callee)                       \
     _(TableSwitch)                  \
+    _(TableSwitchV)                 \
     _(Goto)                         \
     _(NewArray)                     \
     _(NewObject)                    \
     _(NewSlots)                     \
     _(NewCallObject)                \
     _(NewStringObject)              \
     _(InitProp)                     \
     _(CheckOverRecursed)            \
--- a/js/src/ion/Lowering.cpp
+++ b/js/src/ion/Lowering.cpp
@@ -63,16 +63,54 @@ LIRGenerator::visitCallee(MCallee *calle
 
 bool
 LIRGenerator::visitGoto(MGoto *ins)
 {
     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
 LIRGenerator::visitCheckOverRecursed(MCheckOverRecursed *ins)
 {
     LCheckOverRecursed *lir = new LCheckOverRecursed(temp());
 
     if (!add(lir))
         return false;
     if (!assignSafepoint(lir, ins))
         return false;
--- a/js/src/ion/Lowering.h
+++ b/js/src/ion/Lowering.h
@@ -72,16 +72,17 @@ class LIRGenerator : public LIRGenerator
     bool visitInstruction(MInstruction *ins);
     bool visitBlock(MBasicBlock *block);
 
     // Visitor hooks are explicit, to give CPU-specific versions a chance to
     // intercept without a bunch of explicit gunk in the .cpp.
     bool visitParameter(MParameter *param);
     bool visitCallee(MCallee *callee);
     bool visitGoto(MGoto *ins);
+    bool visitTableSwitch(MTableSwitch *tableswitch);
     bool visitNewSlots(MNewSlots *ins);
     bool visitNewArray(MNewArray *ins);
     bool visitNewObject(MNewObject *ins);
     bool visitNewCallObject(MNewCallObject *ins);
     bool visitNewStringObject(MNewStringObject *ins);
     bool visitInitProp(MInitProp *ins);
     bool visitCheckOverRecursed(MCheckOverRecursed *ins);
     bool visitDefVar(MDefVar *ins);
--- a/js/src/ion/MIR.h
+++ b/js/src/ion/MIR.h
@@ -690,18 +690,17 @@ class MControlInstruction : public MInst
     virtual void replaceSuccessor(size_t i, MBasicBlock *successor) = 0;
 
     bool isControlInstruction() const {
         return true;
     }
 };
 
 class MTableSwitch
-  : public MControlInstruction,
-    public TableSwitchPolicy
+  : public MControlInstruction
 {
     // The successors of the tableswitch
     // - First successor = the default case
     // - Successor 2 and higher = the cases sorted on case index.
     Vector<MBasicBlock*, 0, IonAllocPolicy> successors_;
 
     // Contains the blocks/cases that still need to get build
     Vector<MBasicBlock*, 0, IonAllocPolicy> blocks_;
@@ -795,20 +794,16 @@ class MTableSwitch
     MDefinition *getOperand(size_t index) const {
         JS_ASSERT(index == 0);
         return operand_;
     }
 
     size_t numOperands() const {
         return 1;
     }
-
-    TypePolicy *typePolicy() {
-        return this;
-    }
 };
 
 template <size_t Arity, size_t Successors>
 class MAryControlInstruction : public MControlInstruction
 {
     FixedArityList<MDefinition *, Arity> operands_;
     FixedArityList<MBasicBlock *, Successors> successors_;
 
--- a/js/src/ion/TypePolicy.cpp
+++ b/js/src/ion/TypePolicy.cpp
@@ -218,38 +218,16 @@ BitwisePolicy::adjustInputs(MInstruction
         ins->block()->insertBefore(ins, replace);
         ins->replaceOperand(i, replace);
     }
 
     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
 PowPolicy::adjustInputs(MInstruction *ins)
 {
     JS_ASSERT(specialization_ == MIRType_Int32 || specialization_ == MIRType_Double);
 
     // Input must be a double.
     if (!DoublePolicy<0>::staticAdjustInputs(ins))
         return false;
 
--- a/js/src/ion/TypePolicy.h
+++ b/js/src/ion/TypePolicy.h
@@ -70,22 +70,16 @@ class BitwisePolicy : public BoxInputsPo
   public:
     bool adjustInputs(MInstruction *def);
 
     MIRType specialization() const {
         return specialization_;
     }
 };
 
-class TableSwitchPolicy : public BoxInputsPolicy
-{
-  public:
-    bool adjustInputs(MInstruction *def);
-};
-
 class ComparePolicy : public BoxInputsPolicy
 {
   protected:
     MIRType specialization_;
 
   public:
     ComparePolicy()
       : specialization_(MIRType_None)
--- a/js/src/ion/arm/CodeGenerator-arm.cpp
+++ b/js/src/ion/arm/CodeGenerator-arm.cpp
@@ -21,30 +21,30 @@
 
 #include "jsscopeinlines.h"
 
 using namespace js;
 using namespace js::ion;
 
 class DeferredJumpTable : public DeferredData
 {
-    LTableSwitch *lswitch;
+    MTableSwitch *mswitch;
     BufferOffset off;
     MacroAssembler *masm;
   public:
-    DeferredJumpTable(LTableSwitch *lswitch, BufferOffset off_, MacroAssembler *masm_)
-      : lswitch(lswitch), off(off_), masm(masm_)
+    DeferredJumpTable(MTableSwitch *mswitch, BufferOffset off_, MacroAssembler *masm_)
+      : mswitch(mswitch), off(off_), masm(masm_)
     { }
 
     void copy(IonCode *code, uint8 *ignore__) const {
         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 (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();
 
             uint32 offset = caseheader->offset();
             *jumpData = (void *)(code->raw() + masm->actualOffset(offset));
             jumpData++;
         }
     }
 };
@@ -836,17 +836,18 @@ CodeGeneratorARM::visitMoveGroup(LMoveGr
     MoveEmitter emitter(masm);
     emitter.emit(resolver);
     emitter.finish();
 
     return true;
 }
 
 bool
-CodeGeneratorARM::visitTableSwitch(LTableSwitch *ins)
+CodeGeneratorARM::emitTableSwitchDispatch(MTableSwitch *mir, const Register &index,
+                                          const Register &base)
 {
     // the code generated by this is utter hax.
     // the end result looks something like:
     // SUBS index, input, #base
     // RSBSPL index, index, #max
     // LDRPL pc, pc, index lsl 2
     // B default
 
@@ -864,39 +865,26 @@ CodeGeneratorARM::visitTableSwitch(LTabl
     // the address size) into the pc, which branches to the correct case.
     // NOTE: when we go to read the pc, the value that we get back is the pc of
     // the current instruction *PLUS 8*.  This means that ldr foo, [pc, +0]
     // reads $pc+8.  In other words, there is an empty word after the branch into
     // the switch table before the table actually starts.  Since the only other
     // 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
     // we don't attempt to execute the address table.
-    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();
-    }
+    Label *defaultcase = mir->getDefault()->lir()->label();
 
     int32 cases = mir->numCases();
-    Register tempReg = ToRegister(temp);
     // Lower value with low value
-    masm.ma_sub(tempReg, Imm32(mir->low()), tempReg, SetCond);
-    masm.ma_rsb(tempReg, Imm32(cases - 1), tempReg, SetCond, Assembler::Unsigned);
+    masm.ma_sub(index, Imm32(mir->low()), index, SetCond);
+    masm.ma_rsb(index, Imm32(cases - 1), index, SetCond, Assembler::Unsigned);
     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);
-    DeferredJumpTable *d = new DeferredJumpTable(ins, masm.nextOffset(), &masm);
+    DeferredJumpTable *d = new DeferredJumpTable(mir, masm.nextOffset(), &masm);
     masm.as_jumpPool(cases);
 
     if (!masm.addDeferredData(d, 0))
         return false;
 
     return true;
 }
 
--- a/js/src/ion/arm/CodeGenerator-arm.h
+++ b/js/src/ion/arm/CodeGenerator-arm.h
@@ -59,16 +59,18 @@ class CodeGeneratorARM : public CodeGene
 
     // Emits a conditional set.
     void emitSet(Assembler::Condition cond, const Register &dest);
 
     // Emits a branch that directs control flow to the true block if |cond| is
     // true, and the false block if |cond| is false.
     void emitBranch(Assembler::Condition cond, MBasicBlock *ifTrue, MBasicBlock *ifFalse);
 
+    bool emitTableSwitchDispatch(MTableSwitch *mir, const Register &index, const Register &base);
+
   public:
     // Instruction visitors.
     virtual bool visitMinMaxD(LMinMaxD *ins);
     virtual bool visitAbsD(LAbsD *ins);
     virtual bool visitSqrtD(LSqrtD *ins);
     virtual bool visitAddI(LAddI *ins);
     virtual bool visitSubI(LSubI *ins);
     virtual bool visitBitNotI(LBitNotI *ins);
@@ -94,17 +96,16 @@ class CodeGeneratorARM : public CodeGene
     virtual bool visitCompareB(LCompareB *lir);
     virtual bool visitCompareBAndBranch(LCompareBAndBranch *lir);
     virtual bool visitNotI(LNotI *ins);
     virtual bool visitNotD(LNotD *ins);
 
     virtual bool visitMathD(LMathD *math);
     virtual bool visitFloor(LFloor *lir);
     virtual bool visitRound(LRound *lir);
-    virtual bool visitTableSwitch(LTableSwitch *ins);
     virtual bool visitTruncateDToInt32(LTruncateDToInt32 *ins);
 
     // Out of line visitors.
     bool visitOutOfLineBailout(OutOfLineBailout *ool);
 
   protected:
     ValueOperand ToValue(LInstruction *ins, size_t pos);
     ValueOperand ToOutValue(LInstruction *ins);
--- a/js/src/ion/arm/LIR-arm.h
+++ b/js/src/ion/arm/LIR-arm.h
@@ -195,16 +195,51 @@ class LTableSwitch : public LInstruction
     }
 
     const LAllocation *index() {
         return getOperand(0);
     }
     const LAllocation *tempInt() {
         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.
 class LGuardShape : public LInstructionHelper<0, 1, 1>
 {
   public:
     LIR_HEADER(GuardShape);
 
--- a/js/src/ion/arm/Lowering-arm.cpp
+++ b/js/src/ion/arm/Lowering-arm.cpp
@@ -276,44 +276,27 @@ bool
 LIRGeneratorARM::visitPowHalf(MPowHalf *ins)
 {
     MDefinition *input = ins->input();
     JS_ASSERT(input->type() == MIRType_Double);
     LPowHalfD *lir = new LPowHalfD(useRegisterAtStart(input));
     return defineReuseInput(lir, ins, 0);
 }
 
-bool
-LIRGeneratorARM::visitTableSwitch(MTableSwitch *tableswitch)
+LTableSwitch *
+LIRGeneratorARM::newLTableSwitch(const LAllocation &in, const LDefinition &inputCopy,
+                                       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()));
+    return new LTableSwitch(in, inputCopy, tableswitch);
+}
 
-    // 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));
+LTableSwitchV *
+LIRGeneratorARM::newLTableSwitchV(MTableSwitch *tableswitch)
+{
+    return new LTableSwitchV(temp(), tempFloat(), tableswitch);
 }
 
 bool
 LIRGeneratorARM::visitGuardShape(MGuardShape *ins)
 {
     LDefinition tempObj = temp(LDefinition::OBJECT);
     LGuardShape *guard = new LGuardShape(useRegister(ins->obj()), tempObj);
     return assignSnapshot(guard, ins->bailoutKind()) && add(guard, ins);
--- a/js/src/ion/arm/Lowering-arm.h
+++ b/js/src/ion/arm/Lowering-arm.h
@@ -43,17 +43,20 @@ class LIRGeneratorARM : public LIRGenera
     bool lowerForFPU(LInstructionHelper<1, 2, 0> *ins, MDefinition *mir,
                      MDefinition *lhs, MDefinition *rhs);
 
     bool lowerConstantDouble(double d, MInstruction *ins);
     bool lowerDivI(MDiv *div);
     bool lowerModI(MMod *mod);
     bool lowerMulI(MMul *mul, MDefinition *lhs, MDefinition *rhs);
     bool visitPowHalf(MPowHalf *ins);
-    bool visitTableSwitch(MTableSwitch *tableswitch);
+
+    LTableSwitch *newLTableSwitch(const LAllocation &in, const LDefinition &inputCopy,
+                                  MTableSwitch *ins);
+    LTableSwitchV *newLTableSwitchV(MTableSwitch *ins);
 
   public:
     bool visitConstant(MConstant *ins);
     bool visitBox(MBox *box);
     bool visitUnbox(MUnbox *unbox);
     bool visitReturn(MReturn *ret);
     bool lowerPhi(MPhi *phi);
     bool visitGuardShape(MGuardShape *ins);
--- a/js/src/ion/shared/CodeGenerator-shared-inl.h
+++ b/js/src/ion/shared/CodeGenerator-shared-inl.h
@@ -36,16 +36,22 @@ ToRegister(const LAllocation *a)
 }
 
 static inline Register
 ToRegister(const LDefinition *def)
 {
     return ToRegister(*def->output());
 }
 
+static inline Register
+ToRegisterOrInvalid(const LAllocation *a)
+{
+    return a ? ToRegister(*a) : InvalidReg;
+}
+
 static inline FloatRegister
 ToFloatRegister(const LAllocation &a)
 {
     JS_ASSERT(a.isFloatReg());
     return a.toFloatReg()->reg();
 }
 
 static inline FloatRegister
--- a/js/src/ion/shared/CodeGenerator-x86-shared.cpp
+++ b/js/src/ion/shared/CodeGenerator-x86-shared.cpp
@@ -17,29 +17,29 @@
 using namespace js;
 using namespace js::ion;
 
 namespace js {
 namespace ion {
 
 class DeferredJumpTable : public DeferredData
 {
-    LTableSwitch *lswitch;
+    MTableSwitch *mswitch;
 
   public:
-    DeferredJumpTable(LTableSwitch *lswitch)
-      : lswitch(lswitch)
+    DeferredJumpTable(MTableSwitch *mswitch)
+      : mswitch(mswitch)
     { }
-    
+
     void copy(IonCode *code, uint8 *buffer) const {
         void **jumpData = (void **)buffer;
 
         // For every case write the pointer to the start in the table
-        for (size_t j = 0; j < lswitch->mir()->numCases(); j++) { 
-            LBlock *caseblock = lswitch->mir()->getCase(j)->lir();
+        for (size_t j = 0; j < mswitch->numCases(); j++) {
+            LBlock *caseblock = mswitch->getCase(j)->lir();
             Label *caseheader = caseblock->label();
 
             uint32 offset = caseheader->offset();
             *jumpData = (void *)(code->raw() + offset);
             jumpData++;
         }
     }
 };
@@ -928,50 +928,38 @@ CodeGeneratorX86Shared::visitMoveGroup(L
     MoveEmitter emitter(masm);
     emitter.emit(resolver);
     emitter.finish();
 
     return true;
 }
 
 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();
-    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
     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
     int32 cases = mir->numCases();
-    masm.cmpl(ToRegister(temp), Imm32(cases));
+    masm.cmpl(index, Imm32(cases));
     masm.j(AssemblerX86Shared::AboveOrEqual, defaultcase);
 
     // 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))
         return false;
 
     // Compute the position where a pointer to the right case stands.
-    const LAllocation *base = ins->tempPointer();
-    masm.mov(d->label(), ToRegister(base));
-    Operand pointer = Operand(ToRegister(base), ToRegister(temp), ScalePointer);
+    masm.mov(d->label(), base);
+    Operand pointer = Operand(base, index, ScalePointer);
 
     // Jump to the right case
     masm.jmp(pointer);
 
     return true;
 }
 
 bool
--- a/js/src/ion/shared/CodeGenerator-x86-shared.h
+++ b/js/src/ion/shared/CodeGenerator-x86-shared.h
@@ -75,16 +75,18 @@ class CodeGeneratorX86Shared : public Co
     void emitSet(Assembler::DoubleCondition cond, const Register &dest);
 
     // Emits a branch that directs control flow to the true block if |cond| is
     // true, and the false block if |cond| is false.
     void emitBranch(Assembler::Condition cond, MBasicBlock *ifTrue, MBasicBlock *ifFalse,
                     NaNCond ifNaN = NaN_Unexpected);
     void emitBranch(Assembler::DoubleCondition cond, MBasicBlock *ifTrue, MBasicBlock *ifFalse);
 
+    bool emitTableSwitchDispatch(MTableSwitch *mir, const Register &index, const Register &base);
+
   public:
     CodeGeneratorX86Shared(MIRGenerator *gen, LIRGraph &graph);
 
   public:
     // Instruction visitors.
     virtual bool visitMinMaxD(LMinMaxD *ins);
     virtual bool visitAbsD(LAbsD *ins);
     virtual bool visitSqrtD(LSqrtD *ins);
@@ -106,17 +108,16 @@ class CodeGeneratorX86Shared : public Co
     virtual bool visitCompareAndBranch(LCompareAndBranch *comp);
     virtual bool visitCompareD(LCompareD *comp);
     virtual bool visitCompareDAndBranch(LCompareDAndBranch *comp);
     virtual bool visitNotI(LNotI *comp);
     virtual bool visitNotD(LNotD *comp);
     virtual bool visitMathD(LMathD *math);
     virtual bool visitFloor(LFloor *lir);
     virtual bool visitRound(LRound *lir);
-    virtual bool visitTableSwitch(LTableSwitch *ins);
     virtual bool visitGuardShape(LGuardShape *guard);
     virtual bool visitGuardClass(LGuardClass *guard);
     virtual bool visitTruncateDToInt32(LTruncateDToInt32 *ins);
 
     // Out of line visitors.
     bool visitOutOfLineBailout(OutOfLineBailout *ool);
     bool visitMulNegativeZeroCheck(MulNegativeZeroCheck *ool);
     bool visitOutOfLineTruncate(OutOfLineTruncate *ool);
--- a/js/src/ion/shared/LIR-x86-shared.h
+++ b/js/src/ion/shared/LIR-x86-shared.h
@@ -112,16 +112,48 @@ class LTableSwitch : public LInstruction
     const LAllocation *tempInt() {
         return getTemp(0)->output();
     }
     const LAllocation *tempPointer() {
         return getTemp(1)->output();
     }
 };
 
+// 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.
 class LGuardShape : public LInstructionHelper<0, 1, 0>
 {
   public:
     LIR_HEADER(GuardShape);
 
     LGuardShape(const LAllocation &in) {
         setOperand(0, in);
--- a/js/src/ion/shared/Lowering-x86-shared.cpp
+++ b/js/src/ion/shared/Lowering-x86-shared.cpp
@@ -7,44 +7,27 @@
 
 #include "ion/MIR.h"
 #include "ion/Lowering.h"
 #include "ion/shared/Lowering-x86-shared.h"
 #include "ion/shared/Lowering-shared-inl.h"
 using namespace js;
 using namespace js::ion;
 
-bool
-LIRGeneratorX86Shared::visitTableSwitch(MTableSwitch *tableswitch)
+LTableSwitch *
+LIRGeneratorX86Shared::newLTableSwitch(const LAllocation &in, const LDefinition &inputCopy,
+                                       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()));
+    return new LTableSwitch(in, inputCopy, temp(), tableswitch);
+}
 
-    // 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));
+LTableSwitchV *
+LIRGeneratorX86Shared::newLTableSwitchV(MTableSwitch *tableswitch)
+{
+    return new LTableSwitchV(temp(), tempFloat(), temp(), tableswitch);
 }
 
 bool
 LIRGeneratorX86Shared::visitRecompileCheck(MRecompileCheck *ins)
 {
     LRecompileCheck *lir = new LRecompileCheck();
     return assignSnapshot(lir, Bailout_RecompileCheck) && add(lir, ins);
 }
--- a/js/src/ion/shared/Lowering-x86-shared.h
+++ b/js/src/ion/shared/Lowering-x86-shared.h
@@ -15,17 +15,20 @@ namespace ion {
 
 class LIRGeneratorX86Shared : public LIRGeneratorShared
 {
   protected:
     LIRGeneratorX86Shared(MIRGenerator *gen, MIRGraph &graph, LIRGraph &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 visitInterruptCheck(MInterruptCheck *ins);
     bool visitGuardShape(MGuardShape *ins);
     bool visitPowHalf(MPowHalf *ins);
     bool lowerMulI(MMul *mul, MDefinition *lhs, MDefinition *rhs);
     bool lowerModI(MMod *mod);
     bool lowerUrshD(MUrsh *mir);
 };