Bug 1271010 - Baldr: simplify register use in profiling prologue/epilogue (r=bbouvier)
authorLuke Wagner <luke@mozilla.com>
Sat, 28 May 2016 16:50:03 -0500
changeset 340599 8ca82dcfc2a31722ac005ba8cbce4e7704643ea5
parent 340598 90ba40dac02d30f615626eda393cf1f53335f783
child 340600 ff7d5e4ca750c0ad228e5e4dc0dfc70e9770efee
push id1183
push userraliiev@mozilla.com
push dateMon, 05 Sep 2016 20:01:49 +0000
treeherdermozilla-release@3148731bed45 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbbouvier
bugs1271010
milestone49.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1271010 - Baldr: simplify register use in profiling prologue/epilogue (r=bbouvier) MozReview-Commit-ID: 9Vy6JXraPv8
js/src/asmjs/WasmFrameIterator.cpp
js/src/asmjs/WasmStubs.cpp
js/src/jit/Lowering.cpp
js/src/jit/arm/Assembler-arm.cpp
js/src/jit/arm/Assembler-arm.h
js/src/jit/arm/MacroAssembler-arm.cpp
js/src/jit/arm/MacroAssembler-arm.h
js/src/jit/arm64/Assembler-arm64.cpp
js/src/jit/arm64/Assembler-arm64.h
js/src/jit/mips32/Assembler-mips32.cpp
js/src/jit/mips32/Assembler-mips32.h
js/src/jit/mips64/Assembler-mips64.cpp
js/src/jit/mips64/Assembler-mips64.h
js/src/jit/none/MacroAssembler-none.h
js/src/jit/none/Trampoline-none.cpp
js/src/jit/x64/Assembler-x64.cpp
js/src/jit/x64/Assembler-x64.h
js/src/jit/x86/Assembler-x86.cpp
js/src/jit/x86/Assembler-x86.h
--- a/js/src/asmjs/WasmFrameIterator.cpp
+++ b/js/src/asmjs/WasmFrameIterator.cpp
@@ -189,25 +189,17 @@ PushRetAddr(MacroAssembler& masm)
 
 // Generate a prologue that maintains WasmActivation::fp as the virtual frame
 // pointer so that ProfilingFrameIterator can walk the stack at any pc in
 // generated code.
 static void
 GenerateProfilingPrologue(MacroAssembler& masm, unsigned framePushed, ExitReason reason,
                           ProfilingOffsets* offsets)
 {
-#if !defined (JS_CODEGEN_ARM)
-    Register scratch = ABIArgGenerator::NonArg_VolatileReg;
-#else
-    // Unfortunately, there are no unused non-arg volatile registers on ARM --
-    // the MacroAssembler claims both lr and ip -- so we use the second scratch
-    // register (lr) and be very careful not to call any methods that use it.
-    Register scratch = lr;
-    masm.setSecondScratchReg(InvalidReg);
-#endif
+    Register scratch = ABINonArgReg0;
 
     // ProfilingFrameIterator needs to know the offsets of several key
     // instructions from entry. To save space, we make these offsets static
     // constants and assert that they match the actual codegen below. On ARM,
     // this requires AutoForbidPools to prevent a constant pool from being
     // randomly inserted between two instructions.
     {
 #if defined(JS_CODEGEN_ARM)
@@ -222,38 +214,32 @@ GenerateProfilingPrologue(MacroAssembler
         masm.loadWasmActivation(scratch);
         masm.push(Address(scratch, WasmActivation::offsetOfFP()));
         MOZ_ASSERT_IF(!masm.oom(), PushedFP == masm.currentOffset() - offsets->begin);
 
         masm.storePtr(masm.getStackPointer(), Address(scratch, WasmActivation::offsetOfFP()));
         MOZ_ASSERT_IF(!masm.oom(), StoredFP == masm.currentOffset() - offsets->begin);
     }
 
-    if (reason != ExitReason::None) {
-        masm.store32_NoSecondScratch(Imm32(int32_t(reason)),
-                                     Address(scratch, WasmActivation::offsetOfExitReason()));
-    }
-
-#if defined(JS_CODEGEN_ARM)
-    masm.setSecondScratchReg(lr);
-#endif
+    if (reason != ExitReason::None)
+        masm.store32(Imm32(int32_t(reason)), Address(scratch, WasmActivation::offsetOfExitReason()));
 
     if (framePushed)
         masm.subFromStackPtr(Imm32(framePushed));
 }
 
 // Generate the inverse of GenerateProfilingPrologue.
 static void
 GenerateProfilingEpilogue(MacroAssembler& masm, unsigned framePushed, ExitReason reason,
                           ProfilingOffsets* offsets)
 {
-    Register scratch = ABIArgGenerator::NonReturn_VolatileReg0;
+    Register scratch = ABINonArgReturnReg0;
 #if defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_ARM64) || \
     defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64)
-    Register scratch2 = ABIArgGenerator::NonReturn_VolatileReg1;
+    Register scratch2 = ABINonArgReturnReg1;
 #endif
 
     if (framePushed)
         masm.addToStackPtr(Imm32(framePushed));
 
     masm.loadWasmActivation(scratch);
 
     if (reason != ExitReason::None) {
--- a/js/src/asmjs/WasmStubs.cpp
+++ b/js/src/asmjs/WasmStubs.cpp
@@ -130,18 +130,18 @@ wasm::GenerateEntry(MacroAssembler& masm
     // register already having been loaded.
     if (usesHeap)
         masm.loadAsmJSHeapRegisterFromGlobalData();
 
     // Put the 'argv' argument into a non-argument/return register so that we
     // can use 'argv' while we fill in the arguments for the asm.js callee.
     // Also, save 'argv' on the stack so that we can recover it after the call.
     // Use a second non-argument/return register as temporary scratch.
-    Register argv = ABIArgGenerator::NonArgReturnReg0;
-    Register scratch = ABIArgGenerator::NonArgReturnReg1;
+    Register argv = ABINonArgReturnReg0;
+    Register scratch = ABINonArgReturnReg1;
     Register64 scratch64(scratch);
 
 #if defined(JS_CODEGEN_X86)
     masm.loadPtr(Address(masm.getStackPointer(), EntryFrameSize + masm.framePushed()), argv);
 #else
     masm.movePtr(IntArgReg0, argv);
 #endif
     masm.Push(argv);
@@ -419,17 +419,17 @@ wasm::GenerateInterpExit(MacroAssembler&
     unsigned argBytes = Max<size_t>(1, sig.args().length()) * sizeof(Value);
     unsigned framePushed = StackDecrementForCall(masm, ABIStackAlignment, argOffset + argBytes);
 
     ProfilingOffsets offsets;
     GenerateExitPrologue(masm, framePushed, ExitReason::ImportInterp, &offsets);
 
     // Fill the argument array.
     unsigned offsetToCallerStackArgs = sizeof(AsmJSFrame) + masm.framePushed();
-    Register scratch = ABIArgGenerator::NonArgReturnReg0;
+    Register scratch = ABINonArgReturnReg0;
     FillArgumentArray(masm, sig.args(), argOffset, offsetToCallerStackArgs, scratch, ToValue(false));
 
     // Prepare the arguments for the call to InvokeImport_*.
     ABIArgMIRTypeIter i(invokeArgTypes);
 
     // argument 0: importIndex
     if (i->kind() == ABIArg::GPR)
         masm.mov(ImmWord(importIndex), i->gpr());
@@ -538,18 +538,18 @@ wasm::GenerateJitExit(MacroAssembler& ma
     // 1. Descriptor
     size_t argOffset = 0;
     uint32_t descriptor = MakeFrameDescriptor(jitFramePushed, JitFrame_Entry,
                                               JitFrameLayout::Size());
     masm.storePtr(ImmWord(uintptr_t(descriptor)), Address(masm.getStackPointer(), argOffset));
     argOffset += sizeof(size_t);
 
     // 2. Callee
-    Register callee = ABIArgGenerator::NonArgReturnReg0;   // live until call
-    Register scratch = ABIArgGenerator::NonArgReturnReg1;  // repeatedly clobbered
+    Register callee = ABINonArgReturnReg0;   // live until call
+    Register scratch = ABINonArgReturnReg1;  // repeatedly clobbered
 
     // 2.1. Get ExitDatum
     uint32_t globalDataOffset = import.exitGlobalDataOffset();
 #if defined(JS_CODEGEN_X64)
     masm.append(AsmJSGlobalAccess(masm.leaRipRelative(callee), globalDataOffset));
 #elif defined(JS_CODEGEN_X86)
     masm.append(AsmJSGlobalAccess(masm.movlWithPatch(Imm32(0), callee), globalDataOffset));
 #elif defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_ARM64) || \
@@ -834,17 +834,17 @@ GenerateStackOverflow(MacroAssembler& ma
     offsets.begin = masm.currentOffset();
 
     // If we reach here via the non-profiling prologue, WasmActivation::fp has
     // not been updated. To enable stack unwinding from C++, store to it now. If
     // we reached here via the profiling prologue, we'll just store the same
     // value again. Do not update AsmJSFrame::callerFP as it is not necessary in
     // the non-profiling case (there is no return path from this point) and, in
     // the profiling case, it is already correct.
-    Register activation = ABIArgGenerator::NonArgReturnReg0;
+    Register activation = ABINonArgReturnReg0;
     masm.loadWasmActivation(activation);
     masm.storePtr(masm.getStackPointer(), Address(activation, WasmActivation::offsetOfFP()));
 
     // Prepare the stack for calling C++.
     if (uint32_t d = StackDecrementForCall(ABIStackAlignment, sizeof(AsmJSFrame), ShadowStackSpace))
         masm.subFromStackPtr(Imm32(d));
 
     // No need to restore the stack; the throw stub pops everything.
@@ -904,17 +904,17 @@ GenerateThrow(MacroAssembler& masm)
     masm.haltingAlign(CodeAlignment);
 
     Offsets offsets;
     offsets.begin = masm.currentOffset();
 
     // We are about to pop all frames in this WasmActivation. Set fp to null to
     // maintain the invariant that fp is either null or pointing to a valid
     // frame.
-    Register scratch = ABIArgGenerator::NonArgReturnReg0;
+    Register scratch = ABINonArgReturnReg0;
     masm.loadWasmActivation(scratch);
     masm.storePtr(ImmWord(0), Address(scratch, WasmActivation::offsetOfFP()));
 
     masm.setFramePushed(FramePushedForEntrySP);
     masm.loadStackPtr(Address(scratch, WasmActivation::offsetOfEntrySP()));
     masm.Pop(scratch);
     masm.PopRegsInMask(NonVolatileRegs);
     MOZ_ASSERT(masm.framePushed() == 0);
@@ -973,37 +973,37 @@ wasm::GenerateInterruptStub(MacroAssembl
     // Be very careful here not to perturb the machine state before saving it
     // to the stack. In particular, add/sub instructions may set conditions in
     // the flags register.
     masm.push(Imm32(0));            // space for resumePC
     masm.pushFlags();               // after this we are safe to use sub
     masm.setFramePushed(0);         // set to zero so we can use masm.framePushed() below
     masm.PushRegsInMask(AllRegsExceptSP); // save all GP/FP registers (except SP)
 
-    Register scratch = ABIArgGenerator::NonArgReturnReg0;
+    Register scratch = ABINonArgReturnReg0;
 
     // Store resumePC into the reserved space.
     masm.loadWasmActivation(scratch);
     masm.loadPtr(Address(scratch, WasmActivation::offsetOfResumePC()), scratch);
     masm.storePtr(scratch, Address(masm.getStackPointer(), masm.framePushed() + sizeof(void*)));
 
     // We know that StackPointer is word-aligned, but not necessarily
     // stack-aligned, so we need to align it dynamically.
-    masm.moveStackPtrTo(ABIArgGenerator::NonVolatileReg);
+    masm.moveStackPtrTo(ABINonVolatileReg);
     masm.andToStackPtr(Imm32(~(ABIStackAlignment - 1)));
     if (ShadowStackSpace)
         masm.subFromStackPtr(Imm32(ShadowStackSpace));
 
     masm.assertStackAlignment(ABIStackAlignment);
     masm.call(SymbolicAddress::HandleExecutionInterrupt);
 
     masm.branchIfFalseBool(ReturnReg, JumpTarget::Throw);
 
     // Restore the StackPointer to its position before the call.
-    masm.moveToStackPtr(ABIArgGenerator::NonVolatileReg);
+    masm.moveToStackPtr(ABINonVolatileReg);
 
     // Restore the machine state to before the interrupt.
     masm.PopRegsInMask(AllRegsExceptSP); // restore all GP/FP registers (except SP)
     masm.popFlags();              // after this, nothing that sets conditions
     masm.ret();                   // pop resumePC into PC
 #elif defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64)
     // Reserve space to store resumePC.
     masm.subFromStackPtr(Imm32(sizeof(intptr_t)));
--- a/js/src/jit/Lowering.cpp
+++ b/js/src/jit/Lowering.cpp
@@ -4200,18 +4200,20 @@ LIRGenerator::visitAsmJSCall(MAsmJSCall*
     if (!args) {
         gen->abort("Couldn't allocate for MAsmJSCall");
         return;
     }
 
     for (unsigned i = 0; i < ins->numArgs(); i++)
         args[i] = useFixed(ins->getOperand(i), ins->registerForArg(i));
 
-    if (ins->callee().which() == MAsmJSCall::Callee::Dynamic)
-        args[ins->dynamicCalleeOperandIndex()] = useFixed(ins->callee().dynamic(), CallTempReg0);
+    if (ins->callee().which() == MAsmJSCall::Callee::Dynamic) {
+        args[ins->dynamicCalleeOperandIndex()] =
+            useFixed(ins->callee().dynamic(), ABINonArgReg0);
+    }
 
     LInstruction* lir = new(alloc()) LAsmJSCall(args, ins->numOperands());
     if (ins->type() == MIRType::None)
         add(lir, ins);
     else
         defineReturn(lir, ins);
 }
 
--- a/js/src/jit/arm/Assembler-arm.cpp
+++ b/js/src/jit/arm/Assembler-arm.cpp
@@ -138,21 +138,16 @@ ABIArgGenerator::hardNext(MIRType type)
 ABIArg
 ABIArgGenerator::next(MIRType type)
 {
     if (useHardFp_)
         return hardNext(type);
     return softNext(type);
 }
 
-const Register ABIArgGenerator::NonArgReturnReg0 = r4;
-const Register ABIArgGenerator::NonArgReturnReg1 = r5;
-const Register ABIArgGenerator::NonReturn_VolatileReg0 = r2;
-const Register ABIArgGenerator::NonReturn_VolatileReg1 = r3;
-
 // Encode a standard register when it is being used as src1, the dest, and an
 // extra register. These should never be called with an InvalidReg.
 uint32_t
 js::jit::RT(Register r)
 {
     MOZ_ASSERT((r.code() & ~0xf) == 0);
     return r.code() << 12;
 }
--- a/js/src/jit/arm/Assembler-arm.h
+++ b/js/src/jit/arm/Assembler-arm.h
@@ -96,22 +96,22 @@ class ABIArgGenerator
 
     void setUseHardFp(bool useHardFp) {
         MOZ_ASSERT(intRegIndex_ == 0 && floatRegIndex_ == 0);
         useHardFp_ = useHardFp;
     }
     ABIArg next(MIRType argType);
     ABIArg& current() { return current_; }
     uint32_t stackBytesConsumedSoFar() const { return stackOffset_; }
+};
 
-    static const Register NonArgReturnReg0;
-    static const Register NonArgReturnReg1;
-    static const Register NonReturn_VolatileReg0;
-    static const Register NonReturn_VolatileReg1;
-};
+static MOZ_CONSTEXPR_VAR Register ABINonArgReg0 = r4;
+static MOZ_CONSTEXPR_VAR Register ABINonArgReg1 = r5;
+static MOZ_CONSTEXPR_VAR Register ABINonArgReturnReg0 = r4;
+static MOZ_CONSTEXPR_VAR Register ABINonArgReturnReg1 = r5;
 
 static MOZ_CONSTEXPR_VAR Register PreBarrierReg = r1;
 
 static MOZ_CONSTEXPR_VAR Register InvalidReg = { Registers::invalid_reg };
 static MOZ_CONSTEXPR_VAR FloatRegister InvalidFloatReg;
 
 static MOZ_CONSTEXPR_VAR Register JSReturnReg_Type = r3;
 static MOZ_CONSTEXPR_VAR Register JSReturnReg_Data = r2;
--- a/js/src/jit/arm/MacroAssembler-arm.cpp
+++ b/js/src/jit/arm/MacroAssembler-arm.cpp
@@ -2219,25 +2219,16 @@ MacroAssemblerARMCompat::store32(Registe
 
     if (dest.offset != 0) {
         ma_add(base, Imm32(dest.offset), scratch2);
         base = scratch2;
     }
     ma_str(src, DTRAddr(base, DtrRegImmShift(dest.index, LSL, scale)));
 }
 
-void
-MacroAssemblerARMCompat::store32_NoSecondScratch(Imm32 src, const Address& address)
-{
-    // move32() needs to use the ScratchRegister internally, but there is no additional
-    // scratch register available since this function forbids use of the second one.
-    move32(src, ScratchRegister);
-    storePtr(ScratchRegister, address);
-}
-
 template <typename T>
 void
 MacroAssemblerARMCompat::storePtr(ImmWord imm, T address)
 {
     ScratchRegisterScope scratch(asMasm());
     movePtr(imm, scratch);
     storePtr(scratch, address);
 }
--- a/js/src/jit/arm/MacroAssembler-arm.h
+++ b/js/src/jit/arm/MacroAssembler-arm.h
@@ -978,18 +978,16 @@ class MacroAssemblerARMCompat : public M
     void store16(Imm32 imm, const BaseIndex& address);
 
     void store32(Register src, AbsoluteAddress address);
     void store32(Register src, const Address& address);
     void store32(Register src, const BaseIndex& address);
     void store32(Imm32 src, const Address& address);
     void store32(Imm32 src, const BaseIndex& address);
 
-    void store32_NoSecondScratch(Imm32 src, const Address& address);
-
     void store64(Register64 src, Address address) {
         store32(src.low, address);
         store32(src.high, Address(address.base, address.offset + 4));
     }
 
     template <typename T> void storePtr(ImmWord imm, T address);
     template <typename T> void storePtr(ImmPtr imm, T address);
     template <typename T> void storePtr(ImmGCPtr imm, T address);
--- a/js/src/jit/arm64/Assembler-arm64.cpp
+++ b/js/src/jit/arm64/Assembler-arm64.cpp
@@ -57,23 +57,16 @@ ABIArgGenerator::next(MIRType type)
         break;
 
       default:
         MOZ_CRASH("Unexpected argument type");
     }
     return current_;
 }
 
-const Register ABIArgGenerator::NonArgReturnReg0 = r8;
-const Register ABIArgGenerator::NonArgReturnReg1 = r9;
-const Register ABIArgGenerator::NonVolatileReg = r1;
-const Register ABIArgGenerator::NonArg_VolatileReg = r13;
-const Register ABIArgGenerator::NonReturn_VolatileReg0 = r2;
-const Register ABIArgGenerator::NonReturn_VolatileReg1 = r3;
-
 namespace js {
 namespace jit {
 
 void
 Assembler::finish()
 {
     armbuffer_.flushPool();
 
--- a/js/src/jit/arm64/Assembler-arm64.h
+++ b/js/src/jit/arm64/Assembler-arm64.h
@@ -443,31 +443,28 @@ class ABIArgGenerator
         stackOffset_(0),
         current_()
     { }
 
     ABIArg next(MIRType argType);
     ABIArg& current() { return current_; }
     uint32_t stackBytesConsumedSoFar() const { return stackOffset_; }
 
-  public:
-    static const Register NonArgReturnReg0;
-    static const Register NonArgReturnReg1;
-    static const Register NonVolatileReg;
-    static const Register NonArg_VolatileReg;
-    static const Register NonReturn_VolatileReg0;
-    static const Register NonReturn_VolatileReg1;
-
   protected:
     unsigned intRegIndex_;
     unsigned floatRegIndex_;
     uint32_t stackOffset_;
     ABIArg current_;
 };
 
+static MOZ_CONSTEXPR_VAR Register ABINonArgReg0 = r8;
+static MOZ_CONSTEXPR_VAR Register ABINonArgReg1 = r9;
+static MOZ_CONSTEXPR_VAR Register ABINonArgReturnReg0 = r8;
+static MOZ_CONSTEXPR_VAR Register ABINonArgReturnReg1 = r9;
+
 static inline bool
 GetIntArgReg(uint32_t usedIntArgs, uint32_t usedFloatArgs, Register* out)
 {
     if (usedIntArgs >= NumIntArgRegs)
         return false;
     *out = Register::FromCode(usedIntArgs);
     return true;
 }
--- a/js/src/jit/mips32/Assembler-mips32.cpp
+++ b/js/src/jit/mips32/Assembler-mips32.cpp
@@ -68,22 +68,16 @@ ABIArgGenerator::next(MIRType type)
         }
         break;
       default:
         MOZ_CRASH("Unexpected argument type");
     }
     return current_;
 }
 
-const Register ABIArgGenerator::NonArgReturnReg0 = t0;
-const Register ABIArgGenerator::NonArgReturnReg1 = t1;
-const Register ABIArgGenerator::NonArg_VolatileReg = v0;
-const Register ABIArgGenerator::NonReturn_VolatileReg0 = a0;
-const Register ABIArgGenerator::NonReturn_VolatileReg1 = a1;
-
 uint32_t
 js::jit::RT(FloatRegister r)
 {
     MOZ_ASSERT(r.id() < FloatRegisters::RegisterIdLimit);
     return r.id() << RTShift;
 }
 
 uint32_t
--- a/js/src/jit/mips32/Assembler-mips32.h
+++ b/js/src/jit/mips32/Assembler-mips32.h
@@ -39,23 +39,22 @@ class ABIArgGenerator
     }
 
     uint32_t stackBytesConsumedSoFar() const {
         if (usedArgSlots_ <= 4)
             return ShadowStackSpace;
 
         return usedArgSlots_ * sizeof(intptr_t);
     }
+};
 
-    static const Register NonArgReturnReg0;
-    static const Register NonArgReturnReg1;
-    static const Register NonArg_VolatileReg;
-    static const Register NonReturn_VolatileReg0;
-    static const Register NonReturn_VolatileReg1;
-};
+static MOZ_CONSTEXPR_VAR Register ABINonArgReg0 = t0;
+static MOZ_CONSTEXPR_VAR Register ABINonArgReg1 = t1;
+static MOZ_CONSTEXPR_VAR Register ABINonArgReturnReg0 = t0;
+static MOZ_CONSTEXPR_VAR Register ABINonArgReturnReg1 = t1;
 
 static MOZ_CONSTEXPR_VAR Register JSReturnReg_Type = a3;
 static MOZ_CONSTEXPR_VAR Register JSReturnReg_Data = a2;
 static MOZ_CONSTEXPR_VAR Register64 ReturnReg64(InvalidReg, InvalidReg);
 static MOZ_CONSTEXPR_VAR FloatRegister ReturnFloat32Reg = { FloatRegisters::f0, FloatRegister::Single };
 static MOZ_CONSTEXPR_VAR FloatRegister ReturnDoubleReg = { FloatRegisters::f0, FloatRegister::Double };
 static MOZ_CONSTEXPR_VAR FloatRegister ScratchFloat32Reg = { FloatRegisters::f18, FloatRegister::Single };
 static MOZ_CONSTEXPR_VAR FloatRegister ScratchDoubleReg = { FloatRegisters::f18, FloatRegister::Double };
--- a/js/src/jit/mips64/Assembler-mips64.cpp
+++ b/js/src/jit/mips64/Assembler-mips64.cpp
@@ -49,22 +49,16 @@ ABIArgGenerator::next(MIRType type)
         break;
       }
       default:
         MOZ_CRASH("Unexpected argument type");
     }
     return current_;
 }
 
-const Register ABIArgGenerator::NonArgReturnReg0 = t0;
-const Register ABIArgGenerator::NonArgReturnReg1 = t1;
-const Register ABIArgGenerator::NonArg_VolatileReg = v0;
-const Register ABIArgGenerator::NonReturn_VolatileReg0 = a0;
-const Register ABIArgGenerator::NonReturn_VolatileReg1 = a1;
-
 uint32_t
 js::jit::RT(FloatRegister r)
 {
     MOZ_ASSERT(r.id() < FloatRegisters::TotalPhys);
     return r.id() << RTShift;
 }
 
 uint32_t
--- a/js/src/jit/mips64/Assembler-mips64.h
+++ b/js/src/jit/mips64/Assembler-mips64.h
@@ -32,23 +32,22 @@ class ABIArgGenerator
     ABIArg& current() { return current_; }
 
     uint32_t stackBytesConsumedSoFar() const {
         if (usedArgSlots_ <= 8)
             return 0;
 
         return (usedArgSlots_ - 8) * sizeof(int64_t);
     }
+};
 
-    static const Register NonArgReturnReg0;
-    static const Register NonArgReturnReg1;
-    static const Register NonArg_VolatileReg;
-    static const Register NonReturn_VolatileReg0;
-    static const Register NonReturn_VolatileReg1;
-};
+static MOZ_CONSTEXPR_VAR Register ABINonArgReg0 = t0;
+static MOZ_CONSTEXPR_VAR Register ABINonArgReg1 = t1;
+static MOZ_CONSTEXPR_VAR Register ABINonArgReturnReg0 = t0;
+static MOZ_CONSTEXPR_VAR Register ABINonArgReturnReg1 = t1;
 
 static MOZ_CONSTEXPR_VAR Register JSReturnReg = v1;
 static MOZ_CONSTEXPR_VAR Register JSReturnReg_Type = JSReturnReg;
 static MOZ_CONSTEXPR_VAR Register JSReturnReg_Data = JSReturnReg;
 static MOZ_CONSTEXPR_VAR Register64 ReturnReg64(ReturnReg);
 static MOZ_CONSTEXPR_VAR FloatRegister ReturnFloat32Reg = { FloatRegisters::f0, FloatRegisters::Single };
 static MOZ_CONSTEXPR_VAR FloatRegister ReturnDoubleReg = { FloatRegisters::f0, FloatRegisters::Double };
 static MOZ_CONSTEXPR_VAR FloatRegister ScratchFloat32Reg = { FloatRegisters::f23, FloatRegisters::Single };
--- a/js/src/jit/none/MacroAssembler-none.h
+++ b/js/src/jit/none/MacroAssembler-none.h
@@ -74,16 +74,21 @@ static MOZ_CONSTEXPR_VAR ValueOperand JS
 static MOZ_CONSTEXPR_VAR Register64 ReturnReg64(InvalidReg, InvalidReg);
 #elif defined(JS_PUNBOX64)
 static MOZ_CONSTEXPR_VAR ValueOperand JSReturnOperand(InvalidReg);
 static MOZ_CONSTEXPR_VAR Register64 ReturnReg64(InvalidReg);
 #else
 #error "Bad architecture"
 #endif
 
+static MOZ_CONSTEXPR_VAR Register ABINonArgReg0 = { Registers::invalid_reg };
+static MOZ_CONSTEXPR_VAR Register ABINonArgReg1 = { Registers::invalid_reg };
+static MOZ_CONSTEXPR_VAR Register ABINonArgReturnReg0 = { Registers::invalid_reg };
+static MOZ_CONSTEXPR_VAR Register ABINonArgReturnReg1 = { Registers::invalid_reg };
+
 static MOZ_CONSTEXPR_VAR uint32_t ABIStackAlignment = 4;
 static MOZ_CONSTEXPR_VAR uint32_t CodeAlignment = 4;
 static MOZ_CONSTEXPR_VAR uint32_t JitStackAlignment = 8;
 static MOZ_CONSTEXPR_VAR uint32_t JitStackValueAlignment = JitStackAlignment / sizeof(Value);
 
 static const Scale ScalePointer = TimesOne;
 
 class Assembler : public AssemblerShared
@@ -417,22 +422,16 @@ typedef MacroAssemblerNone MacroAssemble
 
 class ABIArgGenerator
 {
   public:
     ABIArgGenerator() { MOZ_CRASH(); }
     ABIArg next(MIRType) { MOZ_CRASH(); }
     ABIArg& current() { MOZ_CRASH(); }
     uint32_t stackBytesConsumedSoFar() const { MOZ_CRASH(); }
-
-    static const Register NonArgReturnReg0;
-    static const Register NonArgReturnReg1;
-    static const Register NonArg_VolatileReg;
-    static const Register NonReturn_VolatileReg0;
-    static const Register NonReturn_VolatileReg1;
 };
 
 static inline void
 PatchJump(CodeLocationJump&, CodeLocationLabel, ReprotectCode reprotect = DontReprotect)
 {
     MOZ_CRASH();
 }
 
--- a/js/src/jit/none/Trampoline-none.cpp
+++ b/js/src/jit/none/Trampoline-none.cpp
@@ -27,22 +27,16 @@ JitCode* JitRuntime::generatePreBarrier(
 JitCode* JitRuntime::generateDebugTrapHandler(JSContext*) { MOZ_CRASH(); }
 JitCode* JitRuntime::generateExceptionTailStub(JSContext*, void*) { MOZ_CRASH(); }
 JitCode* JitRuntime::generateBailoutTailStub(JSContext*) { MOZ_CRASH(); }
 
 FrameSizeClass FrameSizeClass::FromDepth(uint32_t) { MOZ_CRASH(); }
 FrameSizeClass FrameSizeClass::ClassLimit() { MOZ_CRASH(); }
 uint32_t FrameSizeClass::frameSize() const { MOZ_CRASH(); }
 
-const Register ABIArgGenerator::NonArgReturnReg0 = { Registers::invalid_reg };
-const Register ABIArgGenerator::NonArgReturnReg1 = {  Registers::invalid_reg };
-const Register ABIArgGenerator::NonArg_VolatileReg = {  Registers::invalid_reg };
-const Register ABIArgGenerator::NonReturn_VolatileReg0 = {  Registers::invalid_reg };
-const Register ABIArgGenerator::NonReturn_VolatileReg1 = {  Registers::invalid_reg };
-
 BailoutFrameInfo::BailoutFrameInfo(const JitActivationIterator& iter, BailoutStack* bailout)
 {
     MOZ_CRASH();
 }
 
 BailoutFrameInfo::BailoutFrameInfo(const JitActivationIterator& iter, InvalidationBailoutStack* bailout)
 {
     MOZ_CRASH();
--- a/js/src/jit/x64/Assembler-x64.cpp
+++ b/js/src/jit/x64/Assembler-x64.cpp
@@ -104,23 +104,16 @@ ABIArgGenerator::next(MIRType type)
         break;
       default:
         MOZ_CRASH("Unexpected argument type");
     }
     return current_;
 #endif
 }
 
-// Avoid r11, which is the MacroAssembler's ScratchReg.
-const Register ABIArgGenerator::NonArgReturnReg0 = jit::r10;
-const Register ABIArgGenerator::NonArgReturnReg1 = jit::r12;
-const Register ABIArgGenerator::NonVolatileReg = jit::r13;
-const Register ABIArgGenerator::NonArg_VolatileReg = jit::rax;
-const Register ABIArgGenerator::NonReturn_VolatileReg0 = jit::rcx;
-
 void
 Assembler::writeRelocation(JmpSrc src, Relocation::Kind reloc)
 {
     if (!jumpRelocations_.length()) {
         // The jump relocation table starts with a fixed-width integer pointing
         // to the start of the extended jump table. But, we don't know the
         // actual extended jump table offset yet, so write a 0 which we'll
         // patch later.
--- a/js/src/jit/x64/Assembler-x64.h
+++ b/js/src/jit/x64/Assembler-x64.h
@@ -184,24 +184,26 @@ class ABIArgGenerator
     uint32_t stackOffset_;
     ABIArg current_;
 
   public:
     ABIArgGenerator();
     ABIArg next(MIRType argType);
     ABIArg& current() { return current_; }
     uint32_t stackBytesConsumedSoFar() const { return stackOffset_; }
+};
 
-    // Note: these registers are all guaranteed to be different
-    static const Register NonArgReturnReg0;
-    static const Register NonArgReturnReg1;
-    static const Register NonVolatileReg;
-    static const Register NonArg_VolatileReg;
-    static const Register NonReturn_VolatileReg0;
-};
+// Avoid r11, which is the MacroAssembler's ScratchReg.
+static MOZ_CONSTEXPR_VAR Register ABINonArgReg0 = rax;
+static MOZ_CONSTEXPR_VAR Register ABINonArgReg1 = rbx;
+
+// Note: these three registers are all guaranteed to be different
+static MOZ_CONSTEXPR_VAR Register ABINonArgReturnReg0 = r10;
+static MOZ_CONSTEXPR_VAR Register ABINonArgReturnReg1 = r12;
+static MOZ_CONSTEXPR_VAR Register ABINonVolatileReg = r13;
 
 static MOZ_CONSTEXPR_VAR Register OsrFrameReg = IntArgReg3;
 
 static MOZ_CONSTEXPR_VAR Register PreBarrierReg = rdx;
 
 static MOZ_CONSTEXPR_VAR uint32_t ABIStackAlignment = 16;
 static MOZ_CONSTEXPR_VAR uint32_t CodeAlignment = 16;
 static MOZ_CONSTEXPR_VAR uint32_t JitStackAlignment = 16;
--- a/js/src/jit/x86/Assembler-x86.cpp
+++ b/js/src/jit/x86/Assembler-x86.cpp
@@ -41,22 +41,16 @@ ABIArgGenerator::next(MIRType type)
         stackOffset_ += Simd128DataSize;
         break;
       default:
         MOZ_CRASH("Unexpected argument type");
     }
     return current_;
 }
 
-const Register ABIArgGenerator::NonArgReturnReg0 = ecx;
-const Register ABIArgGenerator::NonArgReturnReg1 = edx;
-const Register ABIArgGenerator::NonVolatileReg = ebx;
-const Register ABIArgGenerator::NonArg_VolatileReg = eax;
-const Register ABIArgGenerator::NonReturn_VolatileReg0 = ecx;
-
 void
 Assembler::executableCopy(uint8_t* buffer)
 {
     AssemblerX86Shared::executableCopy(buffer);
 
     for (size_t i = 0; i < jumps_.length(); i++) {
         RelativePatch& rp = jumps_[i];
         X86Encoding::SetRel32(buffer + rp.offset, rp.target);
--- a/js/src/jit/x86/Assembler-x86.h
+++ b/js/src/jit/x86/Assembler-x86.h
@@ -74,24 +74,26 @@ class ABIArgGenerator
     ABIArg current_;
 
   public:
     ABIArgGenerator();
     ABIArg next(MIRType argType);
     ABIArg& current() { return current_; }
     uint32_t stackBytesConsumedSoFar() const { return stackOffset_; }
 
-    // Note: these registers are all guaranteed to be different
-    static const Register NonArgReturnReg0;
-    static const Register NonArgReturnReg1;
-    static const Register NonVolatileReg;
-    static const Register NonArg_VolatileReg;
-    static const Register NonReturn_VolatileReg0;
 };
 
+static MOZ_CONSTEXPR_VAR Register ABINonArgReg0 = eax;
+static MOZ_CONSTEXPR_VAR Register ABINonArgReg1 = ecx;
+
+// Note: these three registers are all guaranteed to be different
+static MOZ_CONSTEXPR_VAR Register ABINonArgReturnReg0 = ecx;
+static MOZ_CONSTEXPR_VAR Register ABINonArgReturnReg1 = edx;
+static MOZ_CONSTEXPR_VAR Register ABINonVolatileReg = ebx;
+
 static MOZ_CONSTEXPR_VAR Register OsrFrameReg = edx;
 static MOZ_CONSTEXPR_VAR Register PreBarrierReg = edx;
 
 // Registers used in the GenerateFFIIonExit Enable Activation block.
 static MOZ_CONSTEXPR_VAR Register AsmJSIonExitRegCallee = ecx;
 static MOZ_CONSTEXPR_VAR Register AsmJSIonExitRegE0 = edi;
 static MOZ_CONSTEXPR_VAR Register AsmJSIonExitRegE1 = eax;
 static MOZ_CONSTEXPR_VAR Register AsmJSIonExitRegE2 = ebx;