Back out 0498e3bb74bd:9011919fcf00 (bug 799818) for build bustage
authorPhil Ringnalda <philringnalda@gmail.com>
Fri, 19 Oct 2012 14:55:53 -0700
changeset 110959 441defeeb6533f18a9eaa3c09ddb5e3747987049
parent 110958 0498e3bb74bdc6aabad86ac10d9c376bdd8a654e
child 110960 ff4af83233dc62a9423bfb0a3042a3c7f3eadd79
child 110961 561d6a3c4d7b0588beb570bc74827e7f8d0976b9
push id93
push usernmatsakis@mozilla.com
push dateWed, 31 Oct 2012 21:26:57 +0000
bugs799818
milestone19.0a1
backs out0498e3bb74bdc6aabad86ac10d9c376bdd8a654e
Back out 0498e3bb74bd:9011919fcf00 (bug 799818) for build bustage on a CLOSED TREE
js/src/ion/CodeGenerator.cpp
js/src/ion/CodeGenerator.h
js/src/ion/IonBuilder.cpp
js/src/ion/LOpcodes.h
js/src/ion/Lowering.cpp
js/src/ion/Lowering.h
js/src/ion/MIR.h
js/src/ion/MOpcodes.h
js/src/ion/TypeOracle.cpp
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,59 +357,16 @@ 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,18 +40,16 @@ 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/IonBuilder.cpp
+++ b/js/src/ion/IonBuilder.cpp
@@ -4413,26 +4413,24 @@ TestSingletonProperty(JSContext *cx, Han
 
     *isKnownConstant = true;
     return true;
 }
 
 static inline bool
 TestSingletonPropertyTypes(JSContext *cx, types::StackTypeSet *types,
                            HandleObject globalObj, HandleId id,
-                           bool *isKnownConstant, bool *testObject,
-                           bool *testString)
+                           bool *isKnownConstant, bool *testObject)
 {
     // As for TestSingletonProperty, but the input is any value in a type set
     // rather than a specific object. If testObject is set then the constant
     // result can only be used after ensuring the input is an object.
 
     *isKnownConstant = false;
     *testObject = false;
-    *testString = false;
 
     if (!types || types->unknownObject())
         return true;
 
     RootedObject singleton(cx, types->getSingleton());
     if (singleton)
         return TestSingletonProperty(cx, singleton, id, isKnownConstant);
 
@@ -4452,25 +4450,16 @@ TestSingletonPropertyTypes(JSContext *cx
         break;
 
       case JSVAL_TYPE_BOOLEAN:
         key = JSProto_Boolean;
         break;
 
       case JSVAL_TYPE_OBJECT:
       case JSVAL_TYPE_UNKNOWN: {
-        if (types->hasType(types::Type::StringType())) {
-            // Do not optimize if the object is either a String or an Object.
-            if (types->maybeObject())
-                return true;
-            key = JSProto_String;
-            *testString = true;
-            break;
-        }
-
         // For property accesses which may be on many objects, we just need to
         // find a prototype common to all the objects; if that prototype
         // has the singleton property, the access will not be on a missing property.
         bool thoughtConstant = true;
         for (unsigned i = 0; i < types->getObjectCount(); i++) {
             types::TypeObject *object = types->getTypeObject(i);
             if (!object) {
                 // Try to get it through the singleton.
@@ -5060,19 +5049,16 @@ IonBuilder::jsop_getelem_string()
 
     MInstruction *idInt32 = MToInt32::New(id);
     current->add(idInt32);
     id = idInt32;
 
     MStringLength *length = MStringLength::New(str);
     current->add(length);
 
-    // This will cause an invalidation of this script once the 'undefined' type
-    // is monitored by the interpreter.
-    JS_ASSERT(oracle->propertyRead(script_, pc)->getKnownTypeTag() == JSVAL_TYPE_STRING);
     id = addBoundsCheck(id, length);
 
     MCharCodeAt *charCode = MCharCodeAt::New(str, id);
     current->add(charCode);
 
     MFromCharCode *result = MFromCharCode::New(charCode);
     current->add(result);
     current->push(result);
@@ -5890,32 +5876,28 @@ IonBuilder::getPropTryConstant(bool *emi
 {
     JS_ASSERT(*emitted == false);
     JSObject *singleton = types ? types->getSingleton() : NULL;
     if (!singleton || barrier)
         return true;
 
     RootedObject global(cx, &script_->global());
 
-    bool isConstant, testObject, testString;
-    if (!TestSingletonPropertyTypes(cx, unaryTypes.inTypes, global, id,
-                                    &isConstant, &testObject, &testString))
+    bool isConstant, testObject;
+    if (!TestSingletonPropertyTypes(cx, unaryTypes.inTypes, global, id, &isConstant, &testObject))
         return false;
 
     if (!isConstant)
         return true;
 
     MDefinition *obj = current->pop();
 
     // Property access is a known constant -- safe to emit.
-	JS_ASSERT(!testString || !testObject);
     if (testObject)
         current->add(MGuardObject::New(obj));
-	else if (testString)
-        current->add(MGuardString::New(obj));
 
     MConstant *known = MConstant::New(ObjectValue(*singleton));
     if (singleton->isFunction()) {
         RootedFunction singletonFunc(cx, singleton->toFunction());
         if (TestAreKnownDOMTypes(cx, unaryTypes.inTypes) &&
             TestShouldDOMCall(cx, unaryTypes.inTypes, singletonFunc))
         {
             FreezeDOMTypes(cx, unaryTypes.inTypes);
--- a/js/src/ion/LOpcodes.h
+++ b/js/src/ion/LOpcodes.h
@@ -15,17 +15,16 @@
     _(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,54 +63,16 @@ 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;
@@ -1714,25 +1676,16 @@ LIRGenerator::visitGuardObject(MGuardObj
 {
     // The type policy does all the work, so at this point the input
     // is guaranteed to be an object.
     JS_ASSERT(ins->input()->type() == MIRType_Object);
     return redefine(ins, ins->input());
 }
 
 bool
-LIRGenerator::visitGuardString(MGuardString *ins)
-{
-    // The type policy does all the work, so at this point the input
-    // is guaranteed to be a string.
-    JS_ASSERT(ins->input()->type() == MIRType_String);
-    return redefine(ins, ins->input());
-}
-
-bool
 LIRGenerator::visitCallGetProperty(MCallGetProperty *ins)
 {
     LCallGetProperty *lir = new LCallGetProperty();
     if (!useBoxAtStart(lir, LCallGetProperty::Value, ins->value()))
         return false;
     return defineVMReturn(lir, ins) && assignSafepoint(lir, ins);
 }
 
--- a/js/src/ion/Lowering.h
+++ b/js/src/ion/Lowering.h
@@ -72,17 +72,16 @@ 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);
@@ -160,17 +159,16 @@ class LIRGenerator : public LIRGenerator
     bool visitClampToUint8(MClampToUint8 *ins);
     bool visitLoadFixedSlot(MLoadFixedSlot *ins);
     bool visitStoreFixedSlot(MStoreFixedSlot *ins);
     bool visitGetPropertyCache(MGetPropertyCache *ins);
     bool visitGetElementCache(MGetElementCache *ins);
     bool visitBindNameCache(MBindNameCache *ins);
     bool visitGuardClass(MGuardClass *ins);
     bool visitGuardObject(MGuardObject *ins);
-    bool visitGuardString(MGuardString *ins);
     bool visitCallGetProperty(MCallGetProperty *ins);
     bool visitDeleteProperty(MDeleteProperty *ins);
     bool visitGetNameCache(MGetNameCache *ins);
     bool visitCallGetElement(MCallGetElement *ins);
     bool visitCallSetElement(MCallSetElement *ins);
     bool visitSetPropertyCache(MSetPropertyCache *ins);
     bool visitCallSetProperty(MCallSetProperty *ins);
     bool visitIteratorStart(MIteratorStart *ins);
--- a/js/src/ion/MIR.h
+++ b/js/src/ion/MIR.h
@@ -690,17 +690,18 @@ class MControlInstruction : public MInst
     virtual void replaceSuccessor(size_t i, MBasicBlock *successor) = 0;
 
     bool isControlInstruction() const {
         return true;
     }
 };
 
 class MTableSwitch
-  : public MControlInstruction
+  : public MControlInstruction,
+    public TableSwitchPolicy
 {
     // 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_;
@@ -794,16 +795,20 @@ 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_;
 
@@ -1496,47 +1501,16 @@ class MGuardObject : public MUnaryInstru
     TypePolicy *typePolicy() {
         return this;
     }
     AliasSet getAliasSet() const {
         return AliasSet::None();
     }
 };
 
-class MGuardString
-  : public MUnaryInstruction,
-    public StringPolicy
-{
-    MGuardString(MDefinition *ins)
-      : MUnaryInstruction(ins)
-    {
-        setGuard();
-        setMovable();
-        setResultType(MIRType_String);
-    }
-
-  public:
-    INSTRUCTION_HEADER(GuardString);
-
-    static MGuardString *New(MDefinition *ins) {
-        return new MGuardString(ins);
-    }
-
-    MDefinition *input() const {
-        return getOperand(0);
-    }
-
-    TypePolicy *typePolicy() {
-        return this;
-    }
-    AliasSet getAliasSet() const {
-        return AliasSet::None();
-    }
-};
-
 // Caller-side allocation of |this| for |new|:
 // Given a prototype operand, construct |this| for JSOP_NEW.
 // For native constructors, returns MagicValue(JS_IS_CONSTRUCTING).
 class MCreateThis
   : public MAryInstruction<2>,
     public MixPolicy<ObjectPolicy<0>, ObjectPolicy<1> >
 {
     // Template for |this|, provided by TI, or NULL.
--- a/js/src/ion/MOpcodes.h
+++ b/js/src/ion/MOpcodes.h
@@ -58,17 +58,16 @@ namespace ion {
     _(Concat)                                                               \
     _(CharCodeAt)                                                           \
     _(FromCharCode)                                                         \
     _(Return)                                                               \
     _(Throw)                                                                \
     _(Box)                                                                  \
     _(Unbox)                                                                \
     _(GuardObject)                                                          \
-    _(GuardString)                                                          \
     _(ToDouble)                                                             \
     _(ToInt32)                                                              \
     _(TruncateToInt32)                                                      \
     _(ToString)                                                             \
     _(NewSlots)                                                             \
     _(NewArray)                                                             \
     _(NewObject)                                                            \
     _(NewCallObject)                                                        \
--- a/js/src/ion/TypeOracle.cpp
+++ b/js/src/ion/TypeOracle.cpp
@@ -352,21 +352,18 @@ TypeInferenceOracle::elementReadIsString
     StackTypeSet *id = script->analysis()->poppedTypes(pc, 0);
 
     if (value->getKnownTypeTag() != JSVAL_TYPE_STRING)
         return false;
 
     if (id->getKnownTypeTag() != JSVAL_TYPE_INT32)
         return false;
 
-    // This function is used for jsop_getelem_string which should return
-    // undefined if this is out-side the string bounds. Currently we just
-    // fallback to a CallGetElement.
-    StackTypeSet *pushed = script->analysis()->pushedTypes(pc, 0);
-    if (pushed->getKnownTypeTag() != JSVAL_TYPE_STRING)
+    types::TypeSet *pushed = script->analysis()->pushedTypes(pc, 0);
+    if (!pushed->hasType(types::Type::StringType()))
         return false;
 
     return true;
 }
 
 bool
 TypeInferenceOracle::elementReadIsPacked(JSScript *script, jsbytecode *pc)
 {
--- a/js/src/ion/TypePolicy.cpp
+++ b/js/src/ion/TypePolicy.cpp
@@ -218,16 +218,38 @@ 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,16 +70,22 @@ 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
 {
-    MTableSwitch *mswitch;
+    LTableSwitch *lswitch;
     BufferOffset off;
     MacroAssembler *masm;
   public:
-    DeferredJumpTable(MTableSwitch *mswitch, BufferOffset off_, MacroAssembler *masm_)
-      : mswitch(mswitch), off(off_), masm(masm_)
+    DeferredJumpTable(LTableSwitch *lswitch, BufferOffset off_, MacroAssembler *masm_)
+      : lswitch(lswitch), off(off_), masm(masm_)
     { }
 
     void copy(IonCode *code, uint8 *ignore__) const {
         void **jumpData = (void **)(((char*)code->raw()) + masm->actualOffset(off).getOffset());
-        int numCases =  mswitch->numCases();
+        int numCases =  lswitch->mir()->numCases();
         // For every case write the pointer to the start in the table
         for (int j = 0; j < numCases; j++) {
-            LBlock *caseblock = mswitch->getCase(numCases - 1 - j)->lir();
+            LBlock *caseblock = lswitch->mir()->getCase(numCases - 1 - j)->lir();
             Label *caseheader = caseblock->label();
 
             uint32 offset = caseheader->offset();
             *jumpData = (void *)(code->raw() + masm->actualOffset(offset));
             jumpData++;
         }
     }
 };
@@ -836,18 +836,17 @@ CodeGeneratorARM::visitMoveGroup(LMoveGr
     MoveEmitter emitter(masm);
     emitter.emit(resolver);
     emitter.finish();
 
     return true;
 }
 
 bool
-CodeGeneratorARM::emitTableSwitchDispatch(MTableSwitch *mir, const Register &index,
-                                          const Register &base)
+CodeGeneratorARM::visitTableSwitch(LTableSwitch *ins)
 {
     // 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
 
@@ -865,26 +864,39 @@ CodeGeneratorARM::emitTableSwitchDispatc
     // 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.
-    Label *defaultcase = mir->getDefault()->lir()->label();
+    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();
+    }
 
     int32 cases = mir->numCases();
+    Register tempReg = ToRegister(temp);
     // Lower value with low value
-    masm.ma_sub(index, Imm32(mir->low()), index, SetCond);
-    masm.ma_rsb(index, Imm32(cases - 1), index, SetCond, Assembler::Unsigned);
+    masm.ma_sub(tempReg, Imm32(mir->low()), tempReg, SetCond);
+    masm.ma_rsb(tempReg, Imm32(cases - 1), tempReg, SetCond, Assembler::Unsigned);
     AutoForbidPools afp(&masm);
-    masm.ma_ldr(DTRAddr(pc, DtrRegImmShift(index, LSL, 2)), pc, Offset, Assembler::Unsigned);
+    masm.ma_ldr(DTRAddr(pc, DtrRegImmShift(tempReg, LSL, 2)), pc, Offset, Assembler::Unsigned);
     masm.ma_b(defaultcase);
-    DeferredJumpTable *d = new DeferredJumpTable(mir, masm.nextOffset(), &masm);
+    DeferredJumpTable *d = new DeferredJumpTable(ins, 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,18 +59,16 @@ 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);
@@ -96,16 +94,17 @@ 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,51 +195,16 @@ 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,27 +276,44 @@ 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);
 }
 
-LTableSwitch *
-LIRGeneratorARM::newLTableSwitch(const LAllocation &in, const LDefinition &inputCopy,
-                                       MTableSwitch *tableswitch)
+bool
+LIRGeneratorARM::visitTableSwitch(MTableSwitch *tableswitch)
 {
-    return new LTableSwitch(in, inputCopy, 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()));
+
+    // 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()));
 
-LTableSwitchV *
-LIRGeneratorARM::newLTableSwitchV(MTableSwitch *tableswitch)
-{
-    return new LTableSwitchV(temp(), tempFloat(), tableswitch);
+    // 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
 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,20 +43,17 @@ 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);
-
-    LTableSwitch *newLTableSwitch(const LAllocation &in, const LDefinition &inputCopy,
-                                  MTableSwitch *ins);
-    LTableSwitchV *newLTableSwitchV(MTableSwitch *ins);
+    bool visitTableSwitch(MTableSwitch *tableswitch);
 
   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,22 +36,16 @@ 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
 {
-    MTableSwitch *mswitch;
+    LTableSwitch *lswitch;
 
   public:
-    DeferredJumpTable(MTableSwitch *mswitch)
-      : mswitch(mswitch)
+    DeferredJumpTable(LTableSwitch *lswitch)
+      : lswitch(lswitch)
     { }
-
+    
     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 < mswitch->numCases(); j++) {
-            LBlock *caseblock = mswitch->getCase(j)->lir();
+        for (size_t j = 0; j < lswitch->mir()->numCases(); j++) { 
+            LBlock *caseblock = lswitch->mir()->getCase(j)->lir();
             Label *caseheader = caseblock->label();
 
             uint32 offset = caseheader->offset();
             *jumpData = (void *)(code->raw() + offset);
             jumpData++;
         }
     }
 };
@@ -928,38 +928,50 @@ CodeGeneratorX86Shared::visitMoveGroup(L
     MoveEmitter emitter(masm);
     emitter.emit(resolver);
     emitter.finish();
 
     return true;
 }
 
 bool
-CodeGeneratorX86Shared::emitTableSwitchDispatch(MTableSwitch *mir, const Register &index,
-                                                const Register &base)
+CodeGeneratorX86Shared::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();
+    }
 
     // Lower value with low value
     if (mir->low() != 0)
-        masm.subl(Imm32(mir->low()), index);
+        masm.subl(Imm32(mir->low()), ToRegister(temp));
 
     // Jump to default case if input is out of range
     int32 cases = mir->numCases();
-    masm.cmpl(index, Imm32(cases));
+    masm.cmpl(ToRegister(temp), Imm32(cases));
     masm.j(AssemblerX86Shared::AboveOrEqual, defaultcase);
 
     // Create a JumpTable that during linking will get written.
-    DeferredJumpTable *d = new DeferredJumpTable(mir);
+    DeferredJumpTable *d = new DeferredJumpTable(ins);
     if (!masm.addDeferredData(d, (1 << ScalePointer) * cases))
         return false;
 
     // Compute the position where a pointer to the right case stands.
-    masm.mov(d->label(), base);
-    Operand pointer = Operand(base, index, ScalePointer);
+    const LAllocation *base = ins->tempPointer();
+    masm.mov(d->label(), ToRegister(base));
+    Operand pointer = Operand(ToRegister(base), ToRegister(temp), 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,18 +75,16 @@ 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);
@@ -108,16 +106,17 @@ 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,48 +112,16 @@ 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,27 +7,44 @@
 
 #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;
 
-LTableSwitch *
-LIRGeneratorX86Shared::newLTableSwitch(const LAllocation &in, const LDefinition &inputCopy,
-                                       MTableSwitch *tableswitch)
+bool
+LIRGeneratorX86Shared::visitTableSwitch(MTableSwitch *tableswitch)
 {
-    return new LTableSwitch(in, inputCopy, temp(), 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()));
+
+    // 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()));
 
-LTableSwitchV *
-LIRGeneratorX86Shared::newLTableSwitchV(MTableSwitch *tableswitch)
-{
-    return new LTableSwitchV(temp(), tempFloat(), temp(), tableswitch);
+    // 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
 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,20 +15,17 @@ namespace ion {
 
 class LIRGeneratorX86Shared : public LIRGeneratorShared
 {
   protected:
     LIRGeneratorX86Shared(MIRGenerator *gen, MIRGraph &graph, LIRGraph &lirGraph)
       : LIRGeneratorShared(gen, graph, lirGraph)
     {}
 
-    LTableSwitch *newLTableSwitch(const LAllocation &in, const LDefinition &inputCopy,
-                                  MTableSwitch *ins);
-    LTableSwitchV *newLTableSwitchV(MTableSwitch *ins);
-
+    bool visitTableSwitch(MTableSwitch *tableswitch);
     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);
 };