Bug 1406340 - Remove ArgumentsRectifierReg and just load argc from the stack. r=bbouvier
authorJan de Mooij <jdemooij@mozilla.com>
Sat, 07 Oct 2017 19:18:26 +0200
changeset 385030 b632d01bb67047bcdc46787d00ee832b0c4fca27
parent 385029 8367a42358e2c6f8f89185ec02a1c0337d8709a9
child 385031 a5ab6b153cccc38a2fae62a529923f8370734c39
push id32640
push userarchaeopteryx@coole-files.de
push dateSun, 08 Oct 2017 09:44:48 +0000
treeherdermozilla-central@8dba4037f395 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbbouvier
bugs1406340
milestone58.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 1406340 - Remove ArgumentsRectifierReg and just load argc from the stack. r=bbouvier
js/src/jit/BaselineCacheIRCompiler.cpp
js/src/jit/BaselineIC.cpp
js/src/jit/CacheIRCompiler.h
js/src/jit/CodeGenerator.cpp
js/src/jit/Lowering.cpp
js/src/jit/arm/Assembler-arm.h
js/src/jit/arm/Trampoline-arm.cpp
js/src/jit/arm64/Assembler-arm64.h
js/src/jit/arm64/Trampoline-arm64.cpp
js/src/jit/mips-shared/Assembler-mips-shared.h
js/src/jit/none/MacroAssembler-none.h
js/src/jit/x64/Assembler-x64.h
js/src/jit/x64/Trampoline-x64.cpp
js/src/jit/x86/Assembler-x86.h
js/src/jit/x86/Trampoline-x86.cpp
--- a/js/src/jit/BaselineCacheIRCompiler.cpp
+++ b/js/src/jit/BaselineCacheIRCompiler.cpp
@@ -525,17 +525,17 @@ BaselineCacheIRCompiler::emitGuardHasGet
 bool
 BaselineCacheIRCompiler::emitCallScriptedGetterResult()
 {
     MOZ_ASSERT(engine_ == ICStubEngine::Baseline);
 
     Register obj = allocator.useRegister(masm, reader.objOperandId());
     Address getterAddr(stubAddress(reader.stubOffset()));
 
-    AutoScratchRegisterExcluding code(allocator, masm, ArgumentsRectifierReg);
+    AutoScratchRegister code(allocator, masm);
     AutoScratchRegister callee(allocator, masm);
     AutoScratchRegister scratch(allocator, masm);
 
     // First, ensure our getter is non-lazy and has JIT code.
     {
         FailurePath* failure;
         if (!addFailurePath(&failure))
             return false;
@@ -566,22 +566,19 @@ BaselineCacheIRCompiler::emitCallScripte
     masm.Push(scratch);
 
     // Handle arguments underflow.
     Label noUnderflow;
     masm.load16ZeroExtend(Address(callee, JSFunction::offsetOfNargs()), callee);
     masm.branch32(Assembler::Equal, callee, Imm32(0), &noUnderflow);
     {
         // Call the arguments rectifier.
-        MOZ_ASSERT(ArgumentsRectifierReg != code);
-
         JitCode* argumentsRectifier = cx_->runtime()->jitRuntime()->getArgumentsRectifier();
         masm.movePtr(ImmGCPtr(argumentsRectifier), code);
         masm.loadPtr(Address(code, JitCode::offsetOfCode()), code);
-        masm.movePtr(ImmWord(0), ArgumentsRectifierReg);
     }
 
     masm.bind(&noUnderflow);
     masm.callJit(code);
 
     stubFrame.leave(masm, true);
     return true;
 }
@@ -1625,17 +1622,17 @@ BaselineCacheIRCompiler::emitCallNativeS
 
     stubFrame.leave(masm);
     return true;
 }
 
 bool
 BaselineCacheIRCompiler::emitCallScriptedSetter()
 {
-    AutoScratchRegisterExcluding scratch1(allocator, masm, ArgumentsRectifierReg);
+    AutoScratchRegister scratch1(allocator, masm);
     AutoScratchRegister scratch2(allocator, masm);
 
     Register obj = allocator.useRegister(masm, reader.objOperandId());
     Address setterAddr(stubAddress(reader.stubOffset()));
     ValueOperand val = allocator.useValueRegister(masm, reader.valOperandId());
 
     // First, ensure our setter is non-lazy and has JIT code. This also loads
     // the callee in scratch1.
@@ -1680,22 +1677,19 @@ BaselineCacheIRCompiler::emitCallScripte
     masm.load16ZeroExtend(Address(scratch1, JSFunction::offsetOfNargs()), scratch2);
     masm.loadPtr(Address(scratch1, JSFunction::offsetOfNativeOrScript()), scratch1);
     masm.loadBaselineOrIonRaw(scratch1, scratch1, nullptr);
 
     // Handle arguments underflow.
     masm.branch32(Assembler::BelowOrEqual, scratch2, Imm32(1), &noUnderflow);
     {
         // Call the arguments rectifier.
-        MOZ_ASSERT(ArgumentsRectifierReg != scratch1);
-
         JitCode* argumentsRectifier = cx_->runtime()->jitRuntime()->getArgumentsRectifier();
         masm.movePtr(ImmGCPtr(argumentsRectifier), scratch1);
         masm.loadPtr(Address(scratch1, JitCode::offsetOfCode()), scratch1);
-        masm.movePtr(ImmWord(1), ArgumentsRectifierReg);
     }
 
     masm.bind(&noUnderflow);
     masm.callJit(scratch1);
 
     stubFrame.leave(masm, true);
     return true;
 }
--- a/js/src/jit/BaselineIC.cpp
+++ b/js/src/jit/BaselineIC.cpp
@@ -3052,20 +3052,17 @@ ICCallScriptedCompiler::generateStubCode
 {
     MOZ_ASSERT(engine_ == Engine::Baseline);
 
     Label failure;
     AllocatableGeneralRegisterSet regs(availableGeneralRegs(0));
     bool canUseTailCallReg = regs.has(ICTailCallReg);
 
     Register argcReg = R0.scratchReg();
-    MOZ_ASSERT(argcReg != ArgumentsRectifierReg);
-
     regs.take(argcReg);
-    regs.take(ArgumentsRectifierReg);
     regs.takeUnchecked(ICTailCallReg);
 
     if (isSpread_)
         guardSpreadCall(masm, argcReg, &failure, isConstructing_);
 
     // Load the callee in R1, accounting for newTarget, if necessary
     // Stack Layout: [ ..., CalleeVal, ThisVal, Arg0Val, ..., ArgNVal, [newTarget] +ICStackValueOffset+ ]
     if (isSpread_) {
@@ -3164,17 +3161,16 @@ ICCallScriptedCompiler::generateStubCode
         masm.assumeUnreachable("The return of CreateThis must be an object or uninitialized.");
         masm.bind(&createdThisOK);
 #endif
 
         // Reset the register set from here on in.
         MOZ_ASSERT(JSReturnOperand == R0);
         regs = availableGeneralRegs(0);
         regs.take(R0);
-        regs.take(ArgumentsRectifierReg);
         argcReg = regs.takeAny();
 
         // Restore saved argc so we can use it to calculate the address to save
         // the resulting this object to.
         masm.pop(argcReg);
 
         // Save "this" value back into pushed arguments on stack.  R0 can be clobbered after that.
         // Stack now looks like:
@@ -3247,25 +3243,21 @@ ICCallScriptedCompiler::generateStubCode
     masm.Push(scratch);
 
     // Handle arguments underflow.
     Label noUnderflow;
     masm.load16ZeroExtend(Address(callee, JSFunction::offsetOfNargs()), callee);
     masm.branch32(Assembler::AboveOrEqual, argcReg, callee, &noUnderflow);
     {
         // Call the arguments rectifier.
-        MOZ_ASSERT(ArgumentsRectifierReg != code);
-        MOZ_ASSERT(ArgumentsRectifierReg != argcReg);
-
         JitCode* argumentsRectifier =
             cx->runtime()->jitRuntime()->getArgumentsRectifier();
 
         masm.movePtr(ImmGCPtr(argumentsRectifier), code);
         masm.loadPtr(Address(code, JitCode::offsetOfCode()), code);
-        masm.movePtr(argcReg, ArgumentsRectifierReg);
     }
 
     masm.bind(&noUnderflow);
     masm.callJit(code);
 
     // If this is a constructing call, and the callee returns a non-object, replace it with
     // the |this| object passed in.
     if (isConstructing_) {
@@ -3676,17 +3668,16 @@ ICCall_ScriptedApplyArray::Compiler::gen
     MOZ_ASSERT(engine_ == Engine::Baseline);
 
     Label failure;
     AllocatableGeneralRegisterSet regs(availableGeneralRegs(0));
 
     Register argcReg = R0.scratchReg();
     regs.take(argcReg);
     regs.takeUnchecked(ICTailCallReg);
-    regs.takeUnchecked(ArgumentsRectifierReg);
 
     //
     // Validate inputs
     //
 
     Register target = guardFunApply(masm, regs, argcReg, /*checkNative=*/false,
                                     FunApply_Array, &failure);
     if (regs.has(target)) {
@@ -3744,25 +3735,21 @@ ICCall_ScriptedApplyArray::Compiler::gen
     masm.loadPtr(Address(target, JSFunction::offsetOfNativeOrScript()), target);
     masm.loadBaselineOrIonRaw(target, target, nullptr);
 
     // Handle arguments underflow.
     Label noUnderflow;
     masm.branch32(Assembler::AboveOrEqual, argcReg, scratch, &noUnderflow);
     {
         // Call the arguments rectifier.
-        MOZ_ASSERT(ArgumentsRectifierReg != target);
-        MOZ_ASSERT(ArgumentsRectifierReg != argcReg);
-
         JitCode* argumentsRectifier =
             cx->runtime()->jitRuntime()->getArgumentsRectifier();
 
         masm.movePtr(ImmGCPtr(argumentsRectifier), target);
         masm.loadPtr(Address(target, JitCode::offsetOfCode()), target);
-        masm.movePtr(argcReg, ArgumentsRectifierReg);
     }
     masm.bind(&noUnderflow);
     regs.add(argcReg);
 
     // Do call
     masm.callJit(target);
     leaveStubFrame(masm, true);
 
@@ -3780,17 +3767,16 @@ ICCall_ScriptedApplyArguments::Compiler:
     MOZ_ASSERT(engine_ == Engine::Baseline);
 
     Label failure;
     AllocatableGeneralRegisterSet regs(availableGeneralRegs(0));
 
     Register argcReg = R0.scratchReg();
     regs.take(argcReg);
     regs.takeUnchecked(ICTailCallReg);
-    regs.takeUnchecked(ArgumentsRectifierReg);
 
     //
     // Validate inputs
     //
 
     Register target = guardFunApply(masm, regs, argcReg, /*checkNative=*/false,
                                     FunApply_MagicArgs, &failure);
     if (regs.has(target)) {
@@ -3842,25 +3828,21 @@ ICCall_ScriptedApplyArguments::Compiler:
     masm.loadPtr(Address(target, JSFunction::offsetOfNativeOrScript()), target);
     masm.loadBaselineOrIonRaw(target, target, nullptr);
 
     // Handle arguments underflow.
     Label noUnderflow;
     masm.branch32(Assembler::AboveOrEqual, argcReg, scratch, &noUnderflow);
     {
         // Call the arguments rectifier.
-        MOZ_ASSERT(ArgumentsRectifierReg != target);
-        MOZ_ASSERT(ArgumentsRectifierReg != argcReg);
-
         JitCode* argumentsRectifier =
             cx->runtime()->jitRuntime()->getArgumentsRectifier();
 
         masm.movePtr(ImmGCPtr(argumentsRectifier), target);
         masm.loadPtr(Address(target, JitCode::offsetOfCode()), target);
-        masm.movePtr(argcReg, ArgumentsRectifierReg);
     }
     masm.bind(&noUnderflow);
     regs.add(argcReg);
 
     // Do call
     masm.callJit(target);
     leaveStubFrame(masm, true);
 
@@ -3877,20 +3859,17 @@ ICCall_ScriptedFunCall::Compiler::genera
 {
     MOZ_ASSERT(engine_ == Engine::Baseline);
 
     Label failure;
     AllocatableGeneralRegisterSet regs(availableGeneralRegs(0));
     bool canUseTailCallReg = regs.has(ICTailCallReg);
 
     Register argcReg = R0.scratchReg();
-    MOZ_ASSERT(argcReg != ArgumentsRectifierReg);
-
     regs.take(argcReg);
-    regs.take(ArgumentsRectifierReg);
     regs.takeUnchecked(ICTailCallReg);
 
     // Load the callee in R1.
     // Stack Layout: [ ..., CalleeVal, ThisVal, Arg0Val, ..., ArgNVal, +ICStackValueOffset+ ]
     BaseValueIndex calleeSlot(masm.getStackPointer(), argcReg, ICStackValueOffset + sizeof(Value));
     masm.loadValue(calleeSlot, R1);
     regs.take(R1);
 
@@ -3973,25 +3952,21 @@ ICCall_ScriptedFunCall::Compiler::genera
     masm.Push(scratch);
 
     // Handle arguments underflow.
     Label noUnderflow;
     masm.load16ZeroExtend(Address(callee, JSFunction::offsetOfNargs()), callee);
     masm.branch32(Assembler::AboveOrEqual, argcReg, callee, &noUnderflow);
     {
         // Call the arguments rectifier.
-        MOZ_ASSERT(ArgumentsRectifierReg != code);
-        MOZ_ASSERT(ArgumentsRectifierReg != argcReg);
-
         JitCode* argumentsRectifier =
             cx->runtime()->jitRuntime()->getArgumentsRectifier();
 
         masm.movePtr(ImmGCPtr(argumentsRectifier), code);
         masm.loadPtr(Address(code, JitCode::offsetOfCode()), code);
-        masm.movePtr(argcReg, ArgumentsRectifierReg);
     }
 
     masm.bind(&noUnderflow);
     masm.callJit(code);
 
     leaveStubFrame(masm, true);
 
     // Enter type monitor IC to type-check result.
--- a/js/src/jit/CacheIRCompiler.h
+++ b/js/src/jit/CacheIRCompiler.h
@@ -459,47 +459,16 @@ class MOZ_RAII AutoScratchRegister
     ~AutoScratchRegister() {
         alloc_.releaseRegister(reg_);
     }
 
     Register get() const { return reg_; }
     operator Register() const { return reg_; }
 };
 
-// Like AutoScratchRegister, but lets the caller specify a register that should
-// not be allocated here.
-class MOZ_RAII AutoScratchRegisterExcluding
-{
-    CacheRegisterAllocator& alloc_;
-    Register reg_;
-
-  public:
-    AutoScratchRegisterExcluding(CacheRegisterAllocator& alloc, MacroAssembler& masm,
-                                 Register excluding)
-      : alloc_(alloc)
-    {
-        MOZ_ASSERT(excluding != InvalidReg);
-
-        reg_ = alloc.allocateRegister(masm);
-
-        if (reg_ == excluding) {
-            // We need a different register, so try again.
-            reg_ = alloc.allocateRegister(masm);
-            MOZ_ASSERT(reg_ != excluding);
-            alloc_.releaseRegister(excluding);
-        }
-
-        MOZ_ASSERT(alloc_.currentOpRegs_.has(reg_));
-    }
-    ~AutoScratchRegisterExcluding() {
-        alloc_.releaseRegister(reg_);
-    }
-    operator Register() const { return reg_; }
-};
-
 // The FailurePath class stores everything we need to generate a failure path
 // at the end of the IC code. The failure path restores the input registers, if
 // needed, and jumps to the next stub.
 class FailurePath
 {
     Vector<OperandLocation, 4, SystemAllocPolicy> inputs_;
     SpilledRegisterVector spilledRegs_;
     NonAssertingLabel label_;
--- a/js/src/jit/CodeGenerator.cpp
+++ b/js/src/jit/CodeGenerator.cpp
@@ -4236,20 +4236,18 @@ CodeGenerator::visitCallGeneric(LCallGen
     MOZ_ASSERT(call->numActualArgs() == call->mir()->numStackArgs() - numNonArgsOnStack);
     masm.load16ZeroExtend(Address(calleereg, JSFunction::offsetOfNargs()), nargsreg);
     masm.branch32(Assembler::Above, nargsreg, Imm32(call->numActualArgs()), &thunk);
     masm.jump(&makeCall);
 
     // Argument fixed needed. Load the ArgumentsRectifier.
     masm.bind(&thunk);
     {
-        MOZ_ASSERT(ArgumentsRectifierReg != objreg);
         masm.movePtr(ImmGCPtr(argumentsRectifier), objreg); // Necessary for GC marking.
         masm.loadPtr(Address(objreg, JitCode::offsetOfCode()), objreg);
-        masm.move32(Imm32(call->numActualArgs()), ArgumentsRectifierReg);
     }
 
     // Finally call the function in objreg.
     masm.bind(&makeCall);
     uint32_t callOffset = masm.callJit(objreg);
     markSafepointAt(callOffset, call);
 
     // Increment to remove IonFramePrefix; decrement to fill FrameSizeClass.
@@ -4669,20 +4667,18 @@ CodeGenerator::emitApplyGeneric(T* apply
 
         // Argument fixup needed. Get ready to call the argumentsRectifier.
         {
             masm.bind(&underflow);
 
             // Hardcode the address of the argumentsRectifier code.
             JitCode* argumentsRectifier = gen->jitRuntime()->getArgumentsRectifier();
 
-            MOZ_ASSERT(ArgumentsRectifierReg != objreg);
             masm.movePtr(ImmGCPtr(argumentsRectifier), objreg); // Necessary for GC marking.
             masm.loadPtr(Address(objreg, JitCode::offsetOfCode()), objreg);
-            masm.movePtr(argcreg, ArgumentsRectifierReg);
         }
 
         masm.bind(&rejoin);
 
         // Finally call the function in objreg, as assigned by one of the paths above.
         uint32_t callOffset = masm.callJit(objreg);
         markSafepointAt(callOffset, apply);
 
--- a/js/src/jit/Lowering.cpp
+++ b/js/src/jit/Lowering.cpp
@@ -495,19 +495,16 @@ LIRGenerator::lowerCallArguments(MCall* 
             return false;
     }
     return true;
 }
 
 void
 LIRGenerator::visitCall(MCall* call)
 {
-    MOZ_ASSERT(CallTempReg0 != CallTempReg1);
-    MOZ_ASSERT(CallTempReg0 != ArgumentsRectifierReg);
-    MOZ_ASSERT(CallTempReg1 != ArgumentsRectifierReg);
     MOZ_ASSERT(call->getFunction()->type() == MIRType::Object);
 
     // In case of oom, skip the rest of the allocations.
     if (!lowerCallArguments(call)) {
         abort(AbortReason::Alloc, "OOM: LIRGenerator::visitCall");
         return;
     }
 
@@ -543,32 +540,28 @@ LIRGenerator::visitCall(MCall* call)
                                            tempFixed(vpReg), tempFixed(tmpReg));
         } else {
             lir = new(alloc()) LCallKnown(useFixedAtStart(call->getFunction(), CallTempReg0),
                                           tempFixed(CallTempReg2));
         }
     } else {
         // Call anything, using the most generic code.
         lir = new(alloc()) LCallGeneric(useFixedAtStart(call->getFunction(), CallTempReg0),
-                                        tempFixed(ArgumentsRectifierReg),
+                                        tempFixed(CallTempReg1),
                                         tempFixed(CallTempReg2));
     }
     defineReturn(lir, call);
     assignSafepoint(lir, call);
 }
 
 void
 LIRGenerator::visitApplyArgs(MApplyArgs* apply)
 {
     MOZ_ASSERT(apply->getFunction()->type() == MIRType::Object);
 
-    // Assert if we cannot build a rectifier frame.
-    MOZ_ASSERT(CallTempReg0 != ArgumentsRectifierReg);
-    MOZ_ASSERT(CallTempReg1 != ArgumentsRectifierReg);
-
     // Assert if the return value is already erased.
     MOZ_ASSERT(CallTempReg2 != JSReturnReg_Type);
     MOZ_ASSERT(CallTempReg2 != JSReturnReg_Data);
 
     LApplyArgsGeneric* lir = new(alloc()) LApplyArgsGeneric(
         useFixedAtStart(apply->getFunction(), CallTempReg3),
         useFixedAtStart(apply->getArgc(), CallTempReg0),
         useBoxFixedAtStart(apply->getThis(), CallTempReg4, CallTempReg5),
@@ -584,20 +577,16 @@ LIRGenerator::visitApplyArgs(MApplyArgs*
     assignSafepoint(lir, apply);
 }
 
 void
 LIRGenerator::visitApplyArray(MApplyArray* apply)
 {
     MOZ_ASSERT(apply->getFunction()->type() == MIRType::Object);
 
-    // Assert if we cannot build a rectifier frame.
-    MOZ_ASSERT(CallTempReg0 != ArgumentsRectifierReg);
-    MOZ_ASSERT(CallTempReg1 != ArgumentsRectifierReg);
-
     // Assert if the return value is already erased.
     MOZ_ASSERT(CallTempReg2 != JSReturnReg_Type);
     MOZ_ASSERT(CallTempReg2 != JSReturnReg_Data);
 
     LApplyArrayGeneric* lir = new(alloc()) LApplyArrayGeneric(
         useFixedAtStart(apply->getFunction(), CallTempReg3),
         useFixedAtStart(apply->getElements(), CallTempReg0),
         useBoxFixedAtStart(apply->getThis(), CallTempReg4, CallTempReg5),
--- a/js/src/jit/arm/Assembler-arm.h
+++ b/js/src/jit/arm/Assembler-arm.h
@@ -56,17 +56,16 @@ struct ScratchRegisterScope : public Aut
 };
 
 struct SecondScratchRegisterScope : public AutoRegisterScope
 {
     explicit SecondScratchRegisterScope(MacroAssembler& masm);
 };
 
 static constexpr Register OsrFrameReg = r3;
-static constexpr Register ArgumentsRectifierReg = r8;
 static constexpr Register CallTempReg0 = r5;
 static constexpr Register CallTempReg1 = r6;
 static constexpr Register CallTempReg2 = r7;
 static constexpr Register CallTempReg3 = r8;
 static constexpr Register CallTempReg4 = r0;
 static constexpr Register CallTempReg5 = r1;
 
 static constexpr Register IntArgReg0 = r0;
--- a/js/src/jit/arm/Trampoline-arm.cpp
+++ b/js/src/jit/arm/Trampoline-arm.cpp
@@ -471,22 +471,19 @@ JitRuntime::generateInvalidator(JSContex
 }
 
 JitCode*
 JitRuntime::generateArgumentsRectifier(JSContext* cx, void** returnAddrOut)
 {
     MacroAssembler masm(cx);
     masm.pushReturnAddress();
 
-    // ArgumentsRectifierReg contains the |nargs| pushed onto the current frame.
-    // Including |this|, there are (|nargs| + 1) arguments to copy.
-    MOZ_ASSERT(ArgumentsRectifierReg == r8);
-
-    // Copy number of actual arguments into r0.
+    // Copy number of actual arguments into r0 and r8.
     masm.ma_ldr(DTRAddr(sp, DtrOffImm(RectifierFrameLayout::offsetOfNumActualArgs())), r0);
+    masm.mov(r0, r8);
 
     // Load the number of |undefined|s to push into r6.
     masm.ma_ldr(DTRAddr(sp, DtrOffImm(RectifierFrameLayout::offsetOfCalleeToken())), r1);
     {
         ScratchRegisterScope scratch(masm);
         masm.ma_and(Imm32(CalleeTokenMask), r1, r6, scratch);
     }
     masm.ma_ldrh(EDtrAddr(r6, EDtrOffImm(JSFunction::offsetOfNargs())), r6);
--- a/js/src/jit/arm64/Assembler-arm64.h
+++ b/js/src/jit/arm64/Assembler-arm64.h
@@ -38,17 +38,16 @@ static constexpr FloatRegister ReturnDou
 
 static constexpr FloatRegister ReturnFloat32Reg = { FloatRegisters::s0, FloatRegisters::Single };
 static constexpr FloatRegister ScratchFloat32Reg = { FloatRegisters::s31, FloatRegisters::Single };
 
 static constexpr Register InvalidReg { Registers::invalid_reg };
 static constexpr FloatRegister InvalidFloatReg = { FloatRegisters::invalid_fpreg, FloatRegisters::Single };
 
 static constexpr Register OsrFrameReg { Registers::x3 };
-static constexpr Register ArgumentsRectifierReg { Registers::x8 };
 static constexpr Register CallTempReg0 { Registers::x9 };
 static constexpr Register CallTempReg1 { Registers::x10 };
 static constexpr Register CallTempReg2 { Registers::x11 };
 static constexpr Register CallTempReg3 { Registers::x12 };
 static constexpr Register CallTempReg4 { Registers::x13 };
 static constexpr Register CallTempReg5 { Registers::x14 };
 
 static constexpr Register PreBarrierReg { Registers::x1 };
--- a/js/src/jit/arm64/Trampoline-arm64.cpp
+++ b/js/src/jit/arm64/Trampoline-arm64.cpp
@@ -339,18 +339,20 @@ JitRuntime::generateArgumentsRectifier(J
 
     // Get the arguments from the function object.
     masm.Ldrh(x6, MemOperand(x5, JSFunction::offsetOfNargs()));
 
     static_assert(CalleeToken_FunctionConstructing == 0x1, "Constructing must be low-order bit");
     masm.And(x4, x1, Operand(CalleeToken_FunctionConstructing));
     masm.Add(x7, x6, x4);
 
+    // Copy the number of actual arguments into r8.
+    masm.mov(r0, r8);
+
     // Calculate the position that our arguments are at before sp gets modified.
-    MOZ_ASSERT(ArgumentsRectifierReg == r8, "x8 used for argc in Arguments Rectifier");
     masm.Add(x3, masm.GetStackPointer64(), Operand(x8, vixl::LSL, 3));
     masm.Add(x3, x3, Operand(sizeof(RectifierFrameLayout)));
 
     // Pad to a multiple of 16 bytes. This neglects the |this| value,
     // which will also be pushed, because the rest of the frame will
     // round off that value. See pushes of |argc|, |callee| and |desc| below.
     Label noPadding;
     masm.Tbnz(x7, 0, &noPadding);
--- a/js/src/jit/mips-shared/Assembler-mips-shared.h
+++ b/js/src/jit/mips-shared/Assembler-mips-shared.h
@@ -75,17 +75,16 @@ struct SecondScratchRegisterScope : publ
 {
     explicit SecondScratchRegisterScope(MacroAssembler& masm)
       : AutoRegisterScope(masm, SecondScratchReg)
     { }
 };
 
 // Use arg reg from EnterJIT function as OsrFrameReg.
 static constexpr Register OsrFrameReg = a3;
-static constexpr Register ArgumentsRectifierReg = s3;
 static constexpr Register CallTempReg0 = t0;
 static constexpr Register CallTempReg1 = t1;
 static constexpr Register CallTempReg2 = t2;
 static constexpr Register CallTempReg3 = t3;
 
 static constexpr Register IntArgReg0 = a0;
 static constexpr Register IntArgReg1 = a1;
 static constexpr Register IntArgReg2 = a2;
--- a/js/src/jit/none/MacroAssembler-none.h
+++ b/js/src/jit/none/MacroAssembler-none.h
@@ -21,17 +21,16 @@ static constexpr FloatRegister ReturnFlo
 static constexpr FloatRegister ReturnDoubleReg = { FloatRegisters::invalid_reg };
 static constexpr FloatRegister ReturnSimd128Reg = { FloatRegisters::invalid_reg };
 static constexpr FloatRegister ScratchFloat32Reg = { FloatRegisters::invalid_reg };
 static constexpr FloatRegister ScratchDoubleReg = { FloatRegisters::invalid_reg };
 static constexpr FloatRegister ScratchSimd128Reg = { FloatRegisters::invalid_reg };
 static constexpr FloatRegister InvalidFloatReg = { FloatRegisters::invalid_reg };
 
 static constexpr Register OsrFrameReg { Registers::invalid_reg };
-static constexpr Register ArgumentsRectifierReg { Registers::invalid_reg };
 static constexpr Register PreBarrierReg { Registers::invalid_reg };
 static constexpr Register CallTempReg0 { Registers::invalid_reg };
 static constexpr Register CallTempReg1 { Registers::invalid_reg };
 static constexpr Register CallTempReg2 { Registers::invalid_reg };
 static constexpr Register CallTempReg3 { Registers::invalid_reg };
 static constexpr Register CallTempReg4 { Registers::invalid_reg };
 static constexpr Register CallTempReg5 { Registers::invalid_reg };
 static constexpr Register InvalidReg { Registers::invalid_reg };
--- a/js/src/jit/x64/Assembler-x64.h
+++ b/js/src/jit/x64/Assembler-x64.h
@@ -87,17 +87,16 @@ static constexpr Register64 ReturnReg64(
 static constexpr FloatRegister ReturnFloat32Reg = FloatRegister(X86Encoding::xmm0, FloatRegisters::Single);
 static constexpr FloatRegister ReturnDoubleReg = FloatRegister(X86Encoding::xmm0, FloatRegisters::Double);
 static constexpr FloatRegister ReturnSimd128Reg = FloatRegister(X86Encoding::xmm0, FloatRegisters::Simd128);
 static constexpr FloatRegister ScratchFloat32Reg = FloatRegister(X86Encoding::xmm15, FloatRegisters::Single);
 static constexpr FloatRegister ScratchDoubleReg = FloatRegister(X86Encoding::xmm15, FloatRegisters::Double);
 static constexpr FloatRegister ScratchSimd128Reg = xmm15;
 
 // Avoid rbp, which is the FramePointer, which is unavailable in some modes.
-static constexpr Register ArgumentsRectifierReg = r8;
 static constexpr Register CallTempReg0 = rax;
 static constexpr Register CallTempReg1 = rdi;
 static constexpr Register CallTempReg2 = rbx;
 static constexpr Register CallTempReg3 = rcx;
 static constexpr Register CallTempReg4 = rsi;
 static constexpr Register CallTempReg5 = rdx;
 
 // Different argument registers for WIN64
--- a/js/src/jit/x64/Trampoline-x64.cpp
+++ b/js/src/jit/x64/Trampoline-x64.cpp
@@ -406,23 +406,19 @@ JitRuntime::generateInvalidator(JSContex
 JitCode*
 JitRuntime::generateArgumentsRectifier(JSContext* cx, void** returnAddrOut)
 {
     // Do not erase the frame pointer in this function.
 
     MacroAssembler masm(cx);
     // Caller:
     // [arg2] [arg1] [this] [[argc] [callee] [descr] [raddr]] <- rsp
-    // '--- #r8 ---'
-
-    // ArgumentsRectifierReg contains the |nargs| pushed onto the current frame.
-    // Including |this|, there are (|nargs| + 1) arguments to copy.
-    MOZ_ASSERT(ArgumentsRectifierReg == r8);
 
     // Add |this|, in the counter of known arguments.
+    masm.loadPtr(Address(rsp, RectifierFrameLayout::offsetOfNumActualArgs()), r8);
     masm.addl(Imm32(1), r8);
 
     // Load |nformals| into %rcx.
     masm.loadPtr(Address(rsp, RectifierFrameLayout::offsetOfCalleeToken()), rax);
     masm.mov(rax, rcx);
     masm.andq(Imm32(uint32_t(CalleeTokenMask)), rcx);
     masm.movzwl(Operand(rcx, JSFunction::offsetOfNargs()), rcx);
 
@@ -456,18 +452,19 @@ JitRuntime::generateArgumentsRectifier(J
     // Caller:
     // [arg2] [arg1] [this] [[argc] [callee] [descr] [raddr]] <- rsp <- r9
     // '------ #r8 -------'
     //
     // Rectifier frame:
     // [undef] [undef] [undef] [arg2] [arg1] [this] [[argc] [callee] [descr] [raddr]]
     // '------- #rcx --------' '------ #r8 -------'
 
-    // Copy the number of actual arguments
-    masm.loadPtr(Address(rsp, RectifierFrameLayout::offsetOfNumActualArgs()), rdx);
+    // Copy the number of actual arguments into rdx. Use lea to subtract 1 for
+    // |this|.
+    masm.lea(Operand(r8, -1), rdx);
 
     masm.moveValue(UndefinedValue(), ValueOperand(r10));
 
     masm.movq(rsp, r9); // Save %rsp.
 
     // Push undefined. (including the padding)
     {
         Label undefLoopTop;
--- a/js/src/jit/x86/Assembler-x86.h
+++ b/js/src/jit/x86/Assembler-x86.h
@@ -48,17 +48,16 @@ static constexpr Register64 ReturnReg64(
 static constexpr FloatRegister ReturnFloat32Reg = FloatRegister(X86Encoding::xmm0, FloatRegisters::Single);
 static constexpr FloatRegister ReturnDoubleReg = FloatRegister(X86Encoding::xmm0, FloatRegisters::Double);
 static constexpr FloatRegister ReturnSimd128Reg = FloatRegister(X86Encoding::xmm0, FloatRegisters::Simd128);
 static constexpr FloatRegister ScratchFloat32Reg = FloatRegister(X86Encoding::xmm7, FloatRegisters::Single);
 static constexpr FloatRegister ScratchDoubleReg = FloatRegister(X86Encoding::xmm7, FloatRegisters::Double);
 static constexpr FloatRegister ScratchSimd128Reg = FloatRegister(X86Encoding::xmm7, FloatRegisters::Simd128);
 
 // Avoid ebp, which is the FramePointer, which is unavailable in some modes.
-static constexpr Register ArgumentsRectifierReg = esi;
 static constexpr Register CallTempReg0 = edi;
 static constexpr Register CallTempReg1 = eax;
 static constexpr Register CallTempReg2 = ebx;
 static constexpr Register CallTempReg3 = ecx;
 static constexpr Register CallTempReg4 = esi;
 static constexpr Register CallTempReg5 = edx;
 
 // We have no arg regs, so our NonArgRegs are just our CallTempReg*
--- a/js/src/jit/x86/Trampoline-x86.cpp
+++ b/js/src/jit/x86/Trampoline-x86.cpp
@@ -397,21 +397,19 @@ JitRuntime::generateInvalidator(JSContex
 }
 
 JitCode*
 JitRuntime::generateArgumentsRectifier(JSContext* cx, void** returnAddrOut)
 {
     MacroAssembler masm(cx);
     // Caller:
     // [arg2] [arg1] [this] [[argc] [callee] [descr] [raddr]] <- esp
-    // '-- #esi ---'
 
-    // ArgumentsRectifierReg contains the |nargs| pushed onto the current frame.
-    // Including |this|, there are (|nargs| + 1) arguments to copy.
-    MOZ_ASSERT(ArgumentsRectifierReg == esi);
+    // Load argc.
+    masm.loadPtr(Address(esp, RectifierFrameLayout::offsetOfNumActualArgs()), esi);
 
     // Load the number of |undefined|s to push into %ecx.
     masm.loadPtr(Address(esp, RectifierFrameLayout::offsetOfCalleeToken()), eax);
     masm.mov(eax, ecx);
     masm.andl(Imm32(CalleeTokenMask), ecx);
     masm.movzwl(Operand(ecx, JSFunction::offsetOfNargs()), ecx);
 
     // The frame pointer and its padding are pushed on the stack.
@@ -434,18 +432,18 @@ JitRuntime::generateArgumentsRectifier(J
       "Ensure that we can use the constructing bit to count an extra push");
     masm.mov(eax, edx);
     masm.andl(Imm32(CalleeToken_FunctionConstructing), edx);
     masm.addl(edx, ecx);
 
     masm.andl(Imm32(~(JitStackValueAlignment - 1)), ecx);
     masm.subl(esi, ecx);
 
-    // Copy the number of actual arguments.
-    masm.loadPtr(Address(esp, RectifierFrameLayout::offsetOfNumActualArgs()), edx);
+    // Copy the number of actual arguments into edx.
+    masm.mov(esi, edx);
 
     masm.moveValue(UndefinedValue(), ValueOperand(ebx, edi));
 
     // NOTE: The fact that x86 ArgumentsRectifier saves the FramePointer is relied upon
     // by the baseline bailout code.  If this changes, fix that code!  See
     // BaselineJIT.cpp/BaselineStackBuilder::calculatePrevFramePtr, and
     // BaselineJIT.cpp/InitFromBailout.  Check for the |#if defined(JS_CODEGEN_X86)| portions.
     masm.push(FramePointer);