Coalesce handling of RegisterID and FPRegisterID within FrameState, bug 609898.
authorBrian Hackett <bhackett1024@gmail.com>
Thu, 02 Dec 2010 11:40:14 -0800
changeset 74631 b8b23a892c561a0a9c568b1880586e2090ff92dc
parent 74630 ec29ba480113f18ddec86ab01b0805385899307b
child 74632 dfce328c57ee8f0e6a1f23bfcf10656008f9e82e
push id2
push userbsmedberg@mozilla.com
push dateFri, 19 Aug 2011 14:38:13 +0000
bugs609898
milestone2.0b8pre
Coalesce handling of RegisterID and FPRegisterID within FrameState, bug 609898.
js/src/methodjit/BaseAssembler.h
js/src/methodjit/Compiler.cpp
js/src/methodjit/FastArithmetic.cpp
js/src/methodjit/FastOps.cpp
js/src/methodjit/FrameState-inl.h
js/src/methodjit/FrameState.cpp
js/src/methodjit/FrameState.h
js/src/methodjit/ImmutableSync.cpp
js/src/methodjit/InlineFrameAssembler.h
js/src/methodjit/MachineRegs.h
js/src/methodjit/MonoIC.cpp
--- a/js/src/methodjit/BaseAssembler.h
+++ b/js/src/methodjit/BaseAssembler.h
@@ -144,19 +144,16 @@ class Assembler : public ValueAssembler
         saveCount(0)
 #ifdef DEBUG
         , callIsAligned(false)
 #endif
     {
         startLabel = label();
     }
 
-    /* Total number of floating-point registers. */
-    static const uint32 TotalFPRegisters = FPRegisters::TotalFPRegisters;
-
     /* Register pair storing returned type/data for calls. */
 #if defined(JS_CPU_X86) || defined(JS_CPU_X64)
 static const JSC::MacroAssembler::RegisterID JSReturnReg_Type  = JSC::X86Registers::ecx;
 static const JSC::MacroAssembler::RegisterID JSReturnReg_Data  = JSC::X86Registers::edx;
 static const JSC::MacroAssembler::RegisterID JSParamReg_Argc   = JSC::X86Registers::ecx;
 #elif defined(JS_CPU_ARM)
 static const JSC::MacroAssembler::RegisterID JSReturnReg_Type  = JSC::ARMRegisters::r2;
 static const JSC::MacroAssembler::RegisterID JSReturnReg_Data  = JSC::ARMRegisters::r1;
@@ -201,18 +198,18 @@ static const JSC::MacroAssembler::Regist
     }
 
     void fastLoadDouble(RegisterID lo, RegisterID hi, FPRegisterID fpReg) {
         if (MacroAssemblerX86Common::getSSEState() >= HasSSE4_1) {
             m_assembler.movd_rr(lo, fpReg);
             m_assembler.pinsrd_rr(hi, fpReg);
         } else {
             m_assembler.movd_rr(lo, fpReg);
-            m_assembler.movd_rr(hi, FPRegisters::ConversionTemp);
-            m_assembler.unpcklps_rr(FPRegisters::ConversionTemp, fpReg);
+            m_assembler.movd_rr(hi, Registers::FPConversionTemp);
+            m_assembler.unpcklps_rr(Registers::FPConversionTemp, fpReg);
         }
     }
 #endif
 
     /*
      * Move a register pair which may indicate either an int32 or double into fpreg,
      * converting to double in the int32 case.
      */
@@ -250,27 +247,27 @@ static const JSC::MacroAssembler::Regist
         loadDouble(address, fpreg);
         fallthrough.linkTo(label(), this);
     }
 
     /* Ensure that an in-memory address is definitely a double. */
     void ensureInMemoryDouble(Address address)
     {
         Jump notInteger = testInt32(Assembler::NotEqual, address);
-        convertInt32ToDouble(payloadOf(address), FPRegisters::ConversionTemp);
-        storeDouble(FPRegisters::ConversionTemp, address);
+        convertInt32ToDouble(payloadOf(address), Registers::FPConversionTemp);
+        storeDouble(Registers::FPConversionTemp, address);
         notInteger.linkTo(label(), this);
     }
 
     void negateDouble(FPRegisterID fpreg)
     {
 #if defined JS_CPU_X86 || defined JS_CPU_X64
         static const uint64 DoubleNegMask = 0x8000000000000000ULL;
-        loadDouble(&DoubleNegMask, FPRegisters::ConversionTemp);
-        xorDouble(FPRegisters::ConversionTemp, fpreg);
+        loadDouble(&DoubleNegMask, Registers::FPConversionTemp);
+        xorDouble(Registers::FPConversionTemp, fpreg);
 #elif defined JS_CPU_ARM
         negDouble(fpreg, fpreg);
 #endif
     }
 
     // Prepares for a stub call.
     void *getCallTarget(void *fun) {
 #ifdef JS_CPU_ARM
@@ -299,32 +296,35 @@ static const JSC::MacroAssembler::Regist
          * location on the stack can hijack C++'s return mechanism by overwriting
          * that address, so a veneer is not required.
          */
         void *pfun = fun;
 #endif
         return pfun;
     }
 
+    /* :FIXME: unused */
+#if 0
     // Save all registers in the given mask.
     void saveRegs(uint32 volatileMask) {
         // Only one use per call.
         JS_ASSERT(saveCount == 0);
         // Must save registers before pushing arguments or setting up calls.
         JS_ASSERT(!callIsAligned);
 
         Registers set(volatileMask);
         while (!set.empty()) {
             JS_ASSERT(saveCount < TotalRegisters);
 
             RegisterID reg = set.takeAnyReg();
             savedRegs[saveCount++] = reg;
             push(reg);
         }
     }
+#endif
 
     static const uint32 StackAlignment = 16;
 
     static inline uint32 alignForCall(uint32 stackBytes) {
 #if defined(JS_CPU_X86) || defined(JS_CPU_X64)
         // If StackAlignment is a power of two, % is just two shifts.
         // 16 - (x % 16) gives alignment, extra % 16 handles total == 0.
         return (StackAlignment - (stackBytes % StackAlignment)) % StackAlignment;
--- a/js/src/methodjit/Compiler.cpp
+++ b/js/src/methodjit/Compiler.cpp
@@ -2357,17 +2357,17 @@ mjit::Compiler::emitReturn(FrameEntry *f
     emitFinalReturn(masm);
     frame.discardFrame();
 }
 
 void
 mjit::Compiler::prepareStubCall(Uses uses)
 {
     JaegerSpew(JSpew_Insns, " ---- STUB CALL, SYNCING FRAME ---- \n");
-    frame.syncAndKill(Registers(Registers::TempRegs), uses);
+    frame.syncAndKill(Registers(Registers::TempAnyRegs), uses);
     JaegerSpew(JSpew_Insns, " ---- FRAME SYNCING DONE ---- \n");
 }
 
 JSC::MacroAssembler::Call
 mjit::Compiler::emitStubCall(void *ptr)
 {
     JaegerSpew(JSpew_Insns, " ---- CALLING STUB ---- \n");
     Call cl = masm.fallibleVMCall(ptr, PC, frame.stackDepth() + script->nfixed);
@@ -2437,17 +2437,17 @@ mjit::Compiler::addReturnSite(Label join
 void
 mjit::Compiler::emitUncachedCall(uint32 argc, bool callingNew)
 {
     CallPatchInfo callPatch;
 
     RegisterID r0 = Registers::ReturnReg;
     VoidPtrStubUInt32 stub = callingNew ? stubs::UncachedNew : stubs::UncachedCall;
 
-    frame.syncAndKill(Registers(Registers::AvailRegs), Uses(argc + 2));
+    frame.syncAndKill(Uses(argc + 2));
     prepareStubCall(Uses(argc + 2));
     masm.move(Imm32(argc), Registers::ArgReg1);
     INLINE_STUBCALL(stub);
 
     Jump notCompiled = masm.branchTestPtr(Assembler::Zero, r0, r0);
 
     masm.loadPtr(FrameAddress(offsetof(VMFrame, regs.fp)), JSFrameReg);
     callPatch.hasFastNcode = true;
@@ -2674,17 +2674,17 @@ mjit::Compiler::inlineCallHelper(uint32 
             RegisterID origThisData;
             {
                 /* Get thisv in registers. */
                 frame.ensureFullRegs(origThis, &origThisType, &maybeOrigThisData);
                 origThisData = maybeOrigThisData.reg();
                 PinRegAcrossSyncAndKill p3(frame, origThisData), p4(frame, origThisType);
 
                 /* Leaves pinned regs untouched. */
-                frame.syncAndKill(Registers(Registers::AvailRegs), Uses(speculatedArgc + 2));
+                frame.syncAndKill(Uses(speculatedArgc + 2));
             }
 
             checkCallApplySpeculation(callImmArgc, speculatedArgc,
                                       origCallee, origThis,
                                       origCalleeType, origCalleeData,
                                       origThisType, origThisData,
                                       &uncachedCallSlowRejoin, &uncachedCallPatch);
 
@@ -2699,17 +2699,17 @@ mjit::Compiler::inlineCallHelper(uint32 
              * length of the array passed to apply.
              */
             if (*PC == JSOP_FUNCALL)
                 callIC.frameSize.initStatic(frame.localSlots(), speculatedArgc - 1);
             else
                 callIC.frameSize.initDynamic();
         } else {
             /* Leaves pinned regs untouched. */
-            frame.syncAndKill(Registers(Registers::AvailRegs), Uses(speculatedArgc + 2));
+            frame.syncAndKill(Uses(speculatedArgc + 2));
 
             icCalleeType = origCalleeType;
             icCalleeData = origCalleeData;
             icRvalAddr = frame.addressOf(origCallee);
             callIC.frameSize.initStatic(frame.localSlots(), speculatedArgc);
         }
     }
 
@@ -2717,25 +2717,25 @@ mjit::Compiler::inlineCallHelper(uint32 
     MaybeJump notObjectJump;
     if (icCalleeType.isSet())
         notObjectJump = masm.testObject(Assembler::NotEqual, icCalleeType.reg());
 
     /*
      * For an optimized apply, keep icCalleeData and funPtrReg in a
      * callee-saved registers for the subsequent ic::SplatApplyArgs call.
      */
-    Registers tempRegs;
+    Registers tempRegs(Registers::AvailRegs);
     if (callIC.frameSize.isDynamic() && !Registers::isSaved(icCalleeData)) {
-        RegisterID x = tempRegs.takeRegInMask(Registers::SavedRegs);
+        RegisterID x = tempRegs.takeAnyReg(Registers::SavedRegs).reg();
         masm.move(icCalleeData, x);
         icCalleeData = x;
     } else {
         tempRegs.takeReg(icCalleeData);
     }
-    RegisterID funPtrReg = tempRegs.takeRegInMask(Registers::SavedRegs);
+    RegisterID funPtrReg = tempRegs.takeAnyReg(Registers::SavedRegs).reg();
 
     /*
      * Guard on the callee identity. This misses on the first run. If the
      * callee is scripted, compiled/compilable, and argc == nargs, then this
      * guard is patched, and the compiled code address is baked in.
      */
     Jump j = masm.branchPtrWithPatch(Assembler::NotEqual, icCalleeData, callIC.funGuard);
     callIC.funJump = j;
@@ -2747,17 +2747,17 @@ mjit::Compiler::inlineCallHelper(uint32 
 
         /*
          * Test if the callee is even a function. If this doesn't match, we
          * take a _really_ slow path later.
          */
         Jump notFunction = stubcc.masm.testFunction(Assembler::NotEqual, icCalleeData);
 
         /* Test if the function is scripted. */
-        RegisterID tmp = tempRegs.takeAnyReg();
+        RegisterID tmp = tempRegs.takeAnyReg().reg();
         stubcc.masm.loadFunctionPrivate(icCalleeData, funPtrReg);
         stubcc.masm.load16(Address(funPtrReg, offsetof(JSFunction, flags)), tmp);
         stubcc.masm.and32(Imm32(JSFUN_KINDMASK), tmp);
         Jump isNative = stubcc.masm.branch32(Assembler::Below, tmp, Imm32(JSFUN_INTERPRETED));
         tempRegs.putReg(tmp);
 
         /*
          * N.B. After this call, the frame will have a dynamic frame size.
@@ -4811,17 +4811,17 @@ mjit::Compiler::jsop_instanceof()
 }
 
 void
 mjit::Compiler::emitEval(uint32 argc)
 {
     /* Check for interrupts on function call */
     interruptCheckHelper();
 
-    frame.syncAndKill(Registers(Registers::AvailRegs), Uses(argc + 2));
+    frame.syncAndKill(Uses(argc + 2));
     prepareStubCall(Uses(argc + 2));
     masm.move(Imm32(argc), Registers::ArgReg1);
     INLINE_STUBCALL(stubs::Eval);
     frame.popn(argc + 2);
     frame.pushSynced(knownPushedType(0));
 }
 
 void
--- a/js/src/methodjit/FastArithmetic.cpp
+++ b/js/src/methodjit/FastArithmetic.cpp
@@ -397,28 +397,28 @@ mjit::Compiler::jsop_binary_double(Frame
 
     if (done.isSet())
         done.getJump().linkTo(masm.label(), &masm);
 
     stubcc.leave();
     OOL_STUBCALL(stub);
 
     if (allocateRight)
-        frame.freeFPReg(fpRight);
+        frame.freeReg(fpRight);
 
     frame.popn(2);
 
     if (type == JSVAL_TYPE_UNKNOWN) {
-        frame.freeFPReg(fpLeft);
+        frame.freeReg(fpLeft);
         frame.pushSynced(type);
     } else if (type == JSVAL_TYPE_DOUBLE) {
         frame.pushDouble(fpLeft);
     } else {
         JS_ASSERT(op == JSOP_DIV && type == JSVAL_TYPE_INT32);
-        frame.freeFPReg(fpLeft);
+        frame.freeReg(fpLeft);
         frame.pushSynced(type);
     }
 
     stubcc.rejoin(Changes(1));
 }
 
 /*
  * Simpler version of jsop_binary_full() for when lhs == rhs.
@@ -508,17 +508,17 @@ mjit::Compiler::jsop_binary_full_simple(
     /* Finish up stack operations. */
     frame.popn(2);
 
     if (type == JSVAL_TYPE_INT32)
         frame.pushTypedPayload(type, regs.result);
     else
         frame.pushNumber(regs.result, true);
 
-    frame.freeFPReg(regs.lhsFP);
+    frame.freeReg(regs.lhsFP);
 
     /* Merge back OOL double path. */
     if (doublePathDone.isSet())
         stubcc.linkRejoin(doublePathDone.get());
 
     stubcc.rejoin(Changes(1));
 }
 
@@ -758,18 +758,18 @@ mjit::Compiler::jsop_binary_full(FrameEn
     if (regs.undoResult)
         frame.takeReg(regs.result);
 
     if (type == JSVAL_TYPE_INT32)
         frame.pushTypedPayload(type, regs.result);
     else
         frame.pushNumber(regs.result, true);
 
-    frame.freeFPReg(regs.lhsFP);
-    frame.freeFPReg(regs.rhsFP);
+    frame.freeReg(regs.lhsFP);
+    frame.freeReg(regs.rhsFP);
 
     /* Merge back OOL double path. */
     if (doublePathDone.isSet())
         stubcc.linkRejoin(doublePathDone.get());
 
     stubcc.rejoin(Changes(1));
 }
 
@@ -824,17 +824,17 @@ mjit::Compiler::jsop_neg()
         maybeJumpIfNotDouble(masm, jmpNotDbl, fe, feTypeReg);
 
         FPRegisterID fpreg = frame.allocFPReg();
         frame.loadDouble(fe, fpreg, masm);
         masm.negateDouble(fpreg);
 
         /* Overwrite pushed frame's memory (before push). */
         masm.storeDouble(fpreg, frame.addressOf(fe));
-        frame.freeFPReg(fpreg);
+        frame.freeReg(fpreg);
     }
 
     /* Try an integer path (out-of-line). */
     MaybeJump jmpNotInt;
     MaybeJump jmpIntZero;
     MaybeJump jmpMinInt;
     MaybeJump jmpIntRejoin;
     Label lblIntPath = stubcc.masm.label();
@@ -932,22 +932,22 @@ mjit::Compiler::jsop_mod()
     } else {
         frame.takeReg(X86Registers::eax);
         masm.move(Imm32(lhs->getValue().toInt32()), X86Registers::eax);
     }
 
     /* Get RHS into anything but EDX - could avoid more spilling? */
     MaybeRegisterID temp;
     RegisterID rhsReg;
+    uint32 mask = Registers::AvailRegs & ~Registers::maskReg(X86Registers::edx);
     if (!rhs->isConstant()) {
-        uint32 mask = Registers::AvailRegs & ~Registers::maskReg(X86Registers::edx);
         rhsReg = frame.tempRegInMaskForData(rhs, mask);
         JS_ASSERT(rhsReg != X86Registers::edx);
     } else {
-        rhsReg = frame.allocReg(Registers::AvailRegs & ~Registers::maskReg(X86Registers::edx));
+        rhsReg = frame.allocReg(mask).reg();
         JS_ASSERT(rhsReg != X86Registers::edx);
         masm.move(Imm32(rhs->getValue().toInt32()), rhsReg);
         temp = rhsReg;
     }
     frame.takeReg(X86Registers::edx);
     frame.freeReg(X86Registers::eax);
 
     if (temp.isSet())
@@ -1218,17 +1218,17 @@ mjit::Compiler::jsop_equality_int_string
         stubcc.leave();
         OOL_STUBCALL(stub);
 
         RegisterID reg = frame.ownRegForData(lhs);
 
         /* x86/64's SET instruction can only take single-byte regs.*/
         RegisterID resultReg = reg;
         if (!(Registers::maskReg(reg) & Registers::SingleByteRegs))
-            resultReg = frame.allocReg(Registers::SingleByteRegs);
+            resultReg = frame.allocReg(Registers::SingleByteRegs).reg();
 
         /* Emit the compare & set. */
         if (rhs->isConstant()) {
             masm.set32(cond, reg, Imm32(rhs->getValue().toInt32()), resultReg);
         } else if (frame.shouldAvoidDataRemat(rhs)) {
             masm.set32(cond, reg,
                        masm.payloadOf(frame.addressOf(rhs)),
                        resultReg);
@@ -1353,21 +1353,21 @@ mjit::Compiler::jsop_relational_double(J
 
     JS_ASSERT_IF(!target, fused != JSOP_IFEQ);
 
     FPRegisterID fpLeft, fpRight;
     bool allocateLeft, allocateRight;
 
     MaybeJump lhsNotNumber = loadDouble(lhs, &fpLeft, &allocateLeft);
     if (!allocateLeft)
-        frame.pinFPReg(fpLeft);
+        frame.pinReg(fpLeft);
 
     MaybeJump rhsNotNumber = loadDouble(rhs, &fpRight, &allocateRight);
     if (!allocateLeft)
-        frame.unpinFPReg(fpLeft);
+        frame.unpinReg(fpLeft);
 
     Assembler::DoubleCondition dblCond = DoubleCondForOp(op, fused);
 
     if (target) {
         if (lhsNotNumber.isSet())
             stubcc.linkExitForBranch(lhsNotNumber.get());
         if (rhsNotNumber.isSet())
             stubcc.linkExitForBranch(rhsNotNumber.get());
@@ -1416,19 +1416,19 @@ mjit::Compiler::jsop_relational_double(J
         masm.move(Imm32(1), reg);
         skip.linkTo(masm.label(), &masm);
 
         frame.pushTypedPayload(JSVAL_TYPE_BOOLEAN, reg);
 
         stubcc.rejoin(Changes(1));
 
         if (allocateLeft)
-            frame.freeFPReg(fpLeft);
+            frame.freeReg(fpLeft);
         if (allocateRight)
-            frame.freeFPReg(fpRight);
+            frame.freeReg(fpRight);
     }
 
     return true;
 }
 
 bool
 mjit::Compiler::jsop_relational_self(JSOp op, BoolStub stub, jsbytecode *target, JSOp fused)
 {
@@ -1687,15 +1687,15 @@ mjit::Compiler::jsop_relational_full(JSO
 
         frame.popn(2);
         frame.pushTypedPayload(JSVAL_TYPE_BOOLEAN, regs.result);
 
         if (hasDoublePath)
             stubcc.crossJump(doubleDone.get(), masm.label());
         stubcc.rejoin(Changes(1));
 
-        frame.freeFPReg(regs.lhsFP);
-        frame.freeFPReg(regs.rhsFP);
+        frame.freeReg(regs.lhsFP);
+        frame.freeReg(regs.rhsFP);
     }
 
     return true;
 }
 
--- a/js/src/methodjit/FastOps.cpp
+++ b/js/src/methodjit/FastOps.cpp
@@ -147,17 +147,17 @@ mjit::Compiler::ensureInteger(FrameEntry
 
         FPRegisterID fpreg = frame.allocFPReg();
         frame.loadDouble(fe, fpreg, masm);
         Jump truncateGuard = masm.branchTruncateDoubleToInt32(fpreg, scratchReg);
         stubcc.linkExit(truncateGuard, uses);
         masm.move(scratchReg, dataReg);
         intGuard.linkTo(masm.label(), &masm);
 
-        frame.freeFPReg(fpreg);
+        frame.freeReg(fpreg);
         frame.freeReg(scratchReg);
         frame.learnType(fe, JSVAL_TYPE_INT32);
     }
 }
 
 void
 mjit::Compiler::jsop_rsh()
 {
@@ -653,17 +653,17 @@ mjit::Compiler::jsop_not()
         return;
     }
 
     if (top->isTypeKnown()) {
         JSValueType type = top->getKnownType();
         switch (type) {
           case JSVAL_TYPE_INT32:
           {
-            RegisterID data = frame.allocReg(Registers::SingleByteRegs);
+            RegisterID data = frame.allocReg(Registers::SingleByteRegs).reg();
             if (frame.shouldAvoidDataRemat(top))
                 masm.loadPayload(frame.addressOf(top), data);
             else
                 masm.move(frame.tempRegForData(top), data);
 
             masm.set32(Assembler::Equal, data, Imm32(0), data);
 
             frame.pop();
@@ -702,17 +702,17 @@ mjit::Compiler::jsop_not()
             frame.pushTypedPayload(JSVAL_TYPE_BOOLEAN, reg);
             break;
           }
         }
 
         return;
     }
 
-    RegisterID data = frame.allocReg(Registers::SingleByteRegs);
+    RegisterID data = frame.allocReg(Registers::SingleByteRegs).reg();
     if (frame.shouldAvoidDataRemat(top))
         masm.loadPayload(frame.addressOf(top), data);
     else
         masm.move(frame.tempRegForData(top), data);
     RegisterID type = frame.tempRegForType(top);
     Label syncTarget = stubcc.syncExitAndJump(Uses(1));
 
 
@@ -1669,17 +1669,17 @@ mjit::Compiler::jsop_stricteq(JSOp op)
         /* False iff NaN. */
         if (lhs->isTypeKnown() && lhs->isNotType(JSVAL_TYPE_DOUBLE)) {
             frame.popn(2);
             frame.push(BooleanValue(op == JSOP_STRICTEQ));
             return;
         }
         
         /* Assume NaN is in canonical form. */
-        RegisterID result = frame.allocReg(Registers::SingleByteRegs);
+        RegisterID result = frame.allocReg(Registers::SingleByteRegs).reg();
         RegisterID treg = frame.tempRegForType(lhs);
 
         Assembler::Condition oppositeCond = (op == JSOP_STRICTEQ) ? Assembler::NotEqual : Assembler::Equal;
 
 #if defined JS_CPU_X86 || defined JS_CPU_ARM
         static const int CanonicalNaNType = 0x7FF80000;
         masm.setPtr(oppositeCond, treg, Imm32(CanonicalNaNType), result);
 #elif defined JS_CPU_X64
@@ -1702,17 +1702,17 @@ mjit::Compiler::jsop_stricteq(JSOp op)
         if (test->isTypeKnown()) {
             frame.popn(2);
             frame.push(BooleanValue((test->getKnownType() == known->getKnownType()) ==
                                   (op == JSOP_STRICTEQ)));
             return;
         }
 
         /* This is only true if the other side is |null|. */
-        RegisterID result = frame.allocReg(Registers::SingleByteRegs);
+        RegisterID result = frame.allocReg(Registers::SingleByteRegs).reg();
 #if defined JS_CPU_X86 || defined JS_CPU_ARM
         JSValueTag mask = known->getKnownTag();
         if (frame.shouldAvoidTypeRemat(test))
             masm.set32(cond, masm.tagOf(frame.addressOf(test)), Imm32(mask), result);
         else
             masm.set32(cond, frame.tempRegForType(test), Imm32(mask), result);
 #elif defined JS_CPU_X64
         RegisterID maskReg = frame.allocReg();
@@ -1745,17 +1745,17 @@ mjit::Compiler::jsop_stricteq(JSOp op)
             frame.push(BooleanValue((L.toBoolean() == R.toBoolean()) == (op == JSOP_STRICTEQ)));
             return;
         }
 
         RegisterID data = frame.copyDataIntoReg(test);
 
         RegisterID result = data;
         if (!(Registers::maskReg(data) & Registers::SingleByteRegs))
-            result = frame.allocReg(Registers::SingleByteRegs);
+            result = frame.allocReg(Registers::SingleByteRegs).reg();
         
         Jump notBoolean;
         if (!test->isTypeKnown())
            notBoolean = frame.testBoolean(Assembler::NotEqual, test);
 
         /* Do a dynamic test. */
         bool val = lhsTest ? lhs->getValue().toBoolean() : rhs->getValue().toBoolean();
         masm.set32(cond, data, Imm32(val), result);
--- a/js/src/methodjit/FrameState-inl.h
+++ b/js/src/methodjit/FrameState-inl.h
@@ -77,72 +77,56 @@ FrameState::haveSameBacking(FrameEntry *
 {
     if (lhs->isCopy())
         lhs = lhs->copyOf();
     if (rhs->isCopy())
         rhs = rhs->copyOf();
     return lhs == rhs;
 }
 
-inline JSC::MacroAssembler::RegisterID
-FrameState::allocReg()
+inline AnyRegisterID
+FrameState::allocReg(uint32 mask)
 {
-    RegisterID reg;
-    if (!freeRegs.empty()) {
-        reg = freeRegs.takeAnyReg();
+    if (freeRegs.hasRegInMask(mask))
+        return freeRegs.takeAnyReg(mask);
+
+    AnyRegisterID reg = evictSomeReg(mask);
+    regstate(reg).forget();
+    return reg;
+}
+
+inline AnyRegisterID
+FrameState::allocReg(FrameEntry *fe, bool fp, RematInfo::RematType type)
+{
+    JS_ASSERT_IF(fp, type == RematInfo::DATA);
+    uint32 mask = fp ? (uint32) Registers::AvailFPRegs : (uint32) Registers::AvailRegs;
+
+    AnyRegisterID reg;
+    if (!freeRegs.empty(mask)) {
+        reg = freeRegs.takeAnyReg(mask);
     } else {
-        reg = evictSomeReg();
-        regstate[reg].forget();
+        reg = evictSomeReg(mask);
+        regstate(reg).forget();
     }
 
+    regstate(reg).associate(fe, type);
+
     return reg;
 }
 
 inline JSC::MacroAssembler::RegisterID
-FrameState::allocReg(uint32 mask)
+FrameState::allocReg()
 {
-    RegisterID reg;
-    if (freeRegs.hasRegInMask(mask)) {
-        reg = freeRegs.takeRegInMask(mask);
-    } else {
-        reg = evictSomeReg(mask);
-        regstate[reg].forget();
-    }
-
-    return reg;
-}
-
-inline JSC::MacroAssembler::RegisterID
-FrameState::allocReg(FrameEntry *fe, RematInfo::RematType type)
-{
-    RegisterID reg;
-    if (!freeRegs.empty()) {
-        reg = freeRegs.takeAnyReg();
-    } else {
-        reg = evictSomeReg();
-        regstate[reg].forget();
-    }
-
-    regstate[reg].associate(fe, type);
-
-    return reg;
+    return allocReg(Registers::AvailRegs).reg();
 }
 
 inline JSC::MacroAssembler::FPRegisterID
 FrameState::allocFPReg()
 {
-    FPRegisterID reg;
-    if (!freeFPRegs.empty()) {
-        reg = freeFPRegs.takeAnyReg();
-    } else {
-        reg = evictSomeFPReg();
-        fpregstate[reg].forget();
-    }
-
-    return reg;
+    return allocReg(Registers::AvailFPRegs).fpreg();
 }
 
 inline void
 FrameState::convertInt32ToDouble(Assembler &masm, FrameEntry *fe, FPRegisterID fpreg) const
 {
     JS_ASSERT(!fe->isConstant());
 
     if (fe->isCopy())
@@ -170,57 +154,39 @@ FrameState::pop()
     FrameEntry *fe = --sp;
     if (!fe->isTracked())
         return;
 
     forgetAllRegs(fe);
 }
 
 inline void
-FrameState::freeReg(RegisterID reg)
+FrameState::freeReg(AnyRegisterID reg)
 {
-    JS_ASSERT(!regstate[reg].usedBy());
+    JS_ASSERT(!regstate(reg).usedBy());
 
     freeRegs.putReg(reg);
 }
 
 inline void
-FrameState::freeFPReg(FPRegisterID reg)
-{
-    JS_ASSERT(!fpregstate[reg].usedBy());
-
-    freeFPRegs.putReg(reg);
-}
-
-inline void
-FrameState::forgetReg(RegisterID reg)
+FrameState::forgetReg(AnyRegisterID reg)
 {
     /*
      * Important: Do not touch the fe here. We can peephole optimize away
      * loads and stores by re-using the contents of old FEs.
      */
-    JS_ASSERT_IF(regstate[reg].fe(), !regstate[reg].fe()->isCopy());
+    JS_ASSERT_IF(regstate(reg).fe(), !regstate(reg).fe()->isCopy());
 
-    if (!regstate[reg].isPinned()) {
-        regstate[reg].forget();
+    if (!regstate(reg).isPinned()) {
+        regstate(reg).forget();
         freeRegs.putReg(reg);
     }
 }
 
 inline void
-FrameState::forgetFPReg(FPRegisterID reg)
-{
-    JS_ASSERT_IF(fpregstate[reg].fe(), !fpregstate[reg].fe()->isCopy());
-    JS_ASSERT(!fpregstate[reg].isPinned());
-
-    fpregstate[reg].forget();
-    freeFPRegs.putReg(reg);
-}
-
-inline void
 FrameState::syncAndForgetEverything(uint32 newStackDepth)
 {
     syncAndForgetEverything();
     sp = spBase + newStackDepth;
 }
 
 inline FrameEntry *
 FrameState::rawPush()
@@ -258,17 +224,17 @@ FrameState::pushSynced(JSValueType type,
 {
     FrameEntry *fe = rawPush();
 
     fe->resetUnsynced();
     fe->type.sync();
     fe->data.sync();
     fe->setType(type);
     fe->data.setRegister(reg);
-    regstate[reg].associate(fe, RematInfo::DATA);
+    regstate(reg).associate(fe, RematInfo::DATA);
 }
 
 inline void
 FrameState::push(Address address, JSValueType knownType)
 {
     if (knownType == JSVAL_TYPE_DOUBLE) {
         FPRegisterID fpreg = allocFPReg();
         masm.moveInt32OrDouble(address, fpreg);
@@ -311,47 +277,47 @@ FrameState::pushRegs(RegisterID type, Re
 {
     JS_ASSERT(!freeRegs.hasReg(type) && !freeRegs.hasReg(data));
 
     if (knownType == JSVAL_TYPE_UNKNOWN) {
         FrameEntry *fe = rawPush();
         fe->resetUnsynced();
         fe->type.setRegister(type);
         fe->data.setRegister(data);
-        regstate[type].associate(fe, RematInfo::TYPE);
-        regstate[data].associate(fe, RematInfo::DATA);
-        return FPRegisters::ConversionTemp;
+        regstate(type).associate(fe, RematInfo::TYPE);
+        regstate(data).associate(fe, RematInfo::DATA);
+        return Registers::FPConversionTemp;
     }
 
     if (knownType == JSVAL_TYPE_DOUBLE) {
         FPRegisterID fpreg = allocFPReg();
         masm.moveInt32OrDouble(data, type, addressOf(sp), fpreg);
         pushDouble(fpreg);
         freeReg(type);
         freeReg(data);
         return fpreg;
     }
 
     freeReg(type);
     pushTypedPayload(knownType, data);
-    return FPRegisters::ConversionTemp;
+    return Registers::FPConversionTemp;
 }
 
 inline void
 FrameState::pushTypedPayload(JSValueType type, RegisterID payload)
 {
     JS_ASSERT(type != JSVAL_TYPE_DOUBLE);
     JS_ASSERT(!freeRegs.hasReg(payload));
 
     FrameEntry *fe = rawPush();
 
     fe->resetUnsynced();
     fe->setType(type);
     fe->data.setRegister(payload);
-    regstate[payload].associate(fe, RematInfo::DATA);
+    regstate(payload).associate(fe, RematInfo::DATA);
 }
 
 inline void
 FrameState::pushNumber(RegisterID payload, bool asInt32)
 {
     JS_ASSERT(!freeRegs.hasReg(payload));
 
     FrameEntry *fe = rawPush();
@@ -362,31 +328,31 @@ FrameState::pushNumber(RegisterID payloa
             masm.storeTypeTag(ImmType(JSVAL_TYPE_INT32), addressOf(fe));
         fe->type.setMemory();
     } else {
         fe->type.setMemory();
     }
 
     fe->data.unsync();
     fe->data.setRegister(payload);
-    regstate[payload].associate(fe, RematInfo::DATA);
+    regstate(payload).associate(fe, RematInfo::DATA);
 }
 
 inline void
 FrameState::pushInt32(RegisterID payload)
 {
     FrameEntry *fe = rawPush();
     fe->clear();
 
     masm.storeTypeTag(ImmType(JSVAL_TYPE_INT32), addressOf(fe));
     fe->type.setMemory();
 
     fe->data.unsync();
     fe->data.setRegister(payload);
-    regstate[payload].associate(fe, RematInfo::DATA);
+    regstate(payload).associate(fe, RematInfo::DATA);
 }
 
 inline void
 FrameState::pushInitializerObject(RegisterID payload, bool array, JSObject *baseobj)
 {
     pushTypedPayload(JSVAL_TYPE_OBJECT, payload);
 
     FrameEntry *fe = peek(-1);
@@ -409,23 +375,23 @@ FrameState::pushUntypedPayload(JSValueTy
 #ifdef DEBUG
     fe->type.unsync();
 #endif
     fe->type.setMemory();
     fe->data.unsync();
     fe->setNotCopied();
     fe->setCopyOf(NULL);
     fe->data.setRegister(payload);
-    regstate[payload].associate(fe, RematInfo::DATA);
+    regstate(payload).associate(fe, RematInfo::DATA);
 }
 
 inline JSC::MacroAssembler::RegisterID
 FrameState::tempRegForType(FrameEntry *fe, RegisterID fallback)
 {
-    JS_ASSERT(!regstate[fallback].fe());
+    JS_ASSERT(!regstate(fallback).fe());
     if (fe->isCopy())
         fe = fe->copyOf();
 
     JS_ASSERT(!fe->type.isConstant());
 
     if (fe->type.inRegister())
         return fe->type.reg();
 
@@ -444,17 +410,17 @@ FrameState::tempRegForType(FrameEntry *f
 
     JS_ASSERT(!fe->type.isConstant());
 
     if (fe->type.inRegister())
         return fe->type.reg();
 
     /* :XXX: X86 */
 
-    RegisterID reg = allocReg(fe, RematInfo::TYPE);
+    RegisterID reg = allocReg(fe, false, RematInfo::TYPE).reg();
     masm.loadTypeTag(addressOf(fe), reg);
     fe->type.setRegister(reg);
     return reg;
 }
 
 inline JSC::MacroAssembler::RegisterID
 FrameState::tempRegForData(FrameEntry *fe)
 {
@@ -462,17 +428,17 @@ FrameState::tempRegForData(FrameEntry *f
     JS_ASSERT(!fe->isType(JSVAL_TYPE_DOUBLE));
 
     if (fe->isCopy())
         fe = fe->copyOf();
 
     if (fe->data.inRegister())
         return fe->data.reg();
 
-    RegisterID reg = allocReg(fe, RematInfo::DATA);
+    RegisterID reg = allocReg(fe, false, RematInfo::DATA).reg();
     masm.loadPayload(addressOf(fe), reg);
     fe->data.setRegister(reg);
     return reg;
 }
 
 inline JSC::MacroAssembler::FPRegisterID
 FrameState::tempFPRegForData(FrameEntry *fe)
 {
@@ -480,49 +446,48 @@ FrameState::tempFPRegForData(FrameEntry 
     JS_ASSERT(fe->isType(JSVAL_TYPE_DOUBLE));
 
     if (fe->isCopy())
         fe = fe->copyOf();
 
     if (fe->data.inFPRegister())
         return fe->data.fpreg();
 
-    FPRegisterID reg = allocFPReg();
+    FPRegisterID reg = allocReg(fe, true, RematInfo::DATA).fpreg();
     masm.loadDouble(addressOf(fe), reg);
-
-    setFPRegister(fe, reg);
-
+    fe->data.setFPRegister(reg);
     return reg;
 }
 
 inline JSC::MacroAssembler::RegisterID
 FrameState::tempRegInMaskForData(FrameEntry *fe, uint32 mask)
 {
     JS_ASSERT(!fe->data.isConstant());
     JS_ASSERT(!fe->isType(JSVAL_TYPE_DOUBLE));
+    JS_ASSERT(!(mask & ~Registers::AvailRegs));
 
     if (fe->isCopy())
         fe = fe->copyOf();
 
     RegisterID reg;
     if (fe->data.inRegister()) {
         RegisterID old = fe->data.reg();
         if (Registers::maskReg(old) & mask)
             return old;
 
         /* Keep the old register pinned. */
-        regstate[old].forget();
-        reg = allocReg(mask);
+        regstate(old).forget();
+        reg = allocReg(mask).reg();
         masm.move(old, reg);
         freeReg(old);
     } else {
-        reg = allocReg(mask);
+        reg = allocReg(mask).reg();
         masm.loadPayload(addressOf(fe), reg);
     }
-    regstate[reg].associate(fe, RematInfo::DATA);
+    regstate(reg).associate(fe, RematInfo::DATA);
     fe->data.setRegister(reg);
     return reg;
 }
 
 inline JSC::MacroAssembler::RegisterID
 FrameState::tempRegForData(FrameEntry *fe, RegisterID reg, Assembler &masm) const
 {
     JS_ASSERT(!fe->data.isConstant());
@@ -567,18 +532,18 @@ FrameState::ensureFeSynced(const FrameEn
         }
         if (backing->isConstant()) {
             masm.storeValue(backing->getValue(), to);
         } else if (backing->data.inFPRegister()) {
             masm.storeDouble(backing->data.fpreg(), to);
         } else {
             /* Use a temporary so the entry can be synced without allocating a register. */
             JS_ASSERT(backing->data.inMemory() && backing != fe);
-            masm.loadDouble(addressOf(backing), FPRegisters::ConversionTemp);
-            masm.storeDouble(FPRegisters::ConversionTemp, to);
+            masm.loadDouble(addressOf(backing), Registers::FPConversionTemp);
+            masm.storeDouble(Registers::FPConversionTemp, to);
         }
         return;
     }
 
 #if defined JS_PUNBOX64
     /* If we can, sync the type and data in one go. */
     if (!fe->data.synced() && !fe->type.synced()) {
         if (backing->isConstant())
@@ -815,17 +780,17 @@ FrameState::learnType(FrameEntry *fe, JS
 {
     forgetAllRegs(fe);
     fe->setCopyOf(NULL);
 
     fe->type.setConstant();
     fe->knownType = type;
 
     fe->data.setRegister(data);
-    regstate[data].associate(fe, RematInfo::DATA);
+    regstate(data).associate(fe, RematInfo::DATA);
 
     fe->data.unsync();
     fe->type.unsync();
 }
 
 inline JSC::MacroAssembler::Address
 FrameState::addressOf(const FrameEntry *fe) const
 {
@@ -965,29 +930,29 @@ FrameState::getCallee()
         callee_->setType(JSVAL_TYPE_OBJECT);
     }
     return callee_;
 }
 
 inline void
 FrameState::unpinKilledReg(RegisterID reg)
 {
-    regstate[reg].unpinUnsafe();
+    regstate(reg).unpinUnsafe();
     freeRegs.putReg(reg);
 }
 
 inline void
 FrameState::forgetAllRegs(FrameEntry *fe)
 {
     if (fe->type.inRegister())
         forgetReg(fe->type.reg());
     if (fe->data.inRegister())
         forgetReg(fe->data.reg());
     if (fe->data.inFPRegister())
-        forgetFPReg(fe->data.fpreg());
+        forgetReg(fe->data.fpreg());
 }
 
 inline void
 FrameState::swapInTracker(FrameEntry *lhs, FrameEntry *rhs)
 {
     uint32 li = lhs->trackerIndex();
     uint32 ri = rhs->trackerIndex();
     JS_ASSERT(tracker[li] == lhs);
@@ -1194,28 +1159,16 @@ FrameState::loadDouble(FrameEntry *fe, F
 
     if (tryFastDoubleLoad(fe, fpReg, masm))
         return;
 
     ensureFeSynced(fe, masm);
     masm.loadDouble(addressOf(fe), fpReg);
 }
 
-void
-FrameState::setFPRegister(FrameEntry *fe, FPRegisterID fpreg, bool reassociate)
-{
-    fe->type.setConstant();
-    fe->knownType = JSVAL_TYPE_DOUBLE;
-    fe->data.setFPRegister(fpreg);
-    if (reassociate)
-        fpregstate[fpreg].reassociate(fe);
-    else
-        fpregstate[fpreg].associate(fe, RematInfo::DATA);
-}
-
 inline bool
 FrameState::isClosedVar(uint32 slot)
 {
     return eval || closedVars[slot];
 }
 
 inline bool
 FrameState::isClosedArg(uint32 slot)
--- a/js/src/methodjit/FrameState.cpp
+++ b/js/src/methodjit/FrameState.cpp
@@ -44,17 +44,17 @@ using namespace js;
 using namespace js::mjit;
 
 /* Because of Value alignment */
 JS_STATIC_ASSERT(sizeof(FrameEntry) % 8 == 0);
 
 FrameState::FrameState(JSContext *cx, JSScript *script, JSFunction *fun, Assembler &masm)
   : cx(cx), script(script), fun(fun),
     nargs(fun ? fun->nargs : 0),
-    masm(masm), entries(NULL),
+    masm(masm), freeRegs(Registers::AvailAnyRegs), entries(NULL),
 #if defined JS_NUNBOX32
     reifier(cx, *thisFromCtor()),
 #endif
     closedVars(NULL),
     closedArgs(NULL),
     usesArguments(script->usesArguments),
     inTryBlock(false)
 {
@@ -124,153 +124,121 @@ FrameState::init()
     return true;
 }
 
 void
 FrameState::takeReg(RegisterID reg)
 {
     if (freeRegs.hasReg(reg)) {
         freeRegs.takeReg(reg);
-        JS_ASSERT(!regstate[reg].usedBy());
+        JS_ASSERT(!regstate(reg).usedBy());
     } else {
-        JS_ASSERT(regstate[reg].fe());
+        JS_ASSERT(regstate(reg).fe());
         evictReg(reg);
-        regstate[reg].forget();
+        regstate(reg).forget();
     }
 }
 
 void
-FrameState::evictReg(RegisterID reg)
+FrameState::evictReg(AnyRegisterID reg)
 {
-    FrameEntry *fe = regstate[reg].fe();
+    FrameEntry *fe = regstate(reg).fe();
 
-    if (regstate[reg].type() == RematInfo::TYPE) {
+    if (regstate(reg).type() == RematInfo::TYPE) {
         ensureTypeSynced(fe, masm);
         fe->type.setMemory();
     } else {
         ensureDataSynced(fe, masm);
         fe->data.setMemory();
     }
 }
 
-JSC::MacroAssembler::RegisterID
+AnyRegisterID
 FrameState::evictSomeReg(uint32 mask)
 {
+    /* Must be looking for a specific type of register. */
+    JS_ASSERT((mask & Registers::AvailRegs) != (mask & Registers::AvailFPRegs));
+
 #ifdef DEBUG
     bool fallbackSet = false;
 #endif
-    RegisterID fallback = Registers::ReturnReg;
+    AnyRegisterID fallback = Registers::ReturnReg;
 
-    for (uint32 i = 0; i < JSC::MacroAssembler::TotalRegisters; i++) {
-        RegisterID reg = RegisterID(i);
+    for (uint32 i = 0; i < Registers::TotalAnyRegisters; i++) {
+        AnyRegisterID reg;
+        reg.reg_ = i;
 
         /* Register is not allocatable, don't bother.  */
         if (!(Registers::maskReg(reg) & mask))
             continue;
 
         /* Register is not owned by the FrameState. */
-        FrameEntry *fe = regstate[i].fe();
+        FrameEntry *fe = regstate(reg).fe();
         if (!fe)
             continue;
 
         /* Try to find a candidate... that doesn't need spilling. */
 #ifdef DEBUG
         fallbackSet = true;
 #endif
         fallback = reg;
 
-        if (regstate[i].type() == RematInfo::TYPE && fe->type.synced()) {
+        if (regstate(reg).type() == RematInfo::TYPE && fe->type.synced()) {
             fe->type.setMemory();
             return fallback;
         }
-        if (regstate[i].type() == RematInfo::DATA && fe->data.synced()) {
+        if (regstate(reg).type() == RematInfo::DATA && fe->data.synced()) {
             fe->data.setMemory();
             return fallback;
         }
     }
 
     JS_ASSERT(fallbackSet);
 
     evictReg(fallback);
     return fallback;
 }
 
-JSC::MacroAssembler::FPRegisterID
-FrameState::evictSomeFPReg()
-{
-#ifdef DEBUG
-    bool fallbackSet = false;
-#endif
-    FPRegisterID fallback = FPRegisterID(0);
-
-    for (uint32 i = 0; i < FPRegisters::TotalFPRegisters; i++) {
-        FPRegisterID reg = FPRegisterID(i);
-
-        FrameEntry *fe = fpregstate[i].fe();
-        if (!fe)
-            continue;
-        JS_ASSERT(fe->isType(JSVAL_TYPE_DOUBLE));
-
-#ifdef DEBUG
-        fallbackSet = true;
-#endif
-        fallback = reg;
-
-        if (fe->data.synced()) {
-            fe->data.setMemory();
-            return fallback;
-        }
-    }
-
-    JS_ASSERT(fallbackSet);
-
-    FrameEntry *fe = fpregstate[fallback].fe();
-    syncFe(fe);
-
-    fe->data.setMemory();
-    return fallback;
-}
-
 void
 FrameState::syncAndForgetEverything()
 {
-    syncAndKill(Registers(Registers::AvailRegs), Uses(frameSlots()));
+    syncAndKill(Registers(Registers::AvailAnyRegs), Uses(frameSlots()));
     forgetEverything();
 }
 
 void
 FrameState::resetInternalState()
 {
     for (uint32 i = 0; i < tracker.nentries; i++)
         tracker[i]->untrack();
 
     tracker.reset();
-    freeRegs.reset();
-    freeFPRegs.reset();
+    freeRegs = Registers(Registers::AvailAnyRegs);
 }
 
 void
 FrameState::discardFrame()
 {
     resetInternalState();
 
-    memset(regstate, 0, sizeof(regstate));
-    memset(fpregstate, 0, sizeof(fpregstate));
+    memset(regstate_, 0, sizeof(regstate_));
 }
 
 void
 FrameState::forgetEverything()
 {
     resetInternalState();
 
 #ifdef DEBUG
-    for (uint32 i = 0; i < JSC::MacroAssembler::TotalRegisters; i++)
-        JS_ASSERT(!regstate[i].usedBy());
-    for (uint32 i = 0; i < FPRegisters::TotalFPRegisters; i++)
-        JS_ASSERT(!fpregstate[i].usedBy());
+    for (uint32 i = 0; i < Registers::TotalAnyRegisters; i++) {
+        AnyRegisterID reg;
+        reg.reg_ = i;
+
+        JS_ASSERT(!regstate(reg).usedBy());
+    }
 #endif
 }
 
 void
 FrameState::storeTo(FrameEntry *fe, Address address, bool popped)
 {
     if (fe->isConstant()) {
         masm.storeValue(fe->getValue(), address);
@@ -290,18 +258,18 @@ FrameState::storeTo(FrameEntry *fe, Addr
 
     if (fe->data.inFPRegister()) {
         masm.storeDouble(fe->data.fpreg(), address);
         return;
     }
 
     if (fe->isType(JSVAL_TYPE_DOUBLE)) {
         JS_ASSERT(fe->data.inMemory());
-        masm.loadDouble(addressOf(fe), FPRegisters::ConversionTemp);
-        masm.storeDouble(FPRegisters::ConversionTemp, address);
+        masm.loadDouble(addressOf(fe), Registers::FPConversionTemp);
+        masm.storeDouble(Registers::FPConversionTemp, address);
         return;
     }
 
 #if defined JS_PUNBOX64
     if (fe->type.inMemory() && fe->data.inMemory()) {
         /* Future optimization: track that the Value is in a register. */
         RegisterID vreg = Registers::ValueReg;
         masm.loadPtr(addressOf(fe), vreg);
@@ -364,32 +332,32 @@ FrameState::storeTo(FrameEntry *fe, Addr
         freeReg(dreg.reg());
 
 #elif defined JS_NUNBOX32
 
     if (fe->data.inRegister()) {
         masm.storePayload(fe->data.reg(), address);
     } else {
         JS_ASSERT(fe->data.inMemory());
-        RegisterID reg = popped ? allocReg() : allocReg(fe, RematInfo::DATA);
+        RegisterID reg = popped ? allocReg() : allocReg(fe, false, RematInfo::DATA).reg();
         masm.loadPayload(addressOf(fe), reg);
         masm.storePayload(reg, address);
         if (popped)
             freeReg(reg);
         else
             fe->data.setRegister(reg);
     }
 
     if (fe->isTypeKnown()) {
         masm.storeTypeTag(ImmType(fe->getKnownType()), address);
     } else if (fe->type.inRegister()) {
         masm.storeTypeTag(fe->type.reg(), address);
     } else {
         JS_ASSERT(fe->type.inMemory());
-        RegisterID reg = popped ? allocReg() : allocReg(fe, RematInfo::TYPE);
+        RegisterID reg = popped ? allocReg() : allocReg(fe, false, RematInfo::TYPE).reg();
         masm.loadTypeTag(addressOf(fe), reg);
         masm.storeTypeTag(reg, address);
         if (popped)
             freeReg(reg);
         else
             fe->type.setRegister(reg);
     }
 #endif
@@ -484,18 +452,17 @@ void FrameState::loadForReturn(FrameEntr
         masm.move(type, typeReg);
     }
 }
 
 #ifdef DEBUG
 void
 FrameState::assertValidRegisterState() const
 {
-    Registers checkedFreeRegs;
-    FPRegisters checkedFreeFPRegs;
+    Registers checkedFreeRegs(Registers::AvailAnyRegs);
 
     for (uint32 i = 0; i < tracker.nentries; i++) {
         FrameEntry *fe = tracker[i];
         if (fe >= sp)
             continue;
 
         JS_ASSERT(i == fe->trackerIndex());
         JS_ASSERT_IF(fe->isCopy(),
@@ -505,43 +472,44 @@ FrameState::assertValidRegisterState() c
                      !fe->type.inRegister() && !fe->data.inRegister() && !fe->data.inFPRegister());
         JS_ASSERT_IF(fe->isCopy(), fe->copyOf() < sp);
         JS_ASSERT_IF(fe->isCopy(), fe->copyOf()->isCopied());
 
         if (fe->isCopy())
             continue;
         if (fe->type.inRegister()) {
             checkedFreeRegs.takeReg(fe->type.reg());
-            JS_ASSERT(regstate[fe->type.reg()].fe() == fe);
+            JS_ASSERT(regstate(fe->type.reg()).fe() == fe);
         }
         if (fe->data.inRegister()) {
             checkedFreeRegs.takeReg(fe->data.reg());
-            JS_ASSERT(regstate[fe->data.reg()].fe() == fe);
+            JS_ASSERT(regstate(fe->data.reg()).fe() == fe);
         }
         if (fe->data.inFPRegister()) {
             JS_ASSERT(fe->isType(JSVAL_TYPE_DOUBLE));
-            checkedFreeFPRegs.takeReg(fe->data.fpreg());
-            JS_ASSERT(fpregstate[fe->data.fpreg()].fe() == fe);
+            checkedFreeRegs.takeReg(fe->data.fpreg());
+            JS_ASSERT(regstate(fe->data.fpreg()).fe() == fe);
         }
     }
 
     JS_ASSERT(checkedFreeRegs == freeRegs);
-    JS_ASSERT(checkedFreeFPRegs == freeFPRegs);
 
-    for (uint32 i = 0; i < JSC::MacroAssembler::TotalRegisters; i++) {
-        JS_ASSERT(!regstate[i].isPinned());
-        JS_ASSERT_IF(regstate[i].fe(), !freeRegs.hasReg(RegisterID(i)));
-        JS_ASSERT_IF(regstate[i].fe(), regstate[i].fe()->isTracked());
+    for (uint32 i = 0; i < Registers::TotalRegisters; i++) {
+        AnyRegisterID reg = (RegisterID) i;
+        JS_ASSERT(!regstate(reg).isPinned());
+        JS_ASSERT_IF(regstate(reg).fe(), !freeRegs.hasReg(reg));
+        JS_ASSERT_IF(regstate(reg).fe(), regstate(reg).fe()->isTracked());
     }
 
-    for (uint32 i = 0; i < FPRegisters::TotalFPRegisters; i++) {
-        JS_ASSERT(!fpregstate[i].isPinned());
-        JS_ASSERT_IF(fpregstate[i].fe(), !freeFPRegs.hasReg(FPRegisterID(i)));
-        JS_ASSERT_IF(fpregstate[i].fe(), fpregstate[i].fe()->isTracked());
-        JS_ASSERT_IF(fpregstate[i].fe(), fpregstate[i].type() == RematInfo::DATA);
+    for (uint32 i = 0; i < Registers::TotalFPRegisters; i++) {
+        AnyRegisterID reg = (FPRegisterID) i;
+        JS_ASSERT(!regstate(reg).isPinned());
+        JS_ASSERT_IF(regstate(reg).fe(), !freeRegs.hasReg(reg));
+        JS_ASSERT_IF(regstate(reg).fe(), regstate(reg).fe()->isTracked());
+        JS_ASSERT_IF(regstate(reg).fe(), regstate(reg).type() == RematInfo::DATA);
     }
 }
 #endif
 
 #if defined JS_NUNBOX32
 void
 FrameState::syncFancy(Assembler &masm, Registers avail, FrameEntry *resumeAt,
                       FrameEntry *bottom) const
@@ -559,67 +527,54 @@ FrameState::syncFancy(Assembler &masm, R
 
 void
 FrameState::sync(Assembler &masm, Uses uses) const
 {
     if (!entries)
         return;
 
     /* Sync all registers up-front. */
-    Registers allRegs(Registers::AvailRegs);
+    Registers allRegs(Registers::AvailAnyRegs);
     while (!allRegs.empty()) {
-        RegisterID reg = allRegs.takeAnyReg();
-        FrameEntry *fe = regstate[reg].usedBy();
+        AnyRegisterID reg = allRegs.takeAnyReg();
+        FrameEntry *fe = regstate(reg).usedBy();
         if (!fe)
             continue;
 
         JS_ASSERT(fe->isTracked());
 
 #if defined JS_PUNBOX64
         /* Sync entire FE to prevent loads. */
         ensureFeSynced(fe, masm);
 
         /* Take the other register in the pair, if one exists. */
-        if (regstate[reg].type() == RematInfo::DATA && fe->type.inRegister())
+        if (regstate(reg).type() == RematInfo::DATA && fe->type.inRegister())
             allRegs.takeReg(fe->type.reg());
-        else if (regstate[reg].type() == RematInfo::TYPE && fe->data.inRegister())
+        else if (regstate(reg).type() == RematInfo::TYPE && fe->data.inRegister())
             allRegs.takeReg(fe->data.reg());
 #elif defined JS_NUNBOX32
         /* Sync register if unsynced. */
-        if (regstate[reg].type() == RematInfo::DATA) {
-            JS_ASSERT(fe->data.reg() == reg);
+        if (fe->isType(JSVAL_TYPE_DOUBLE)) {
+            ensureFeSynced(fe, masm);
+        } else if (regstate(reg).type() == RematInfo::DATA) {
+            JS_ASSERT(fe->data.reg() == reg.reg());
             ensureDataSynced(fe, masm);
         } else {
-            JS_ASSERT(fe->type.reg() == reg);
+            JS_ASSERT(fe->type.reg() == reg.reg());
             ensureTypeSynced(fe, masm);
         }
 #endif
     }
 
-    /* Floating point registers are all volatile, so they are always synced for calls. */
-    for (unsigned i = 0; i < FPRegisters::TotalFPRegisters; i++) {
-        if (freeFPRegs.hasReg(FPRegisterID(i)))
-            continue;
-
-        FrameEntry *fe = fpregstate[i].fe();
-        if (!fe)
-            continue;
-
-        JS_ASSERT(fe->isType(JSVAL_TYPE_DOUBLE));
-        JS_ASSERT(fpregstate[i].type() == RematInfo::DATA);
-
-        ensureFeSynced(fe, masm);
-    }
-
     /*
      * Keep track of free registers using a bitmask. If we have to drop into
      * syncFancy(), then this mask will help avoid eviction.
      */
-    Registers avail(freeRegs);
-    Registers temp(Registers::TempRegs);
+    Registers avail(freeRegs.freeMask & Registers::AvailRegs);
+    Registers temp(Registers::TempAnyRegs);
 
     FrameEntry *bottom = sp - uses.nuses;
 
     for (FrameEntry *fe = sp - 1; fe >= bottom; fe--) {
         if (!fe->isTracked())
             continue;
 
         if (fe->isType(JSVAL_TYPE_DOUBLE)) {
@@ -703,49 +658,53 @@ FrameState::sync(Assembler &masm, Uses u
 void
 FrameState::syncAndKill(Registers kill, Uses uses, Uses ignore)
 {
     FrameEntry *spStop = sp - ignore.nuses;
 
     /* Sync all kill-registers up-front. */
     Registers search(kill.freeMask & ~freeRegs.freeMask);
     while (!search.empty()) {
-        RegisterID reg = search.takeAnyReg();
-        FrameEntry *fe = regstate[reg].usedBy();
+        AnyRegisterID reg = search.takeAnyReg();
+        FrameEntry *fe = regstate(reg).usedBy();
         if (!fe || fe >= spStop)
             continue;
 
         JS_ASSERT(fe->isTracked());
 
 #if defined JS_PUNBOX64
         /* Don't use syncFe(), since that may clobber more registers. */
         ensureFeSynced(fe, masm);
 
         if (!fe->type.synced())
             fe->type.sync();
         if (!fe->data.synced())
             fe->data.sync();
 
         /* Take the other register in the pair, if one exists. */
-        if (regstate[reg].type() == RematInfo::DATA) {
-            JS_ASSERT(fe->data.reg() == reg);
-            if (fe->type.inRegister() && search.hasReg(fe->type.reg()))
-                search.takeReg(fe->type.reg());
+        if (regstate(reg).type() == RematInfo::DATA) {
+            if (!fe->isType(JSVAL_TYPE_DOUBLE)) {
+                JS_ASSERT(fe->data.reg() == reg);
+                if (fe->type.inRegister() && search.hasReg(fe->type.reg()))
+                    search.takeReg(fe->type.reg());
+            }
         } else {
             JS_ASSERT(fe->type.reg() == reg);
             if (fe->data.inRegister() && search.hasReg(fe->data.reg()))
                 search.takeReg(fe->data.reg());
         }
 #elif defined JS_NUNBOX32
         /* Sync this register. */
-        if (regstate[reg].type() == RematInfo::DATA) {
-            JS_ASSERT(fe->data.reg() == reg);
+        if (fe->isType(JSVAL_TYPE_DOUBLE)) {
+            syncFe(fe);
+        } else if (regstate(reg).type() == RematInfo::DATA) {
+            JS_ASSERT(fe->data.reg() == reg.reg());
             syncData(fe);
         } else {
-            JS_ASSERT(fe->type.reg() == reg);
+            JS_ASSERT(fe->type.reg() == reg.reg());
             syncType(fe);
         }
 #endif
     }
 
     uint32 maxvisits = tracker.nentries;
     FrameEntry *bottom = sp - uses.nuses;
 
@@ -757,72 +716,55 @@ FrameState::syncAndKill(Registers kill, 
 
         if (fe >= spStop)
             continue;
 
         syncFe(fe);
 
         /* Forget registers. */
         if (fe->data.inRegister() && kill.hasReg(fe->data.reg()) &&
-            !regstate[fe->data.reg()].isPinned()) {
+            !regstate(fe->data.reg()).isPinned()) {
             forgetReg(fe->data.reg());
             fe->data.setMemory();
         }
         if (fe->type.inRegister() && kill.hasReg(fe->type.reg()) &&
-            !regstate[fe->type.reg()].isPinned()) {
+            !regstate(fe->type.reg()).isPinned()) {
             forgetReg(fe->type.reg());
             fe->type.setMemory();
         }
     }
 
     /*
      * Anything still alive at this point is guaranteed to be synced. However,
      * it is necessary to evict temporary registers.
      */
     search = Registers(kill.freeMask & ~freeRegs.freeMask);
     while (!search.empty()) {
-        RegisterID reg = search.takeAnyReg();
-        FrameEntry *fe = regstate[reg].usedBy();
+        AnyRegisterID reg = search.takeAnyReg();
+        FrameEntry *fe = regstate(reg).usedBy();
         if (!fe || fe >= spStop)
             continue;
 
         JS_ASSERT(fe->isTracked());
 
-        if (regstate[reg].type() == RematInfo::DATA) {
-            JS_ASSERT(fe->data.reg() == reg);
+        if (fe->isType(JSVAL_TYPE_DOUBLE)) {
+            JS_ASSERT(fe->data.fpreg() == reg.fpreg());
+            fe->data.setMemory();
+        } else if (regstate(reg).type() == RematInfo::DATA) {
+            JS_ASSERT(fe->data.reg() == reg.reg());
             JS_ASSERT(fe->data.synced());
             fe->data.setMemory();
         } else {
-            JS_ASSERT(fe->type.reg() == reg);
+            JS_ASSERT(fe->type.reg() == reg.reg());
             JS_ASSERT(fe->type.synced());
             fe->type.setMemory();
         }
 
         forgetReg(reg);
     }
-
-
-    /* Floating point registers are all volatile, so they are always synced for calls. */
-    for (unsigned i = 0; i < FPRegisters::TotalFPRegisters; i++) {
-        if (freeFPRegs.hasReg(FPRegisterID(i)))
-            continue;
-
-        FrameEntry *fe = fpregstate[i].fe();
-        if (!fe || fe >= spStop)
-            continue;
-
-        JS_ASSERT(fe && fe->isType(JSVAL_TYPE_DOUBLE));
-        JS_ASSERT(fpregstate[i].type() == RematInfo::DATA);
-
-        syncFe(fe);
-
-        JS_ASSERT(fe->data.synced() && fe->type.synced());
-        fe->data.setMemory();
-        forgetFPReg(FPRegisterID(i));
-    }
 }
 
 void
 FrameState::merge(Assembler &masm, Changes changes) const
 {
     /*
      * For any changed values we are merging back which we consider to be doubles,
      * ensure they actually are doubles.  They must be doubles or ints, but we
@@ -830,42 +772,33 @@ FrameState::merge(Assembler &masm, Chang
      * :FIXME: we check this on OOL stub calls, but not inline stub calls.
      */
     for (unsigned i = 0; i < changes.nchanges; i++) {
         FrameEntry *fe = sp - 1 - i;
         if (fe->isType(JSVAL_TYPE_DOUBLE))
             masm.ensureInMemoryDouble(addressOf(fe));
     }
 
-    for (unsigned i = 0; i < FPRegisters::TotalFPRegisters; i++) {
-        if (freeFPRegs.hasReg(FPRegisterID(i)))
-            continue;
-
-        FrameEntry *fe = fpregstate[i].fe();
-        if (!fe)
-            continue;
+    uint32 mask = Registers::AvailAnyRegs & ~freeRegs.freeMask;
+    Registers search(mask);
 
-        JS_ASSERT(fe->isType(JSVAL_TYPE_DOUBLE));
-        JS_ASSERT(fpregstate[i].type() == RematInfo::DATA);
-
-        masm.loadDouble(addressOf(fe), FPRegisterID(i));
-    }
-
-    Registers search(Registers::AvailRegs & ~freeRegs.freeMask);
-
-    while (!search.empty()) {
-        RegisterID reg = search.peekReg();
-        FrameEntry *fe = regstate[reg].usedBy();
+    while (!search.empty(mask)) {
+        AnyRegisterID reg = search.peekReg(mask);
+        FrameEntry *fe = regstate(reg).usedBy();
 
         if (!fe) {
             search.takeReg(reg);
             continue;
         }
 
-        if (fe->data.inRegister() && fe->type.inRegister()) {
+        if (fe->isType(JSVAL_TYPE_DOUBLE)) {
+            JS_ASSERT(fe->data.fpreg() == reg.fpreg());
+            search.takeReg(fe->data.fpreg());
+            masm.loadDouble(addressOf(fe), fe->data.fpreg());
+        } else if (fe->data.inRegister() && fe->type.inRegister()) {
             search.takeReg(fe->data.reg());
             search.takeReg(fe->type.reg());
             masm.loadValueAsComponents(addressOf(fe), fe->type.reg(), fe->data.reg());
         } else {
             if (fe->data.inRegister()) {
                 search.takeReg(fe->data.reg());
                 masm.loadPayload(addressOf(fe), fe->data.reg());
             }
@@ -892,26 +825,26 @@ FrameState::copyDataIntoReg(FrameEntry *
     if (fe->isCopy())
         fe = fe->copyOf();
 
     if (!fe->data.inRegister())
         tempRegForData(fe);
 
     RegisterID reg = fe->data.reg();
     if (reg == hint) {
-        if (freeRegs.empty()) {
+        if (freeRegs.empty(Registers::AvailRegs)) {
             ensureDataSynced(fe, masm);
             fe->data.setMemory();
         } else {
             reg = allocReg();
             masm.move(hint, reg);
             fe->data.setRegister(reg);
-            regstate[reg].associate(regstate[hint].fe(), RematInfo::DATA);
+            regstate(reg).associate(regstate(hint).fe(), RematInfo::DATA);
         }
-        regstate[hint].forget();
+        regstate(hint).forget();
     } else {
         pinReg(reg);
         takeReg(hint);
         unpinReg(reg);
         masm.move(reg, hint);
     }
 }
 
@@ -920,31 +853,31 @@ FrameState::copyDataIntoReg(Assembler &m
 {
     JS_ASSERT(!fe->data.isConstant());
 
     if (fe->isCopy())
         fe = fe->copyOf();
 
     if (fe->data.inRegister()) {
         RegisterID reg = fe->data.reg();
-        if (freeRegs.empty()) {
+        if (freeRegs.empty(Registers::AvailRegs)) {
             ensureDataSynced(fe, masm);
             fe->data.setMemory();
-            regstate[reg].forget();
+            regstate(reg).forget();
         } else {
             RegisterID newReg = allocReg();
             masm.move(reg, newReg);
             reg = newReg;
         }
         return reg;
     }
 
     RegisterID reg = allocReg();
 
-    if (!freeRegs.empty())
+    if (!freeRegs.empty(Registers::AvailRegs))
         masm.move(tempRegForData(fe), reg);
     else
         masm.loadPayload(addressOf(fe),reg);
 
     return reg;
 }
 
 JSC::MacroAssembler::RegisterID
@@ -952,31 +885,31 @@ FrameState::copyTypeIntoReg(FrameEntry *
 {
     JS_ASSERT(!fe->type.isConstant());
 
     if (fe->isCopy())
         fe = fe->copyOf();
 
     if (fe->type.inRegister()) {
         RegisterID reg = fe->type.reg();
-        if (freeRegs.empty()) {
+        if (freeRegs.empty(Registers::AvailRegs)) {
             ensureTypeSynced(fe, masm);
             fe->type.setMemory();
-            regstate[reg].forget();
+            regstate(reg).forget();
         } else {
             RegisterID newReg = allocReg();
             masm.move(reg, newReg);
             reg = newReg;
         }
         return reg;
     }
 
     RegisterID reg = allocReg();
 
-    if (!freeRegs.empty())
+    if (!freeRegs.empty(Registers::AvailRegs))
         masm.move(tempRegForType(fe), reg);
     else
         masm.loadTypeTag(addressOf(fe), reg);
 
     return reg;
 }
 
 JSC::MacroAssembler::RegisterID
@@ -1007,36 +940,36 @@ FrameState::ownRegForType(FrameEntry *fe
     if (fe->isCopy()) {
         /* For now, just do an extra move. The reg must be mutable. */
         FrameEntry *backing = fe->copyOf();
         if (!backing->type.inRegister()) {
             JS_ASSERT(backing->type.inMemory());
             tempRegForType(backing);
         }
 
-        if (freeRegs.empty()) {
+        if (freeRegs.empty(Registers::AvailRegs)) {
             /* For now... just steal the register that already exists. */
             ensureTypeSynced(backing, masm);
             reg = backing->type.reg();
             backing->type.setMemory();
-            regstate[reg].forget();
+            regstate(reg).forget();
         } else {
             reg = allocReg();
             masm.move(backing->type.reg(), reg);
         }
         return reg;
     }
 
     if (fe->type.inRegister()) {
         reg = fe->type.reg();
 
         /* Remove ownership of this register. */
-        JS_ASSERT(regstate[reg].fe() == fe);
-        JS_ASSERT(regstate[reg].type() == RematInfo::TYPE);
-        regstate[reg].forget();
+        JS_ASSERT(regstate(reg).fe() == fe);
+        JS_ASSERT(regstate(reg).type() == RematInfo::TYPE);
+        regstate(reg).forget();
         fe->type.invalidate();
     } else {
         JS_ASSERT(fe->type.inMemory());
         reg = allocReg();
         masm.loadTypeTag(addressOf(fe), reg);
     }
     return reg;
 }
@@ -1051,22 +984,22 @@ FrameState::ownRegForData(FrameEntry *fe
     if (fe->isCopy()) {
         /* For now, just do an extra move. The reg must be mutable. */
         FrameEntry *backing = fe->copyOf();
         if (!backing->data.inRegister()) {
             JS_ASSERT(backing->data.inMemory());
             tempRegForData(backing);
         }
 
-        if (freeRegs.empty()) {
+        if (freeRegs.empty(Registers::AvailRegs)) {
             /* For now... just steal the register that already exists. */
             ensureDataSynced(backing, masm);
             reg = backing->data.reg();
             backing->data.setMemory();
-            regstate[reg].forget();
+            regstate(reg).forget();
         } else {
             reg = allocReg();
             masm.move(backing->data.reg(), reg);
         }
         return reg;
     }
 
     if (fe->isCopied()) {
@@ -1076,19 +1009,19 @@ FrameState::ownRegForData(FrameEntry *fe
             fe->data.invalidate();
             return copyDataIntoReg(copy);
         }
     }
     
     if (fe->data.inRegister()) {
         reg = fe->data.reg();
         /* Remove ownership of this register. */
-        JS_ASSERT(regstate[reg].fe() == fe);
-        JS_ASSERT(regstate[reg].type() == RematInfo::DATA);
-        regstate[reg].forget();
+        JS_ASSERT(regstate(reg).fe() == fe);
+        JS_ASSERT(regstate(reg).type() == RematInfo::DATA);
+        regstate(reg).forget();
         fe->data.invalidate();
     } else {
         JS_ASSERT(fe->data.inMemory());
         reg = allocReg();
         masm.loadPayload(addressOf(fe), reg);
     }
     return reg;
 }
@@ -1101,28 +1034,27 @@ FrameState::discardFe(FrameEntry *fe)
     fe->data.setMemory();
 }
 
 void
 FrameState::pushDouble(FPRegisterID fpreg)
 {
     FrameEntry *fe = rawPush();
     fe->resetUnsynced();
-    setFPRegister(fe, fpreg);
+    fe->setType(JSVAL_TYPE_DOUBLE);
+    fe->data.setFPRegister(fpreg);
+    regstate(fpreg).associate(fe, RematInfo::DATA);
 }
 
 void
 FrameState::pushDouble(Address address)
 {
     FPRegisterID fpreg = allocFPReg();
     masm.loadDouble(address, fpreg);
-
-    FrameEntry *fe = rawPush();
-    fe->resetUnsynced();
-    setFPRegister(fe, fpreg);
+    pushDouble(fpreg);
 }
 
 void
 FrameState::ensureDouble(FrameEntry *fe)
 {
     if (fe->isConstant()) {
         JS_ASSERT(fe->getValue().isInt32());
         Value newValue = DoubleValue(double(fe->getValue().toInt32()));
@@ -1144,37 +1076,32 @@ FrameState::ensureDouble(FrameEntry *fe)
         return;
     }
 
     if (fe != backing) {
         /* Forget this entry is a copy.  We are converting this entry, not the backing. */
         fe->clear();
     }
 
+    FPRegisterID fpreg = allocFPReg();
+
     if (backing->isType(JSVAL_TYPE_INT32)) {
         RegisterID data = tempRegForData(backing);
-        FPRegisterID fpreg = allocFPReg();
         masm.convertInt32ToDouble(data, fpreg);
-
-        forgetAllRegs(fe);
-        setFPRegister(fe, fpreg);
-        fe->data.unsync();
-        fe->type.unsync();
-        return;
+    } else {
+        syncFe(backing);
+        masm.moveInt32OrDouble(addressOf(backing), fpreg);
     }
 
-    syncFe(backing);
-
-    if (fe == backing)
-        forgetAllRegs(backing);
+    forgetAllRegs(fe);
+    fe->resetUnsynced();
+    fe->setType(JSVAL_TYPE_DOUBLE);
+    fe->data.setFPRegister(fpreg);
+    regstate(fpreg).associate(fe, RematInfo::DATA);
 
-    FPRegisterID fpreg = allocFPReg();
-    masm.moveInt32OrDouble(addressOf(backing), fpreg);
-
-    setFPRegister(fe, fpreg);
     fe->data.unsync();
     fe->type.unsync();
     return;
 }
 
 void
 FrameState::pushCopyOf(uint32 index)
 {
@@ -1351,33 +1278,33 @@ FrameState::uncopy(FrameEntry *original)
          * If the copy is unsynced, and the original is in memory,
          * give the original a register. We do this below too; it's
          * okay if it's spilled.
          */
         if (original->type.inMemory() && !fe->type.synced())
             tempRegForType(original);
         fe->type.inherit(original->type);
         if (fe->type.inRegister())
-            regstate[fe->type.reg()].reassociate(fe);
+            regstate(fe->type.reg()).reassociate(fe);
     } else {
         JS_ASSERT(fe->isTypeKnown());
         JS_ASSERT(fe->getKnownType() == original->getKnownType());
     }
     if (original->isType(JSVAL_TYPE_DOUBLE)) {
         if (original->data.inMemory() && !fe->data.synced())
             tempFPRegForData(original);
         fe->data.inherit(original->data);
         if (fe->data.inFPRegister())
-            fpregstate[fe->data.fpreg()].reassociate(fe);
+            regstate(fe->data.fpreg()).reassociate(fe);
     } else {
         if (original->data.inMemory() && !fe->data.synced())
             tempRegForData(original);
         fe->data.inherit(original->data);
         if (fe->data.inRegister())
-            regstate[fe->data.reg()].reassociate(fe);
+            regstate(fe->data.reg()).reassociate(fe);
     }
 
     return fe;
 }
 
 void
 FrameState::finishStore(FrameEntry *fe, bool closed)
 {
@@ -1533,45 +1460,50 @@ FrameState::storeTop(FrameEntry *target,
 
     if (backing->isType(JSVAL_TYPE_DOUBLE)) {
         FPRegisterID fpreg = tempFPRegForData(backing);
         if (type == JSVAL_TYPE_UNKNOWN) {
             masm.storeDouble(fpreg, addressOf(target));
             target->resetSynced();
 
             /* We're about to invalidate the backing, so forget the FP register. */
-            forgetFPReg(fpreg);
+            forgetReg(fpreg);
         } else {
             JS_ASSERT(type == JSVAL_TYPE_DOUBLE);
-            target->resetUnsynced();
-            setFPRegister(target, fpreg, true);
+            target->setType(JSVAL_TYPE_DOUBLE);
+            target->data.setFPRegister(fpreg);
+            regstate(fpreg).reassociate(target);
         }
     } else {
         /*
          * Move the backing store down - we spill registers here, but we could be
          * smarter and re-use the type reg.
          */
         RegisterID reg = tempRegForData(backing);
         target->data.setRegister(reg);
-        regstate[reg].reassociate(target);
+        regstate(reg).reassociate(target);
 
         if (type == JSVAL_TYPE_UNKNOWN) {
             if (backing->isTypeKnown()) {
                 target->setType(backing->getKnownType());
             } else {
                 RegisterID reg = tempRegForType(backing);
                 target->type.setRegister(reg);
-                regstate[reg].reassociate(target);
+                regstate(reg).reassociate(target);
             }
         } else if (type == JSVAL_TYPE_DOUBLE) {
             JS_ASSERT(backing->isType(JSVAL_TYPE_INT32));
 
             FPRegisterID fpreg = allocFPReg();
             masm.convertInt32ToDouble(reg, fpreg);
-            setFPRegister(target, fpreg);
+
+            target->setType(JSVAL_TYPE_DOUBLE);
+            target->data.setFPRegister(fpreg);
+            regstate(fpreg).associate(target, RematInfo::DATA);
+
             forgetReg(reg);
         } else {
             /*
              * The backing should normally already be the type we are storing.  However,
              * we do not always keep track of the type in fused opcodes like GETTHISPROP.
              */
             JS_ASSERT_IF(backing->isTypeKnown(), backing->isType(type));
             if (!backing->isTypeKnown())
@@ -1627,19 +1559,19 @@ FrameState::forgetKnownDouble(FrameEntry
      * contents.  We currently need to do this in order to use the entry in MICs/PICs
      * or to construct its ValueRemat. :FIXME: this needs to get fixed.
      */
     JS_ASSERT(!fe->isConstant() && fe->isType(JSVAL_TYPE_DOUBLE));
 
     FPRegisterID fpreg = tempFPRegForData(fe);
     forgetAllRegs(fe);
     fe->resetUnsynced();
-    RegisterID typeReg = allocReg(fe, RematInfo::TYPE);
+    RegisterID typeReg = allocReg(fe, false, RematInfo::TYPE).reg();
     pinReg(typeReg);
-    RegisterID dataReg = allocReg(fe, RematInfo::DATA);
+    RegisterID dataReg = allocReg(fe, false, RematInfo::DATA).reg();
     unpinReg(typeReg);
     masm.breakDouble(fpreg, typeReg, dataReg);
     fe->type.setRegister(typeReg);
     fe->data.setRegister(dataReg);
 }
 
 void
 FrameState::pinEntry(FrameEntry *fe, ValueRemat &vr)
@@ -1723,17 +1655,17 @@ FrameState::allocForSameBinary(FrameEntr
 
     if (!fe->isTypeKnown()) {
         alloc.lhsType = tempRegForType(fe);
         pinReg(alloc.lhsType.reg());
     }
 
     alloc.lhsData = tempRegForData(fe);
 
-    if (!freeRegs.empty()) {
+    if (!freeRegs.empty(Registers::AvailRegs)) {
         alloc.result = allocReg();
         masm.move(alloc.lhsData.reg(), alloc.result);
         alloc.lhsNeedsRemat = false;
     } else {
         alloc.result = alloc.lhsData.reg();
         takeReg(alloc.result);
         alloc.lhsNeedsRemat = true;
     }
@@ -1893,17 +1825,17 @@ FrameState::allocForBinary(FrameEntry *l
         goto skip;
 
     /*
      * Now a result register is needed. It must contain a mutable copy of the
      * LHS. For commutative operations, we can opt to use the RHS instead. At
      * this point, if for some reason either must be in a register, that has
      * already been guaranteed at this point.
      */
-    if (!freeRegs.empty()) {
+    if (!freeRegs.empty(Registers::AvailRegs)) {
         /* Free reg - just grab it. */
         alloc.result = allocReg();
         if (!alloc.lhsData.isSet()) {
             JS_ASSERT(alloc.rhsData.isSet());
             JS_ASSERT(commu);
             masm.move(alloc.rhsData.reg(), alloc.result);
             alloc.resultHasRhs = true;
         } else {
--- a/js/src/methodjit/FrameState.h
+++ b/js/src/methodjit/FrameState.h
@@ -527,31 +527,30 @@ class FrameState
      * address and no register, this returns true.
      */
     inline bool shouldAvoidDataRemat(FrameEntry *fe);
 
     /*
      * Frees a temporary register. If this register is being tracked, then it
      * is not spilled; the backing data becomes invalidated!
      */
-    inline void freeReg(RegisterID reg);
-    inline void freeFPReg(FPRegisterID reg);
+    inline void freeReg(AnyRegisterID reg);
 
     /*
      * Allocates a register. If none are free, one may be spilled from the
      * tracker. If there are none available for spilling in the tracker,
      * then this is considered a compiler bug and an assert will fire.
      */
     inline RegisterID allocReg();
     inline FPRegisterID allocFPReg();
 
     /*
      * Allocates a register, except using a mask.
      */
-    inline RegisterID allocReg(uint32 mask);
+    inline AnyRegisterID allocReg(uint32 mask);
 
     /*
      * Allocates a specific register, evicting it if it's not avaliable.
      */
     void takeReg(RegisterID reg);
 
     /*
      * Returns a FrameEntry * for a slot on the operation stack.
@@ -594,20 +593,21 @@ class FrameState
     void sync(Assembler &masm, Uses uses) const;
 
     /*
      * Syncs all outstanding stores to memory and possibly kills regs in the
      * process.  The top [ignored..uses-1] frame entries will be synced.
      */
     void syncAndKill(Registers kill, Uses uses, Uses ignored);
     void syncAndKill(Registers kill, Uses uses) { syncAndKill(kill, uses, Uses(0)); }
+    void syncAndKill(Uses uses) { syncAndKill(Registers(Registers::AvailAnyRegs), uses, Uses(0)); }
 
     /* Syncs and kills everything. */
     void syncAndKillEverything() {
-        syncAndKill(Registers(Registers::AvailRegs), Uses(frameSlots()));
+        syncAndKill(Registers(Registers::AvailAnyRegs), Uses(frameSlots()));
     }
 
     /*
      * Clear all tracker entries, syncing all outstanding stores in the process.
      * The stack depth is in case some merge points' edges did not immediately
      * precede the current instruction.
      */
     inline void syncAndForgetEverything(uint32 newStackDepth);
@@ -694,24 +694,22 @@ class FrameState
     inline Jump testPrimitive(Assembler::Condition cond, FrameEntry *fe);
 
     /*
      * Marks a register such that it cannot be spilled by the register
      * allocator. Any pinned registers must be unpinned at the end of the op,
      * no matter what. In addition, pinReg() can only be used on registers
      * which are associated with FrameEntries.
      */
-    inline void pinReg(RegisterID reg) { regstate[reg].pin(); }
-    inline void pinFPReg(FPRegisterID reg) { fpregstate[reg].pin(); }
+    inline void pinReg(AnyRegisterID reg) { regstate(reg).pin(); }
 
     /*
      * Unpins a previously pinned register.
      */
-    inline void unpinReg(RegisterID reg) { regstate[reg].unpin(); }
-    inline void unpinFPReg(FPRegisterID reg) { fpregstate[reg].unpin(); }
+    inline void unpinReg(AnyRegisterID reg) { regstate(reg).unpin(); }
 
     /*
      * Same as unpinReg(), but does not restore the FrameEntry.
      */
     inline void unpinKilledReg(RegisterID reg);
 
     /* Pins a data or type register if one exists. */
     MaybeRegisterID maybePinData(FrameEntry *fe);
@@ -794,25 +792,22 @@ class FrameState
     inline void setClosedVar(uint32 slot);
     inline void setClosedArg(uint32 slot);
 
     inline void setInTryBlock(bool inTryBlock) {
         this->inTryBlock = inTryBlock;
     }
 
   private:
-    inline RegisterID allocReg(FrameEntry *fe, RematInfo::RematType type);
-    inline void forgetReg(RegisterID reg);
-    inline void forgetFPReg(FPRegisterID reg);
-    RegisterID evictSomeReg(uint32 mask);
-    FPRegisterID evictSomeFPReg();
-    void evictReg(RegisterID reg);
+    inline AnyRegisterID allocReg(FrameEntry *fe, bool fp, RematInfo::RematType type);
+    inline void forgetReg(AnyRegisterID reg);
+    AnyRegisterID evictSomeReg(uint32 mask);
+    void evictReg(AnyRegisterID reg);
     inline FrameEntry *rawPush();
     inline void addToTracker(FrameEntry *fe);
-    inline void setFPRegister(FrameEntry *fe, FPRegisterID fpreg, bool reassociate = false);
 
     /* Guarantee sync, but do not set any sync flag. */
     inline void ensureFeSynced(const FrameEntry *fe, Assembler &masm) const;
     inline void ensureTypeSynced(const FrameEntry *fe, Assembler &masm) const;
     inline void ensureDataSynced(const FrameEntry *fe, Assembler &masm) const;
 
     /* Guarantee sync, even if register allocation is required, and set sync. */
     inline void syncFe(FrameEntry *fe);
@@ -850,40 +845,51 @@ class FrameState
      */
     void forgetEntry(FrameEntry *fe);
 
     FrameEntry *entryFor(uint32 index) const {
         JS_ASSERT(entries[index].isTracked());
         return &entries[index];
     }
 
-    RegisterID evictSomeReg() { return evictSomeReg(Registers::AvailRegs); }
+    AnyRegisterID evictSomeReg(bool fp) {
+        return evictSomeReg(fp ? Registers::AvailFPRegs : Registers::AvailRegs);
+    }
     uint32 indexOf(int32 depth) const {
         JS_ASSERT(uint32((sp + depth) - entries) < feLimit());
         return uint32((sp + depth) - entries);
     }
     uint32 indexOfFe(FrameEntry *fe) const {
         JS_ASSERT(uint32(fe - entries) < feLimit());
         return uint32(fe - entries);
     }
     uint32 feLimit() const { return script->nslots + nargs + 2; }
 
     inline bool isClosedVar(uint32 slot);
     inline bool isClosedArg(uint32 slot);
 
+    RegisterState & regstate(AnyRegisterID reg) {
+        JS_ASSERT(reg.reg_ < Registers::TotalAnyRegisters);
+        return regstate_[reg.reg_];
+    }
+
+    const RegisterState & regstate(AnyRegisterID reg) const {
+        JS_ASSERT(reg.reg_ < Registers::TotalAnyRegisters);
+        return regstate_[reg.reg_];
+    }
+
   private:
     JSContext *cx;
     JSScript *script;
     JSFunction *fun;
     uint32 nargs;
     Assembler &masm;
 
     /* All allocated registers. */
     Registers freeRegs;
-    FPRegisters freeFPRegs;
 
     /* Cache of FrameEntry objects. */
     FrameEntry *entries;
 
     FrameEntry *callee_;
     FrameEntry *this_;
 
     /* Base pointer for arguments. */
@@ -900,18 +906,17 @@ class FrameState
 
     /* Vector of tracked slot indexes. */
     Tracker tracker;
 
     /*
      * Register ownership state. This can't be used alone; to find whether an
      * entry is active, you must check the allocated registers.
      */
-    RegisterState regstate[Assembler::TotalRegisters];
-    RegisterState fpregstate[FPRegisters::TotalFPRegisters];
+    RegisterState regstate_[Registers::TotalAnyRegisters];
 
 #if defined JS_NUNBOX32
     mutable ImmutableSync reifier;
 #endif
 
     JSPackedBool *closedVars;
     JSPackedBool *closedArgs;
     bool eval;
--- a/js/src/methodjit/ImmutableSync.cpp
+++ b/js/src/methodjit/ImmutableSync.cpp
@@ -43,17 +43,17 @@
 #include "FrameState.h"
 #include "FrameState-inl.h"
 #include "ImmutableSync.h"
 
 using namespace js;
 using namespace js::mjit;
 
 ImmutableSync::ImmutableSync(JSContext *cx, const FrameState &frame)
-  : cx(cx), entries(NULL), frame(frame), generation(0)
+  : cx(cx), entries(NULL), frame(frame), avail(Registers::AvailRegs), generation(0)
 {
 }
 
 ImmutableSync::~ImmutableSync()
 {
     cx->free(entries);
 }
 
@@ -74,57 +74,58 @@ ImmutableSync::reset(Assembler *masm, Re
     this->generation++;
     memset(regs, 0, sizeof(regs));
 }
 
 JSC::MacroAssembler::RegisterID
 ImmutableSync::allocReg()
 {
     if (!avail.empty())
-        return avail.takeAnyReg();
+        return avail.takeAnyReg().reg();
 
     uint32 lastResort = FrameState::InvalidIndex;
     uint32 evictFromFrame = FrameState::InvalidIndex;
 
     /* Find something to evict. */
-    for (uint32 i = 0; i < JSC::MacroAssembler::TotalRegisters; i++) {
+    for (uint32 i = 0; i < Registers::TotalRegisters; i++) {
         RegisterID reg = RegisterID(i);
         if (!(Registers::maskReg(reg) & Registers::AvailRegs))
             continue;
 
         lastResort = 0;
 
         if (!regs[i]) {
             /* If the frame does not own this register, take it! */
-            FrameEntry *fe = frame.regstate[i].usedBy();
+            FrameEntry *fe = frame.regstate(reg).usedBy();
             if (!fe)
                 return reg;
 
             evictFromFrame = i;
 
             /*
              * If not copied, we can sync and not have to load again later.
              * That's about as good as it gets, so just break out now.
              */
             if (!fe->isCopied())
                 break;
         }
     }
 
     if (evictFromFrame != FrameState::InvalidIndex) {
-        FrameEntry *fe = frame.regstate[evictFromFrame].usedBy();
+        RegisterID evict = RegisterID(evictFromFrame);
+        FrameEntry *fe = frame.regstate(evict).usedBy();
         SyncEntry &e = entryFor(fe);
-        if (frame.regstate[evictFromFrame].type() == RematInfo::TYPE) {
+        if (frame.regstate(evict).type() == RematInfo::TYPE) {
             JS_ASSERT(!e.typeClobbered);
             e.typeClobbered = true;
         } else {
             JS_ASSERT(!e.dataClobbered);
             e.dataClobbered = true;
         }
-        return RegisterID(evictFromFrame);
+        return evict;
     }
 
     JS_ASSERT(lastResort != FrameState::InvalidIndex);
     JS_ASSERT(regs[lastResort]);
 
     SyncEntry *e = regs[lastResort];
     RegisterID reg = RegisterID(lastResort);
     if (e->hasDataReg && e->dataReg == reg) {
@@ -258,24 +259,24 @@ ImmutableSync::syncNormal(FrameEntry *fe
             masm->storeTypeTag(ensureTypeReg(fe, e), addr);
     }
 
     if (e.hasDataReg) {
         avail.putReg(e.dataReg);
         regs[e.dataReg] = NULL;
     } else if (!e.dataClobbered &&
                fe->data.inRegister() &&
-               frame.regstate[fe->data.reg()].usedBy()) {
+               frame.regstate(fe->data.reg()).usedBy()) {
         avail.putReg(fe->data.reg());
     }
 
     if (e.hasTypeReg) {
         avail.putReg(e.typeReg);
         regs[e.typeReg] = NULL;
     } else if (!e.typeClobbered &&
                fe->type.inRegister() &&
-               frame.regstate[fe->type.reg()].usedBy()) {
+               frame.regstate(fe->type.reg()).usedBy()) {
         avail.putReg(fe->type.reg());
     }
 }
 
 #endif /* JS_NUNBOX32 */
 
--- a/js/src/methodjit/InlineFrameAssembler.h
+++ b/js/src/methodjit/InlineFrameAssembler.h
@@ -82,26 +82,26 @@ class InlineFrameAssembler {
   public:
     /*
      * Register state, so consumers of this class can restrict which registers
      * can and can't be clobbered.
      */
     Registers  tempRegs;
 
     InlineFrameAssembler(Assembler &masm, ic::CallICInfo &ic, uint32 flags)
-      : masm(masm), pc(ic.pc), flags(flags)
+      : masm(masm), pc(ic.pc), flags(flags), tempRegs(Registers::AvailRegs)
     {
         frameSize = ic.frameSize;
         funObjReg = ic.funObjReg;
         tempRegs.takeReg(ic.funPtrReg);
         tempRegs.takeReg(funObjReg);
     }
 
     InlineFrameAssembler(Assembler &masm, Compiler::CallGenInfo &gen, uint32 flags)
-      : masm(masm), pc(gen.pc), flags(flags)
+      : masm(masm), pc(gen.pc), flags(flags), tempRegs(Registers::AvailRegs)
     {
         frameSize = gen.frameSize;
         funObjReg = gen.funObjReg;
         tempRegs.takeReg(funObjReg);
     }
 
     DataLabelPtr assemble(void *ncode)
     {
@@ -126,17 +126,17 @@ class InlineFrameAssembler {
             /*
              * If the frame size is dynamic, then the fast path generated by
              * generateFullCallStub must be used. Thus, this code is executed
              * after stubs::SplatApplyArgs has been called. SplatApplyArgs
              * stores the dynamic stack pointer (i.e., regs.sp after pushing a
              * dynamic number of arguments) to VMFrame.regs, so we just load it
              * here to get the new frame pointer.
              */
-            RegisterID newfp = tempRegs.takeAnyReg();
+            RegisterID newfp = tempRegs.takeAnyReg().reg();
             masm.loadPtr(FrameAddress(offsetof(VMFrame, regs.sp)), newfp);
 
             Address flagsAddr(newfp, JSStackFrame::offsetOfFlags());
             masm.store32(Imm32(JSFRAME_FUNCTION | flags), flagsAddr);
             Address prevAddr(newfp, JSStackFrame::offsetOfPrev());
             masm.storePtr(JSFrameReg, prevAddr);
             Address ncodeAddr(newfp, JSStackFrame::offsetOfncode());
             ncodePatch = masm.storePtrWithPatch(ImmPtr(ncode), ncodeAddr);
--- a/js/src/methodjit/MachineRegs.h
+++ b/js/src/methodjit/MachineRegs.h
@@ -42,17 +42,47 @@
 
 #include "jsbit.h"
 #include "assembler/assembler/MacroAssembler.h"
 
 namespace js {
 
 namespace mjit {
 
+/* Common handling for both general purpose and floating point registers. */
+
+struct AnyRegisterID {
+    unsigned reg_;
+
+    AnyRegisterID()
+        : reg_((unsigned)-1)
+    {}
+
+    AnyRegisterID(const AnyRegisterID &o)
+        : reg_(o.reg_)
+    {}
+
+    AnyRegisterID(JSC::MacroAssembler::RegisterID reg)
+        : reg_((unsigned)reg)
+    {}
+
+    AnyRegisterID(JSC::MacroAssembler::FPRegisterID reg)
+        : reg_(JSC::MacroAssembler::TotalRegisters + (unsigned)reg)
+    {}
+
+    inline JSC::MacroAssembler::RegisterID reg();
+    inline JSC::MacroAssembler::FPRegisterID fpreg();
+};
+
 struct Registers {
+
+    /* General purpose registers. */
+
+    static const uint32 TotalRegisters = JSC::MacroAssembler::TotalRegisters;
+
     enum CallConvention {
         NormalCall,
         FastCall
     };
 
     typedef JSC::MacroAssembler::RegisterID RegisterID;
 
     // Homed and scratch registers for working with Values on x64.
@@ -235,203 +265,149 @@ struct Registers {
 #endif
         JS_ASSERT(numArgRegs(conv) == JS_ARRAY_LENGTH(regs));
         if (i > JS_ARRAY_LENGTH(regs))
             return false;
         *reg = regs[i];
         return true;
     }
 
-    Registers()
-      : freeMask(AvailRegs)
-    { }
+    /* Floating point registers. */
+
+    typedef JSC::MacroAssembler::FPRegisterID FPRegisterID;
+
+#if defined(JS_CPU_X86) || defined(JS_CPU_X64)
+    static const uint32 TotalFPRegisters = 7;
+    static const uint32 TempFPRegs = (
+          (1 << JSC::X86Registers::xmm0)
+        | (1 << JSC::X86Registers::xmm1)
+        | (1 << JSC::X86Registers::xmm2)
+        | (1 << JSC::X86Registers::xmm3)
+        | (1 << JSC::X86Registers::xmm4)
+        | (1 << JSC::X86Registers::xmm5)
+        | (1 << JSC::X86Registers::xmm6)
+        ) << TotalRegisters;
+    /* For shuffling FP values around, or loading GPRs into a FP reg. */
+    static const FPRegisterID FPConversionTemp = JSC::X86Registers::xmm7;
+#elif defined(JS_CPU_ARM)
+    static const uint32 TotalFPRegisters = 3;
+    static const uint32 TempFPRegs = (
+          (1 << JSC::ARMRegisters::d0)
+        | (1 << JSC::ARMRegisters::d1)
+        | (1 << JSC::ARMRegisters::d2);
+        ) << TotalRegisters;
+    static const FPRegisterID FPConversionTemp = JSC::ARMRegisters::d3;
+#else
+# error "Unsupported platform"
+#endif
+
+    static const uint32 AvailFPRegs = TempFPRegs;
+
+    static inline uint32 maskReg(FPRegisterID reg) {
+        return (1 << reg) << TotalRegisters;
+    }
+
+    /* Common code. */
+
+    static const uint32 TotalAnyRegisters = TotalRegisters + TotalFPRegisters;
+    static const uint32 TempAnyRegs = TempRegs | TempFPRegs;
+    static const uint32 AvailAnyRegs = AvailRegs | AvailFPRegs;
+
+    static inline uint32 maskReg(AnyRegisterID reg) {
+        return (1 << reg.reg_);
+    }
 
     Registers(uint32 freeMask)
       : freeMask(freeMask)
     { }
 
     Registers(const Registers &other)
       : freeMask(other.freeMask)
     { }
 
     Registers & operator =(const Registers &other)
     {
         freeMask = other.freeMask;
         return *this;
     }
 
-    void reset() {
-        freeMask = AvailRegs;
+    bool empty(uint32 mask) const {
+        return !(freeMask & mask);
     }
 
     bool empty() const {
         return !freeMask;
     }
 
-    bool empty(uint32 mask) const {
-        return !(freeMask & mask);
-    }
-
-    RegisterID peekReg() {
-        JS_ASSERT(!empty());
+    AnyRegisterID peekReg(uint32 mask) {
+        JS_ASSERT(!empty(mask));
         int ireg;
-        JS_FLOOR_LOG2(ireg, freeMask);
+        JS_FLOOR_LOG2(ireg, freeMask & mask);
         RegisterID reg = (RegisterID)ireg;
         return reg;
     }
 
-    RegisterID takeAnyReg() {
-        RegisterID reg = peekReg();
+    AnyRegisterID peekReg() {
+        return peekReg(freeMask);
+    }
+
+    AnyRegisterID takeAnyReg(uint32 mask) {
+        AnyRegisterID reg = peekReg(mask);
         takeReg(reg);
         return reg;
     }
 
-    bool hasRegInMask(uint32 mask) const {
-        Registers temp(freeMask & mask);
-        return !temp.empty();
+    AnyRegisterID takeAnyReg() {
+        return takeAnyReg(freeMask);
+    }
+
+    bool hasReg(AnyRegisterID reg) const {
+        return !!(freeMask & (1 << reg.reg_));
     }
 
-    RegisterID takeRegInMask(uint32 mask) {
-        Registers temp(freeMask & mask);
-        RegisterID reg = temp.takeAnyReg();
-        takeReg(reg);
-        return reg;
+    bool hasRegInMask(uint32 mask) const {
+        return !!(freeMask & mask);
     }
 
-    bool hasReg(RegisterID reg) const {
-        return !!(freeMask & (1 << reg));
+    void putRegUnchecked(AnyRegisterID reg) {
+        freeMask |= (1 << reg.reg_);
     }
 
-    void putRegUnchecked(RegisterID reg) {
-        freeMask |= (1 << reg);
-    }
-
-    void putReg(RegisterID reg) {
+    void putReg(AnyRegisterID reg) {
         JS_ASSERT(!hasReg(reg));
         putRegUnchecked(reg);
     }
 
-    void takeReg(RegisterID reg) {
+    void takeReg(AnyRegisterID reg) {
         JS_ASSERT(hasReg(reg));
-        freeMask &= ~(1 << reg);
+        freeMask &= ~(1 << reg.reg_);
     }
 
     bool operator ==(const Registers &other) {
         return freeMask == other.freeMask;
     }
 
     uint32 freeMask;
 };
 
-
-struct FPRegisters {
-
-    typedef JSC::MacroAssembler::FPRegisterID FPRegisterID;
-
-#if defined(JS_CPU_X86) || defined(JS_CPU_X64)
-    static const uint32 TotalFPRegisters = 7;
-    static const uint32 TempFPRegs =
-          (1 << JSC::X86Registers::xmm0)
-        | (1 << JSC::X86Registers::xmm1)
-        | (1 << JSC::X86Registers::xmm2)
-        | (1 << JSC::X86Registers::xmm3)
-        | (1 << JSC::X86Registers::xmm4)
-        | (1 << JSC::X86Registers::xmm5)
-        | (1 << JSC::X86Registers::xmm6);
-    /* For shuffling FP values around, or loading GPRs into a FP reg. */
-    static const FPRegisterID ConversionTemp = JSC::X86Registers::xmm7;
-#elif defined(JS_CPU_ARM)
-    static const uint32 TotalFPRegisters = 3;
-    static const uint32 TempFPRegs = 
-          (1 << JSC::ARMRegisters::d0)
-        | (1 << JSC::ARMRegisters::d1)
-        | (1 << JSC::ARMRegisters::d2);
-    static const FPRegisterID ConversionTemp = JSC::ARMRegisters::d3;
-#else
-# error "Unsupported platform"
-#endif
-
-    static const uint32 AvailFPRegs = TempFPRegs;
-
-    FPRegisters()
-      : freeFPMask(AvailFPRegs)
-    { }
-
-    FPRegisters(uint32 freeFPMask)
-      : freeFPMask(freeFPMask)
-    { }
-
-    FPRegisters(const FPRegisters &other)
-      : freeFPMask(other.freeFPMask)
-    { }
-
-    FPRegisters & operator =(const FPRegisters &other)
-    {
-        freeFPMask = other.freeFPMask;
-        return *this;
-    }
-
-    void reset() {
-        freeFPMask = AvailFPRegs;
-    }
+static const JSC::MacroAssembler::RegisterID JSFrameReg = Registers::JSFrameReg;
 
-    bool empty() const {
-        return !freeFPMask;
-    }
-
-    bool empty(uint32 mask) const {
-        return !(freeFPMask & mask);
-    }
-
-    FPRegisterID takeAnyReg() {
-        JS_ASSERT(!empty());
-        int ireg;
-        JS_FLOOR_LOG2(ireg, freeFPMask);
-        FPRegisterID reg = (FPRegisterID)ireg;
-        takeReg(reg);
-        return reg;
-    }
-
-    bool hasRegInMask(uint32 mask) const {
-        FPRegisters temp(freeFPMask & mask);
-        return !temp.empty();
-    }
+JSC::MacroAssembler::RegisterID
+AnyRegisterID::reg()
+{
+    JS_ASSERT(reg_ < Registers::TotalRegisters);
+    return (JSC::MacroAssembler::RegisterID) reg_;
+}
 
-    FPRegisterID takeRegInMask(uint32 mask) {
-        FPRegisters temp(freeFPMask & mask);
-        FPRegisterID reg = temp.takeAnyReg();
-        takeReg(reg);
-        return reg;
-    }
-
-    bool hasReg(FPRegisterID fpreg) const {
-        return !!(freeFPMask & (1 << fpreg));
-    }
-
-    void putRegUnchecked(FPRegisterID fpreg) {
-        freeFPMask |= (1 << fpreg);
-    }
-
-    void putReg(FPRegisterID fpreg) {
-        JS_ASSERT(!hasReg(fpreg));
-        putRegUnchecked(fpreg);
-    }
-
-    void takeReg(FPRegisterID fpreg) {
-        JS_ASSERT(hasReg(fpreg));
-        freeFPMask &= ~(1 << fpreg);
-    }
-
-    bool operator ==(const FPRegisters &other) {
-        return freeFPMask == other.freeFPMask;
-    }
-
-    uint32 freeFPMask;
-};
-
-static const JSC::MacroAssembler::RegisterID JSFrameReg = Registers::JSFrameReg;
+JSC::MacroAssembler::FPRegisterID
+AnyRegisterID::fpreg()
+{
+    JS_ASSERT(reg_ >= Registers::TotalRegisters &&
+              reg_ < Registers::TotalAnyRegisters);
+    return (JSC::MacroAssembler::FPRegisterID) (reg_ - Registers::TotalRegisters);
+}
 
 } /* namespace mjit */
 
 } /* namespace js */
 
 #endif /* jsjaeger_regstate_h__ */
 
--- a/js/src/methodjit/MonoIC.cpp
+++ b/js/src/methodjit/MonoIC.cpp
@@ -508,17 +508,17 @@ class CallCompiler : public BaseCompiler
         /*
          * Create a stub that works with arity mismatches. Like the fast-path,
          * this allocates a frame on the caller side, but also performs extra
          * checks for compilability. Perhaps this should be a separate, shared
          * trampoline, but for now we generate it dynamically.
          */
         Assembler masm;
         InlineFrameAssembler inlFrame(masm, ic, flags);
-        RegisterID t0 = inlFrame.tempRegs.takeAnyReg();
+        RegisterID t0 = inlFrame.tempRegs.takeAnyReg().reg();
 
         /* Generate the inline frame creation. */
         inlFrame.assemble(ic.funGuard.labelAtOffset(ic.joinPointOffset).executableAddress());
 
         /* funPtrReg is still valid. Check if a compilation is needed. */
         Address scriptAddr(ic.funPtrReg, offsetof(JSFunction, u) +
                            offsetof(JSFunction::U::Scripted, script));
         masm.loadPtr(scriptAddr, t0);
@@ -611,20 +611,20 @@ class CallCompiler : public BaseCompiler
 
     bool generateStubForClosures(JITScript *from, JSObject *obj)
     {
         JS_ASSERT(ic.frameSize.isStatic());
 
         /* Slightly less fast path - guard on fun->getFunctionPrivate() instead. */
         Assembler masm;
 
-        Registers tempRegs;
+        Registers tempRegs(Registers::AvailRegs);
         tempRegs.takeReg(ic.funObjReg);
 
-        RegisterID t0 = tempRegs.takeAnyReg();
+        RegisterID t0 = tempRegs.takeAnyReg().reg();
 
         /* Guard that it's actually a function object. */
         Jump claspGuard = masm.testObjClass(Assembler::NotEqual, ic.funObjReg, &js_FunctionClass);
 
         /* Guard that it's the same function. */
         JSFunction *fun = obj->getFunctionPrivate();
         masm.loadFunctionPrivate(ic.funObjReg, t0);
         Jump funGuard = masm.branchPtr(Assembler::NotEqual, t0, ImmPtr(fun));
@@ -709,23 +709,23 @@ class CallCompiler : public BaseCompiler
         Jump funGuard = masm.branchPtr(Assembler::NotEqual, ic.funObjReg, ImmPtr(obj));
 
         /* N.B. After this call, the frame will have a dynamic frame size. */
         if (ic.frameSize.isDynamic()) {
             masm.fallibleVMCall(JS_FUNC_TO_DATA_PTR(void *, ic::SplatApplyArgs),
                                 f.regs.pc, initialFrameDepth);
         }
 
-        Registers tempRegs;
+        Registers tempRegs(Registers::AvailRegs);
 #ifndef JS_CPU_X86
         tempRegs.takeReg(Registers::ArgReg0);
         tempRegs.takeReg(Registers::ArgReg1);
         tempRegs.takeReg(Registers::ArgReg2);
 #endif
-        RegisterID t0 = tempRegs.takeAnyReg();
+        RegisterID t0 = tempRegs.takeAnyReg().reg();
 
         /* Store pc. */
         masm.storePtr(ImmPtr(cx->regs->pc),
                        FrameAddress(offsetof(VMFrame, regs.pc)));
 
         /* Store sp (if not already set by ic::SplatApplyArgs). */
         if (ic.frameSize.isStatic()) {
             uint32 spOffset = sizeof(JSStackFrame) + initialFrameDepth * sizeof(Value);
@@ -733,39 +733,39 @@ class CallCompiler : public BaseCompiler
             masm.storePtr(t0, FrameAddress(offsetof(VMFrame, regs.sp)));
         }
 
         /* Store fp. */
         masm.storePtr(JSFrameReg, FrameAddress(offsetof(VMFrame, regs.fp)));
 
         /* Grab cx. */
 #ifdef JS_CPU_X86
-        RegisterID cxReg = tempRegs.takeAnyReg();
+        RegisterID cxReg = tempRegs.takeAnyReg().reg();
 #else
         RegisterID cxReg = Registers::ArgReg0;
 #endif
         masm.loadPtr(FrameAddress(offsetof(VMFrame, cx)), cxReg);
 
         /* Compute vp. */
 #ifdef JS_CPU_X86
         RegisterID vpReg = t0;
 #else
         RegisterID vpReg = Registers::ArgReg2;
 #endif
         MaybeRegisterID argcReg;
         if (ic.frameSize.isStatic()) {
             uint32 vpOffset = sizeof(JSStackFrame) + (vp - f.regs.fp->slots()) * sizeof(Value);
             masm.addPtr(Imm32(vpOffset), JSFrameReg, vpReg);
         } else {
-            argcReg = tempRegs.takeAnyReg();
+            argcReg = tempRegs.takeAnyReg().reg();
             masm.load32(FrameAddress(offsetof(VMFrame, u.call.dynamicArgc)), argcReg.reg());
             masm.loadPtr(FrameAddress(offsetof(VMFrame, regs.sp)), vpReg);
 
             /* vpOff = (argc + 2) * sizeof(Value) */
-            RegisterID vpOff = tempRegs.takeAnyReg();
+            RegisterID vpOff = tempRegs.takeAnyReg().reg();
             masm.move(argcReg.reg(), vpOff);
             masm.add32(Imm32(2), vpOff);  /* callee, this */
             JS_STATIC_ASSERT(sizeof(Value) == 8);
             masm.lshift32(Imm32(3), vpOff);
             masm.subPtr(vpOff, vpReg);
 
             tempRegs.putReg(vpOff);
         }