Back out 0498e3bb74bd:9011919fcf00 (bug 799818) for build bustage
authorPhil Ringnalda <philringnalda@gmail.com>
Fri, 19 Oct 2012 14:55:53 -0700
changeset 110827 441defeeb6533f18a9eaa3c09ddb5e3747987049
parent 110826 0498e3bb74bdc6aabad86ac10d9c376bdd8a654e
child 110828 ff4af83233dc62a9423bfb0a3042a3c7f3eadd79
child 110829 561d6a3c4d7b0588beb570bc74827e7f8d0976b9
push id23716
push userryanvm@gmail.com
push dateSat, 20 Oct 2012 01:43:16 +0000
treeherdermozilla-central@ff4af83233dc [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs799818
milestone19.0a1
backs out0498e3bb74bdc6aabad86ac10d9c376bdd8a654e
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
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);
 };