Bug 1249960 - Rename Int32Key to RegisterOrInt32Constant, branchKey to branch32, storeKey to store32, bumpKey to inc32 and dec32. r=nbp
authorTooru Fujisawa <arai_a@mac.com>
Sat, 05 Mar 2016 07:41:54 +0900
changeset 323168 c04247de9a256823e6f69b604d9b68667cfb4416
parent 323167 5a0c251cdf000a15492e021c75e8aac778f54648
child 323169 c9435de8c24caf7d7c1f28762021983bcc334e42
push id5913
push userjlund@mozilla.com
push dateMon, 25 Apr 2016 16:57:49 +0000
treeherdermozilla-beta@dcaf0a6fa115 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersnbp
bugs1249960
milestone47.0a1
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
Bug 1249960 - Rename Int32Key to RegisterOrInt32Constant, branchKey to branch32, storeKey to store32, bumpKey to inc32 and dec32. r=nbp
js/src/jit/BaselineIC.cpp
js/src/jit/CodeGenerator.cpp
js/src/jit/IonCaches.cpp
js/src/jit/MacroAssembler-inl.h
js/src/jit/MacroAssembler.cpp
js/src/jit/MacroAssembler.h
js/src/jit/RegisterSets.h
js/src/jit/shared/CodeGenerator-shared-inl.h
--- a/js/src/jit/BaselineIC.cpp
+++ b/js/src/jit/BaselineIC.cpp
@@ -3222,17 +3222,17 @@ ICSetElemDenseOrUnboxedArrayAddCompiler:
 
         // Bounds check (key == initLength)
         Address initLengthAddr(obj, UnboxedArrayObject::offsetOfCapacityIndexAndInitializedLength());
         masm.load32(initLengthAddr, scratchReg);
         masm.and32(Imm32(UnboxedArrayObject::InitializedLengthMask), scratchReg);
         masm.branch32(Assembler::NotEqual, scratchReg, key, &failure);
 
         // Capacity check.
-        masm.checkUnboxedArrayCapacity(obj, Int32Key(key), scratchReg, &failure);
+        masm.checkUnboxedArrayCapacity(obj, RegisterOrInt32Constant(key), scratchReg, &failure);
 
         // Load obj->elements.
         masm.loadPtr(Address(obj, UnboxedArrayObject::offsetOfElements()), scratchReg);
 
         // Write the value first, since this can fail. No need for pre-barrier
         // since we're not overwriting an old value.
         masm.Push(R0);
         Address valueAddr(masm.getStackPointer(), ICStackValueOffset + sizeof(Value));
--- a/js/src/jit/CodeGenerator.cpp
+++ b/js/src/jit/CodeGenerator.cpp
@@ -5642,22 +5642,22 @@ CodeGenerator::visitArrayLength(LArrayLe
     Address length(ToRegister(lir->elements()), ObjectElements::offsetOfLength());
     masm.load32(length, ToRegister(lir->output()));
 }
 
 void
 CodeGenerator::visitSetArrayLength(LSetArrayLength* lir)
 {
     Address length(ToRegister(lir->elements()), ObjectElements::offsetOfLength());
-    Int32Key newLength = ToInt32Key(lir->index());
-
-    masm.bumpKey(&newLength, 1);
-    masm.storeKey(newLength, length);
+    RegisterOrInt32Constant newLength = ToRegisterOrInt32Constant(lir->index());
+
+    masm.inc32(&newLength);
+    masm.store32(newLength, length);
     // Restore register value if it is used/captured after.
-    masm.bumpKey(&newLength, -1);
+    masm.dec32(&newLength);
 }
 
 void
 CodeGenerator::visitTypedArrayLength(LTypedArrayLength* lir)
 {
     Register obj = ToRegister(lir->object());
     Register out = ToRegister(lir->output());
     masm.unboxInt32(Address(obj, TypedArrayObject::lengthOffset()), out);
@@ -6982,22 +6982,22 @@ CodeGenerator::visitInitializedLength(LI
     Address initLength(ToRegister(lir->elements()), ObjectElements::offsetOfInitializedLength());
     masm.load32(initLength, ToRegister(lir->output()));
 }
 
 void
 CodeGenerator::visitSetInitializedLength(LSetInitializedLength* lir)
 {
     Address initLength(ToRegister(lir->elements()), ObjectElements::offsetOfInitializedLength());
-    Int32Key index = ToInt32Key(lir->index());
-
-    masm.bumpKey(&index, 1);
-    masm.storeKey(index, initLength);
+    RegisterOrInt32Constant index = ToRegisterOrInt32Constant(lir->index());
+
+    masm.inc32(&index);
+    masm.store32(index, initLength);
     // Restore register value if it is used/captured after.
-    masm.bumpKey(&index, -1);
+    masm.dec32(&index);
 }
 
 void
 CodeGenerator::visitUnboxedArrayLength(LUnboxedArrayLength* lir)
 {
     Register obj = ToRegister(lir->object());
     Register result = ToRegister(lir->output());
     masm.load32(Address(obj, UnboxedArrayObject::offsetOfLength()), result);
@@ -7018,17 +7018,17 @@ CodeGenerator::visitIncrementUnboxedArra
     Register obj = ToRegister(lir->object());
     masm.add32(Imm32(1), Address(obj, UnboxedArrayObject::offsetOfCapacityIndexAndInitializedLength()));
 }
 
 void
 CodeGenerator::visitSetUnboxedArrayInitializedLength(LSetUnboxedArrayInitializedLength* lir)
 {
     Register obj = ToRegister(lir->object());
-    Int32Key key = ToInt32Key(lir->length());
+    RegisterOrInt32Constant key = ToRegisterOrInt32Constant(lir->length());
     Register temp = ToRegister(lir->temp());
 
     Address initLengthAddr(obj, UnboxedArrayObject::offsetOfCapacityIndexAndInitializedLength());
     masm.load32(initLengthAddr, temp);
     masm.and32(Imm32(UnboxedArrayObject::CapacityMask), temp);
 
     if (key.isRegister())
         masm.or32(key.reg(), temp);
@@ -7311,34 +7311,35 @@ void
 CodeGenerator::visitStoreElementHoleT(LStoreElementHoleT* lir)
 {
     OutOfLineStoreElementHole* ool = new(alloc()) OutOfLineStoreElementHole(lir);
     addOutOfLineCode(ool, lir->mir());
 
     Register obj = ToRegister(lir->object());
     Register elements = ToRegister(lir->elements());
     const LAllocation* index = lir->index();
+    RegisterOrInt32Constant key = ToRegisterOrInt32Constant(index);
 
     JSValueType unboxedType = lir->mir()->unboxedType();
     if (unboxedType == JSVAL_TYPE_MAGIC) {
         Address initLength(elements, ObjectElements::offsetOfInitializedLength());
-        masm.branchKey(Assembler::BelowOrEqual, initLength, ToInt32Key(index), ool->entry());
+        masm.branch32(Assembler::BelowOrEqual, initLength, key, ool->entry());
 
         if (lir->mir()->needsBarrier())
             emitPreBarrier(elements, index, 0);
 
         masm.bind(ool->rejoinStore());
         emitStoreElementTyped(lir->value(), lir->mir()->value()->type(), lir->mir()->elementType(),
                               elements, index, 0);
     } else {
         Register temp = ToRegister(lir->getTemp(0));
         Address initLength(obj, UnboxedArrayObject::offsetOfCapacityIndexAndInitializedLength());
         masm.load32(initLength, temp);
         masm.and32(Imm32(UnboxedArrayObject::InitializedLengthMask), temp);
-        masm.branchKey(Assembler::BelowOrEqual, temp, ToInt32Key(index), ool->entry());
+        masm.branch32(Assembler::BelowOrEqual, temp, key, ool->entry());
 
         ConstantOrRegister v = ToConstantOrRegister(lir->value(), lir->mir()->value()->type());
 
         if (index->isConstant()) {
             Address address(elements, ToInt32(index) * UnboxedTypeSize(unboxedType));
             EmitUnboxedPreBarrier(masm, address, unboxedType);
 
             masm.bind(ool->rejoinStore());
@@ -7361,36 +7362,37 @@ CodeGenerator::visitStoreElementHoleV(LS
 {
     OutOfLineStoreElementHole* ool = new(alloc()) OutOfLineStoreElementHole(lir);
     addOutOfLineCode(ool, lir->mir());
 
     Register obj = ToRegister(lir->object());
     Register elements = ToRegister(lir->elements());
     const LAllocation* index = lir->index();
     const ValueOperand value = ToValue(lir, LStoreElementHoleV::Value);
+    RegisterOrInt32Constant key = ToRegisterOrInt32Constant(index);
 
     JSValueType unboxedType = lir->mir()->unboxedType();
     if (unboxedType == JSVAL_TYPE_MAGIC) {
         Address initLength(elements, ObjectElements::offsetOfInitializedLength());
-        masm.branchKey(Assembler::BelowOrEqual, initLength, ToInt32Key(index), ool->entry());
+        masm.branch32(Assembler::BelowOrEqual, initLength, key, ool->entry());
 
         if (lir->mir()->needsBarrier())
             emitPreBarrier(elements, index, 0);
 
         masm.bind(ool->rejoinStore());
         if (index->isConstant())
             masm.storeValue(value, Address(elements, ToInt32(index) * sizeof(js::Value)));
         else
             masm.storeValue(value, BaseIndex(elements, ToRegister(index), TimesEight));
     } else {
         Register temp = ToRegister(lir->getTemp(0));
         Address initLength(obj, UnboxedArrayObject::offsetOfCapacityIndexAndInitializedLength());
         masm.load32(initLength, temp);
         masm.and32(Imm32(UnboxedArrayObject::InitializedLengthMask), temp);
-        masm.branchKey(Assembler::BelowOrEqual, temp, ToInt32Key(index), ool->entry());
+        masm.branch32(Assembler::BelowOrEqual, temp, key, ool->entry());
 
         if (index->isConstant()) {
             Address address(elements, ToInt32(index) * UnboxedTypeSize(unboxedType));
             EmitUnboxedPreBarrier(masm, address, unboxedType);
 
             masm.bind(ool->rejoinStore());
             masm.storeUnboxedProperty(address, unboxedType, ConstantOrRegister(value), nullptr);
         } else {
@@ -7440,66 +7442,66 @@ CodeGenerator::visitOutOfLineStoreElemen
         if (store->value()->isConstant())
             value = ConstantOrRegister(store->value()->toConstant()->toJSValue());
         else
             value = TypedOrValueRegister(valueType, ToAnyRegister(store->value()));
         unboxedType = store->mir()->unboxedType();
         temp = store->getTemp(0);
     }
 
+    RegisterOrInt32Constant key = ToRegisterOrInt32Constant(index);
+
     // If index == initializedLength, try to bump the initialized length inline.
     // If index > initializedLength, call a stub. Note that this relies on the
     // condition flags sticking from the incoming branch.
     Label callStub;
 #if defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64)
     // Had to reimplement for MIPS because there are no flags.
     if (unboxedType == JSVAL_TYPE_MAGIC) {
         Address initLength(elements, ObjectElements::offsetOfInitializedLength());
-        masm.branchKey(Assembler::NotEqual, initLength, ToInt32Key(index), &callStub);
+        masm.branch32(Assembler::NotEqual, initLength, key, &callStub);
     } else {
         Address initLength(object, UnboxedArrayObject::offsetOfCapacityIndexAndInitializedLength());
         masm.load32(initLength, ToRegister(temp));
         masm.and32(Imm32(UnboxedArrayObject::InitializedLengthMask), ToRegister(temp));
-        masm.branchKey(Assembler::NotEqual, ToRegister(temp), ToInt32Key(index), &callStub);
+        masm.branch32(Assembler::NotEqual, ToRegister(temp), key, &callStub);
     }
 #else
     masm.j(Assembler::NotEqual, &callStub);
 #endif
 
-    Int32Key key = ToInt32Key(index);
-
     if (unboxedType == JSVAL_TYPE_MAGIC) {
         // Check array capacity.
-        masm.branchKey(Assembler::BelowOrEqual, Address(elements, ObjectElements::offsetOfCapacity()),
-                       key, &callStub);
+        masm.branch32(Assembler::BelowOrEqual, Address(elements, ObjectElements::offsetOfCapacity()),
+                      key, &callStub);
 
         // Update initialized length. The capacity guard above ensures this won't overflow,
         // due to MAX_DENSE_ELEMENTS_COUNT.
-        masm.bumpKey(&key, 1);
-        masm.storeKey(key, Address(elements, ObjectElements::offsetOfInitializedLength()));
+        masm.inc32(&key);
+        masm.store32(key, Address(elements, ObjectElements::offsetOfInitializedLength()));
 
         // Update length if length < initializedLength.
         Label dontUpdate;
-        masm.branchKey(Assembler::AboveOrEqual, Address(elements, ObjectElements::offsetOfLength()),
-                       key, &dontUpdate);
-        masm.storeKey(key, Address(elements, ObjectElements::offsetOfLength()));
+        masm.branch32(Assembler::AboveOrEqual, Address(elements, ObjectElements::offsetOfLength()),
+                      key, &dontUpdate);
+        masm.store32(key, Address(elements, ObjectElements::offsetOfLength()));
         masm.bind(&dontUpdate);
 
-        masm.bumpKey(&key, -1);
+        masm.dec32(&key);
     } else {
         // Check array capacity.
         masm.checkUnboxedArrayCapacity(object, key, ToRegister(temp), &callStub);
 
         // Update initialized length.
         masm.add32(Imm32(1), Address(object, UnboxedArrayObject::offsetOfCapacityIndexAndInitializedLength()));
 
         // Update length if length < initializedLength.
         Address lengthAddr(object, UnboxedArrayObject::offsetOfLength());
         Label dontUpdate;
-        masm.branchKey(Assembler::Above, lengthAddr, key, &dontUpdate);
+        masm.branch32(Assembler::Above, lengthAddr, key, &dontUpdate);
         masm.add32(Imm32(1), lengthAddr);
         masm.bind(&dontUpdate);
     }
 
     if (ins->isStoreElementHoleT() && unboxedType == JSVAL_TYPE_MAGIC && valueType != MIRType_Double) {
         // The inline path for StoreElementHoleT does not always store the type tag,
         // so we do the store on the OOL path. We use MIRType_None for the element type
         // so that storeElementTyped will always store the type tag.
@@ -7615,47 +7617,47 @@ CodeGenerator::emitArrayPopShift(LInstru
         MOZ_ASSERT(mir->mode() == MArrayPopShift::Shift);
         ool = oolCallVM(ArrayShiftDenseInfo, lir, ArgList(obj), StoreValueTo(out));
     }
 
     // VM call if a write barrier is necessary.
     masm.branchTestNeedsIncrementalBarrier(Assembler::NonZero, ool->entry());
 
     // Load elements and length, and VM call if length != initializedLength.
-    Int32Key key = Int32Key(lengthTemp);
+    RegisterOrInt32Constant key = RegisterOrInt32Constant(lengthTemp);
     if (mir->unboxedType() == JSVAL_TYPE_MAGIC) {
         masm.loadPtr(Address(obj, NativeObject::offsetOfElements()), elementsTemp);
         masm.load32(Address(elementsTemp, ObjectElements::offsetOfLength()), lengthTemp);
 
         Address initLength(elementsTemp, ObjectElements::offsetOfInitializedLength());
-        masm.branchKey(Assembler::NotEqual, initLength, key, ool->entry());
+        masm.branch32(Assembler::NotEqual, initLength, key, ool->entry());
     } else {
         masm.loadPtr(Address(obj, UnboxedArrayObject::offsetOfElements()), elementsTemp);
         masm.load32(Address(obj, UnboxedArrayObject::offsetOfCapacityIndexAndInitializedLength()), lengthTemp);
         masm.and32(Imm32(UnboxedArrayObject::InitializedLengthMask), lengthTemp);
 
         Address lengthAddr(obj, UnboxedArrayObject::offsetOfLength());
-        masm.branchKey(Assembler::NotEqual, lengthAddr, key, ool->entry());
+        masm.branch32(Assembler::NotEqual, lengthAddr, key, ool->entry());
     }
 
     // Test for length != 0. On zero length either take a VM call or generate
     // an undefined value, depending on whether the call is known to produce
     // undefined.
     Label done;
     if (mir->maybeUndefined()) {
         Label notEmpty;
         masm.branchTest32(Assembler::NonZero, lengthTemp, lengthTemp, &notEmpty);
         masm.moveValue(UndefinedValue(), out.valueReg());
         masm.jump(&done);
         masm.bind(&notEmpty);
     } else {
         masm.branchTest32(Assembler::Zero, lengthTemp, lengthTemp, ool->entry());
     }
 
-    masm.bumpKey(&key, -1);
+    masm.dec32(&key);
 
     if (mir->mode() == MArrayPopShift::Pop) {
         if (mir->unboxedType() == JSVAL_TYPE_MAGIC) {
             BaseIndex addr(elementsTemp, lengthTemp, TimesEight);
             masm.loadElementTypedOrValue(addr, out, mir->needsHoleCheck(), ool->entry());
         } else {
             size_t elemSize = UnboxedTypeSize(mir->unboxedType());
             BaseIndex addr(elementsTemp, lengthTemp, ScaleFromElemWidth(elemSize));
@@ -7731,52 +7733,52 @@ static const VMFunction ArrayPushDenseIn
     FunctionInfo<ArrayPushDenseFn>(jit::ArrayPushDense);
 
 void
 CodeGenerator::emitArrayPush(LInstruction* lir, const MArrayPush* mir, Register obj,
                              ConstantOrRegister value, Register elementsTemp, Register length)
 {
     OutOfLineCode* ool = oolCallVM(ArrayPushDenseInfo, lir, ArgList(obj, value), StoreRegisterTo(length));
 
-    Int32Key key = Int32Key(length);
+    RegisterOrInt32Constant key = RegisterOrInt32Constant(length);
     if (mir->unboxedType() == JSVAL_TYPE_MAGIC) {
         // Load elements and length.
         masm.loadPtr(Address(obj, NativeObject::offsetOfElements()), elementsTemp);
         masm.load32(Address(elementsTemp, ObjectElements::offsetOfLength()), length);
 
         // Guard length == initializedLength.
         Address initLength(elementsTemp, ObjectElements::offsetOfInitializedLength());
-        masm.branchKey(Assembler::NotEqual, initLength, key, ool->entry());
+        masm.branch32(Assembler::NotEqual, initLength, key, ool->entry());
 
         // Guard length < capacity.
         Address capacity(elementsTemp, ObjectElements::offsetOfCapacity());
-        masm.branchKey(Assembler::BelowOrEqual, capacity, key, ool->entry());
+        masm.branch32(Assembler::BelowOrEqual, capacity, key, ool->entry());
 
         // Do the store.
         masm.storeConstantOrRegister(value, BaseIndex(elementsTemp, length, TimesEight));
     } else {
         // Load initialized length.
         masm.load32(Address(obj, UnboxedArrayObject::offsetOfCapacityIndexAndInitializedLength()), length);
         masm.and32(Imm32(UnboxedArrayObject::InitializedLengthMask), length);
 
         // Guard length == initializedLength.
         Address lengthAddr(obj, UnboxedArrayObject::offsetOfLength());
-        masm.branchKey(Assembler::NotEqual, lengthAddr, key, ool->entry());
+        masm.branch32(Assembler::NotEqual, lengthAddr, key, ool->entry());
 
         // Guard length < capacity.
         masm.checkUnboxedArrayCapacity(obj, key, elementsTemp, ool->entry());
 
         // Load elements and do the store.
         masm.loadPtr(Address(obj, UnboxedArrayObject::offsetOfElements()), elementsTemp);
         size_t elemSize = UnboxedTypeSize(mir->unboxedType());
         BaseIndex addr(elementsTemp, length, ScaleFromElemWidth(elemSize));
         masm.storeUnboxedProperty(addr, mir->unboxedType(), value, nullptr);
     }
 
-    masm.bumpKey(&key, 1);
+    masm.inc32(&key);
 
     // Update length and initialized length.
     if (mir->unboxedType() == JSVAL_TYPE_MAGIC) {
         masm.store32(length, Address(elementsTemp, ObjectElements::offsetOfLength()));
         masm.store32(length, Address(elementsTemp, ObjectElements::offsetOfInitializedLength()));
     } else {
         masm.store32(length, Address(obj, UnboxedArrayObject::offsetOfLength()));
         masm.add32(Imm32(1), Address(obj, UnboxedArrayObject::offsetOfCapacityIndexAndInitializedLength()));
@@ -9705,22 +9707,22 @@ CodeGenerator::visitLoadUnboxedScalar(LL
 void
 CodeGenerator::visitLoadTypedArrayElementHole(LLoadTypedArrayElementHole* lir)
 {
     Register object = ToRegister(lir->object());
     const ValueOperand out = ToOutValue(lir);
 
     // Load the length.
     Register scratch = out.scratchReg();
-    Int32Key key = ToInt32Key(lir->index());
+    RegisterOrInt32Constant key = ToRegisterOrInt32Constant(lir->index());
     masm.unboxInt32(Address(object, TypedArrayObject::lengthOffset()), scratch);
 
     // Load undefined unless length > key.
     Label inbounds, done;
-    masm.branchKey(Assembler::Above, scratch, key, &inbounds);
+    masm.branch32(Assembler::Above, scratch, key, &inbounds);
     masm.moveValue(UndefinedValue(), out);
     masm.jump(&done);
 
     // Load the elements vector.
     masm.bind(&inbounds);
     masm.loadPtr(Address(object, TypedArrayObject::dataOffset()), scratch);
 
     Scalar::Type arrayType = lir->mir()->arrayType();
--- a/js/src/jit/IonCaches.cpp
+++ b/js/src/jit/IonCaches.cpp
@@ -4449,29 +4449,29 @@ GenerateSetDenseElement(JSContext* cx, M
             Address initLength(elements, ObjectElements::offsetOfInitializedLength());
             masm.branch32(Assembler::Below, initLength, indexReg, &failures);
 
             // if (initLength == index)
             Label inBounds;
             masm.branch32(Assembler::NotEqual, initLength, indexReg, &inBounds);
             {
                 // Increase initialize length.
-                Int32Key newLength(indexReg);
-                masm.bumpKey(&newLength, 1);
-                masm.storeKey(newLength, initLength);
+                Register newLength = indexReg;
+                masm.add32(Imm32(1), newLength);
+                masm.store32(newLength, initLength);
 
                 // Increase length if needed.
                 Label bumpedLength;
                 Address length(elements, ObjectElements::offsetOfLength());
                 masm.branch32(Assembler::AboveOrEqual, length, indexReg, &bumpedLength);
-                masm.storeKey(newLength, length);
+                masm.store32(newLength, length);
                 masm.bind(&bumpedLength);
 
                 // Restore the index.
-                masm.bumpKey(&newLength, -1);
+                masm.add32(Imm32(-1), newLength);
                 masm.jump(&storeElement);
             }
             // else
             masm.bind(&inBounds);
         }
 
         if (cx->zone()->needsIncrementalBarrier())
             masm.callPreBarrier(target, MIRType_Value);
--- a/js/src/jit/MacroAssembler-inl.h
+++ b/js/src/jit/MacroAssembler-inl.h
@@ -312,19 +312,62 @@ MacroAssembler::hasSelfReference() const
 // Arithmetic functions
 
 void
 MacroAssembler::addPtr(ImmPtr imm, Register dest)
 {
     addPtr(ImmWord(uintptr_t(imm.value)), dest);
 }
 
+void
+MacroAssembler::inc32(RegisterOrInt32Constant* key)
+{
+    if (key->isRegister())
+        add32(Imm32(1), key->reg());
+    else
+        key->bumpConstant(1);
+}
+
+void
+MacroAssembler::dec32(RegisterOrInt32Constant* key)
+{
+    if (key->isRegister())
+        add32(Imm32(-1), key->reg());
+    else
+        key->bumpConstant(-1);
+}
+
 // ===============================================================
 // Branch functions
 
+void
+MacroAssembler::branch32(Condition cond, Register length, const RegisterOrInt32Constant& key,
+                         Label* label)
+{
+    branch32Impl(cond, length, key, label);
+}
+
+void
+MacroAssembler::branch32(Condition cond, const Address& length, const RegisterOrInt32Constant& key,
+                         Label* label)
+{
+    branch32Impl(cond, length, key, label);
+}
+
+template <typename T>
+void
+MacroAssembler::branch32Impl(Condition cond, const T& length, const RegisterOrInt32Constant& key,
+                             Label* label)
+{
+    if (key.isRegister())
+        branch32(cond, length, key.reg(), label);
+    else
+        branch32(cond, length, Imm32(key.constant()), label);
+}
+
 template <class L>
 void
 MacroAssembler::branchIfFalseBool(Register reg, L label)
 {
     // Note that C++ bool is only 1 byte, so ignore the higher-order bits.
     branchTest32(Assembler::Zero, reg, Imm32(0xFF), label);
 }
 
@@ -486,26 +529,16 @@ MacroAssembler::branchTestMIRType(Condit
       case MIRType_MagicOptimizedArguments: // Fall through.
       case MIRType_MagicIsConstructing:
       case MIRType_MagicHole: return branchTestMagic(cond, val, label);
       default:
         MOZ_CRASH("Bad MIRType");
     }
 }
 
-template <typename T>
-void
-MacroAssembler::branchKey(Condition cond, const T& length, const Int32Key& key, Label* label)
-{
-    if (key.isRegister())
-        branch32(cond, length, key.reg(), label);
-    else
-        branch32(cond, length, Imm32(key.constant()), label);
-}
-
 void
 MacroAssembler::branchTestNeedsIncrementalBarrier(Condition cond, Label* label)
 {
     MOZ_ASSERT(cond == Zero || cond == NonZero);
     CompileZone* zone = GetJitContext()->compartment->zone();
     AbsoluteAddress needsBarrierAddr(zone->addressOfNeedsIncrementalBarrier());
     branchTest32(cond, needsBarrierAddr, Imm32(0x1), label);
 }
@@ -585,25 +618,16 @@ MacroAssembler::storeObjectOrNull(Regist
     storeValue(NullValue(), dest);
     jump(&done);
     bind(&notNull);
     storeValue(JSVAL_TYPE_OBJECT, src, dest);
     bind(&done);
 }
 
 void
-MacroAssembler::bumpKey(Int32Key* key, int diff)
-{
-    if (key->isRegister())
-        add32(Imm32(diff), key->reg());
-    else
-        key->bumpConstant(diff);
-}
-
-void
 MacroAssembler::assertStackAlignment(uint32_t alignment, int32_t offset /* = 0 */)
 {
 #ifdef DEBUG
     Label ok, bad;
     MOZ_ASSERT(IsPowerOfTwo(alignment));
 
     // Wrap around the offset to be a non-negative number.
     offset %= alignment;
--- a/js/src/jit/MacroAssembler.cpp
+++ b/js/src/jit/MacroAssembler.cpp
@@ -679,37 +679,37 @@ template void
 MacroAssembler::storeUnboxedProperty(Address address, JSValueType type,
                                      ConstantOrRegister value, Label* failure);
 
 template void
 MacroAssembler::storeUnboxedProperty(BaseIndex address, JSValueType type,
                                      ConstantOrRegister value, Label* failure);
 
 void
-MacroAssembler::checkUnboxedArrayCapacity(Register obj, const Int32Key& index, Register temp,
-                                          Label* failure)
+MacroAssembler::checkUnboxedArrayCapacity(Register obj, const RegisterOrInt32Constant& index,
+                                          Register temp, Label* failure)
 {
     Address initLengthAddr(obj, UnboxedArrayObject::offsetOfCapacityIndexAndInitializedLength());
     Address lengthAddr(obj, UnboxedArrayObject::offsetOfLength());
 
     Label capacityIsIndex, done;
     load32(initLengthAddr, temp);
     branchTest32(Assembler::NonZero, temp, Imm32(UnboxedArrayObject::CapacityMask), &capacityIsIndex);
-    branchKey(Assembler::BelowOrEqual, lengthAddr, index, failure);
+    branch32(Assembler::BelowOrEqual, lengthAddr, index, failure);
     jump(&done);
     bind(&capacityIsIndex);
 
     // Do a partial shift so that we can get an absolute offset from the base
     // of CapacityArray to use.
     JS_STATIC_ASSERT(sizeof(UnboxedArrayObject::CapacityArray[0]) == 4);
     rshiftPtr(Imm32(UnboxedArrayObject::CapacityShift - 2), temp);
     and32(Imm32(~0x3), temp);
 
     addPtr(ImmPtr(&UnboxedArrayObject::CapacityArray), temp);
-    branchKey(Assembler::BelowOrEqual, Address(temp, 0), index, failure);
+    branch32(Assembler::BelowOrEqual, Address(temp, 0), index, failure);
     bind(&done);
 }
 
 // Inlined version of gc::CheckAllocatorState that checks the bare essentials
 // and bails for anything that cannot be handled with our jit allocators.
 void
 MacroAssembler::checkAllocatorState(Label* fail)
 {
--- a/js/src/jit/MacroAssembler.h
+++ b/js/src/jit/MacroAssembler.h
@@ -763,18 +763,21 @@ class MacroAssembler : public MacroAssem
     inline void mulBy3(Register src, Register dest) PER_ARCH;
 
     inline void mulDouble(FloatRegister src, FloatRegister dest) PER_SHARED_ARCH;
 
     inline void mulDoublePtr(ImmPtr imm, Register temp, FloatRegister dest) DEFINED_ON(mips_shared, arm, arm64, x86, x64);
 
     inline void divDouble(FloatRegister src, FloatRegister dest) PER_SHARED_ARCH;
 
+    inline void inc32(RegisterOrInt32Constant* key);
     inline void inc64(AbsoluteAddress dest) PER_ARCH;
 
+    inline void dec32(RegisterOrInt32Constant* key);
+
     inline void neg32(Register reg) PER_SHARED_ARCH;
 
     inline void negateFloat(FloatRegister reg) DEFINED_ON(arm64, x86_shared);
 
     inline void negateDouble(FloatRegister reg) PER_SHARED_ARCH;
 
     // ===============================================================
     // Shift functions
@@ -791,18 +794,23 @@ class MacroAssembler : public MacroAssem
     inline void rshift64(Imm32 imm, Register64 dest) PER_ARCH;
 
     // ===============================================================
     // Branch functions
 
     inline void branch32(Condition cond, Register lhs, Register rhs, Label* label) PER_SHARED_ARCH;
     template <class L>
     inline void branch32(Condition cond, Register lhs, Imm32 rhs, L label) PER_SHARED_ARCH;
+    inline void branch32(Condition cond, Register length, const RegisterOrInt32Constant& key,
+                         Label* label);
+
     inline void branch32(Condition cond, const Address& lhs, Register rhs, Label* label) PER_SHARED_ARCH;
     inline void branch32(Condition cond, const Address& lhs, Imm32 rhs, Label* label) PER_SHARED_ARCH;
+    inline void branch32(Condition cond, const Address& length, const RegisterOrInt32Constant& key,
+                         Label* label);
 
     inline void branch32(Condition cond, const AbsoluteAddress& lhs, Register rhs, Label* label)
         DEFINED_ON(arm, arm64, mips_shared, x86, x64);
     inline void branch32(Condition cond, const AbsoluteAddress& lhs, Imm32 rhs, Label* label)
         DEFINED_ON(arm, arm64, mips_shared, x86, x64);
 
     inline void branch32(Condition cond, const BaseIndex& lhs, Register rhs, Label* label)
         DEFINED_ON(x86_shared);
@@ -917,19 +925,16 @@ class MacroAssembler : public MacroAssem
 
     template <typename Value>
     inline void branchTestMIRType(Condition cond, const Value& val, MIRType type, Label* label);
 
     // Emit type case branch on tag matching if the type tag in the definition
     // might actually be that type.
     void maybeBranchTestType(MIRType type, MDefinition* maybeDef, Register tag, Label* label);
 
-    template <typename T>
-    inline void branchKey(Condition cond, const T& length, const Int32Key& key, Label* label);
-
     inline void branchTestNeedsIncrementalBarrier(Condition cond, Label* label);
 
     // Perform a type-test on a tag of a Value (32bits boxing), or the tagged
     // value (64bits boxing).
     inline void branchTestUndefined(Condition cond, Register tag, Label* label) PER_SHARED_ARCH;
     inline void branchTestInt32(Condition cond, Register tag, Label* label) PER_SHARED_ARCH;
     inline void branchTestDouble(Condition cond, Register tag, Label* label)
         DEFINED_ON(arm, arm64, mips32, mips64, x86_shared);
@@ -1013,16 +1018,20 @@ class MacroAssembler : public MacroAssem
     inline void branchTestDoubleTruthy(bool truthy, FloatRegister reg, Label* label) PER_SHARED_ARCH;
     inline void branchTestBooleanTruthy(bool truthy, const ValueOperand& value, Label* label) PER_ARCH;
     inline void branchTestStringTruthy(bool truthy, const ValueOperand& value, Label* label)
         DEFINED_ON(arm, arm64, mips32, mips64, x86_shared);
 
   private:
 
     // Implementation for branch* methods.
+    template <typename T>
+    inline void branch32Impl(Condition cond, const T& length, const RegisterOrInt32Constant& key,
+                             Label* label);
+
     template <typename T, typename S>
     inline void branchPtrImpl(Condition cond, const T& lhs, const S& rhs, Label* label)
         DEFINED_ON(x86_shared);
 
     template <typename T>
     inline void branchTestUndefinedImpl(Condition cond, const T& t, Label* label)
         DEFINED_ON(arm, arm64, x86_shared);
     template <typename T>
@@ -1201,20 +1210,18 @@ class MacroAssembler : public MacroAssem
     }
 
     inline void storeCallResultValue(TypedOrValueRegister dest);
 
     template <typename T>
     Register extractString(const T& source, Register scratch) {
         return extractObject(source, scratch);
     }
-
-    inline void bumpKey(Int32Key* key, int diff);
-
-    void storeKey(const Int32Key& key, const Address& dest) {
+    using MacroAssemblerSpecific::store32;
+    void store32(const RegisterOrInt32Constant& key, const Address& dest) {
         if (key.isRegister())
             store32(key.reg(), dest);
         else
             store32(Imm32(key.constant()), dest);
     }
 
     template <typename T>
     void callPreBarrier(const T& address, MIRType type) {
@@ -1295,18 +1302,18 @@ class MacroAssembler : public MacroAssem
 
     // Store a property to an UnboxedPlainObject, without triggering barriers.
     // If failure is null, the value definitely has a type suitable for storing
     // in the property.
     template <typename T>
     void storeUnboxedProperty(T address, JSValueType type,
                               ConstantOrRegister value, Label* failure);
 
-    void checkUnboxedArrayCapacity(Register obj, const Int32Key& index, Register temp,
-                                   Label* failure);
+    void checkUnboxedArrayCapacity(Register obj, const RegisterOrInt32Constant& index,
+                                   Register temp, Label* failure);
 
     Register extractString(const Address& address, Register scratch) {
         return extractObject(address, scratch);
     }
     Register extractString(const ValueOperand& value, Register scratch) {
         return extractObject(value, scratch);
     }
 
--- a/js/src/jit/RegisterSets.h
+++ b/js/src/jit/RegisterSets.h
@@ -280,28 +280,28 @@ class ConstantOrRegister
         return dataValue();
     }
 
     TypedOrValueRegister reg() {
         return dataReg();
     }
 };
 
-struct Int32Key {
+struct RegisterOrInt32Constant {
     bool isRegister_;
     union {
         Register reg_;
         int32_t constant_;
     };
 
-    explicit Int32Key(Register reg)
+    explicit RegisterOrInt32Constant(Register reg)
       : isRegister_(true), reg_(reg)
     { }
 
-    explicit Int32Key(int32_t index)
+    explicit RegisterOrInt32Constant(int32_t index)
       : isRegister_(false), constant_(index)
     { }
 
     inline void bumpConstant(int diff) {
         MOZ_ASSERT(!isRegister_);
         constant_ += diff;
     }
     inline Register reg() const {
--- a/js/src/jit/shared/CodeGenerator-shared-inl.h
+++ b/js/src/jit/shared/CodeGenerator-shared-inl.h
@@ -135,22 +135,22 @@ ToAnyRegister(const LAllocation* a)
 }
 
 static inline AnyRegister
 ToAnyRegister(const LDefinition* def)
 {
     return ToAnyRegister(def->output());
 }
 
-static inline Int32Key
-ToInt32Key(const LAllocation* a)
+static inline RegisterOrInt32Constant
+ToRegisterOrInt32Constant(const LAllocation* a)
 {
     if (a->isConstant())
-        return Int32Key(ToInt32(a));
-    return Int32Key(ToRegister(a));
+        return RegisterOrInt32Constant(ToInt32(a));
+    return RegisterOrInt32Constant(ToRegister(a));
 }
 
 static inline ValueOperand
 GetValueOutput(LInstruction* ins)
 {
 #if defined(JS_NUNBOX32)
     return ValueOperand(ToRegister(ins->getDef(TYPE_INDEX)),
                         ToRegister(ins->getDef(PAYLOAD_INDEX)));