Bug 1245627: Hoist store{Float32,Double} functions into the MacroAssembler; r=nbp
authorBenjamin Bouvier <benj@benj.me>
Mon, 30 May 2016 18:10:27 +0200
changeset 338677 65f18c79794bad38e16519fa97e39a2483c7fab5
parent 338642 8b0c9204fec755257cdecd21e4c10423adb769af
child 338678 2c86039b1c6868c2606d343e0906c645468c3fcc
push id6249
push userjlund@mozilla.com
push dateMon, 01 Aug 2016 13:59:36 +0000
treeherdermozilla-beta@bad9d4f5bf7e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersnbp
bugs1245627
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 1245627: Hoist store{Float32,Double} functions into the MacroAssembler; r=nbp MozReview-Commit-ID: GODz1ux3Cs0
js/src/jit/MacroAssembler.h
js/src/jit/arm/MacroAssembler-arm-inl.h
js/src/jit/arm/MacroAssembler-arm.cpp
js/src/jit/arm/MacroAssembler-arm.h
js/src/jit/arm64/MacroAssembler-arm64-inl.h
js/src/jit/arm64/MacroAssembler-arm64.cpp
js/src/jit/arm64/MacroAssembler-arm64.h
js/src/jit/mips-shared/MacroAssembler-mips-shared-inl.h
js/src/jit/mips32/MacroAssembler-mips32-inl.h
js/src/jit/mips32/MacroAssembler-mips32.cpp
js/src/jit/mips32/MacroAssembler-mips32.h
js/src/jit/mips64/MacroAssembler-mips64-inl.h
js/src/jit/mips64/MacroAssembler-mips64.cpp
js/src/jit/mips64/MacroAssembler-mips64.h
js/src/jit/x64/MacroAssembler-x64.cpp
js/src/jit/x64/MacroAssembler-x64.h
js/src/jit/x86-shared/MacroAssembler-x86-shared-inl.h
js/src/jit/x86-shared/MacroAssembler-x86-shared.h
js/src/jit/x86/MacroAssembler-x86.cpp
js/src/jit/x86/MacroAssembler-x86.h
--- a/js/src/jit/MacroAssembler.h
+++ b/js/src/jit/MacroAssembler.h
@@ -67,17 +67,17 @@
 # define ALL_ARCH mips32, mips64, arm, arm64, x86, x64
 # define ALL_SHARED_ARCH arm, arm64, x86_shared, mips_shared
 
 // * How this macro works:
 //
 // DEFINED_ON is a macro which check if, for the current architecture, the
 // method is defined on the macro assembler or not.
 //
-// For each architecutre, we have a macro named DEFINED_ON_arch.  This macro is
+// For each architecture, we have a macro named DEFINED_ON_arch.  This macro is
 // empty if this is not the current architecture.  Otherwise it must be either
 // set to "define" or "crash" (only use for the none target so-far).
 //
 // The DEFINED_ON macro maps the list of architecture names given as argument to
 // a list of macro names.  For example,
 //
 //   DEFINED_ON(arm, x86_shared)
 //
@@ -89,17 +89,17 @@
 // to
 //
 //   define
 //
 // or if the JIT is disabled or set to no architecture to
 //
 //   crash
 //
-// or to nothing, if the current architecture is not lsited in the list of
+// or to nothing, if the current architecture is not listed in the list of
 // arguments of DEFINED_ON.  Note, only one of the DEFINED_ON_arch macro
 // contributes to the non-empty result, which is the macro of the current
 // architecture if it is listed in the arguments of DEFINED_ON.
 //
 // This result is appended to DEFINED_ON_RESULT_ before expanding the macro,
 // which result is either no annotation, a MOZ_CRASH(), or a "= delete"
 // annotation on the method declaration.
 
@@ -1115,16 +1115,38 @@ class MacroAssembler : public MacroAssem
         DEFINED_ON(arm, arm64, x86_shared);
     template <typename T>
     inline void branchTestPrimitiveImpl(Condition cond, const T& t, Label* label)
         DEFINED_ON(arm, arm64, x86_shared);
     template <typename T, class L>
     inline void branchTestMagicImpl(Condition cond, const T& t, L label)
         DEFINED_ON(arm, arm64, x86_shared);
 
+  public:
+    // ========================================================================
+    // Memory access primitives.
+    inline void storeDouble(FloatRegister src, const Address& dest)
+        DEFINED_ON(x86_shared, arm, arm64, mips32, mips64);
+    inline void storeDouble(FloatRegister src, const BaseIndex& dest)
+        DEFINED_ON(x86_shared, arm, arm64, mips32, mips64);
+    inline void storeDouble(FloatRegister src, const Operand& dest) DEFINED_ON(x86_shared);
+
+    inline void storeFloat32(FloatRegister src, const Address& dest)
+        DEFINED_ON(x86_shared, arm, arm64, mips32, mips64);
+    inline void storeFloat32(FloatRegister src, const BaseIndex& dest)
+        DEFINED_ON(x86_shared, arm, arm64, mips32, mips64);
+    inline void storeFloat32(FloatRegister src, const Operand& dest) DEFINED_ON(x86_shared);
+
+    inline void storeFloat32x3(FloatRegister src, const Address& dest) PER_SHARED_ARCH;
+    inline void storeFloat32x3(FloatRegister src, const BaseIndex& dest) PER_SHARED_ARCH;
+
+    template <typename T>
+    void storeUnboxedValue(ConstantOrRegister value, MIRType valueType, const T& dest,
+                           MIRType slotType) PER_ARCH;
+
     //}}} check_macroassembler_style
   public:
 
     // Emits a test of a value against all types in a TypeSet. A scratch
     // register is required.
     template <typename Source>
     void guardTypeSet(const Source& address, const TypeSet* types, BarrierKind kind, Register scratch, Label* miss);
 
--- a/js/src/jit/arm/MacroAssembler-arm-inl.h
+++ b/js/src/jit/arm/MacroAssembler-arm-inl.h
@@ -1198,16 +1198,53 @@ MacroAssembler::branchTestMagicImpl(Cond
 
 void
 MacroAssembler::branchTestMagic(Condition cond, const Address& valaddr, JSWhyMagic why, Label* label)
 {
     branchTestMagic(cond, valaddr, label);
     branch32(cond, ToPayload(valaddr), Imm32(why), label);
 }
 
+// ========================================================================
+// Memory access primitives.
+void
+MacroAssembler::storeDouble(FloatRegister src, const Address& addr)
+{
+    ma_vstr(src, addr);
+}
+void
+MacroAssembler::storeDouble(FloatRegister src, const BaseIndex& addr)
+{
+    uint32_t scale = Imm32::ShiftOf(addr.scale).value;
+    ma_vstr(src, addr.base, addr.index, scale, addr.offset);
+}
+
+void
+MacroAssembler::storeFloat32(FloatRegister src, const Address& addr)
+{
+    ma_vstr(src.asSingle(), addr);
+}
+void
+MacroAssembler::storeFloat32(FloatRegister src, const BaseIndex& addr)
+{
+    uint32_t scale = Imm32::ShiftOf(addr.scale).value;
+    ma_vstr(src.asSingle(), addr.base, addr.index, scale, addr.offset);
+}
+
+void
+MacroAssembler::storeFloat32x3(FloatRegister src, const Address& dest)
+{
+    MOZ_CRASH("NYI");
+}
+void
+MacroAssembler::storeFloat32x3(FloatRegister src, const BaseIndex& dest)
+{
+    MOZ_CRASH("NYI");
+}
+
 //}}} check_macroassembler_style
 // ===============================================================
 
 void
 MacroAssemblerARMCompat::incrementInt32Value(const Address& addr)
 {
     asMasm().add32(Imm32(1), ToPayload(addr));
 }
--- a/js/src/jit/arm/MacroAssembler-arm.cpp
+++ b/js/src/jit/arm/MacroAssembler-arm.cpp
@@ -3053,45 +3053,16 @@ MacroAssemblerARMCompat::extractTag(cons
 
 Register
 MacroAssemblerARMCompat::extractTag(const BaseIndex& address, Register scratch)
 {
     ma_alu(address.base, lsl(address.index, address.scale), scratch, OpAdd, LeaveCC);
     return extractTag(Address(scratch, address.offset), scratch);
 }
 
-template <typename T>
-void
-MacroAssemblerARMCompat::storeUnboxedValue(ConstantOrRegister value, MIRType valueType,
-                                           const T& dest, MIRType slotType)
-{
-    if (valueType == MIRType::Double) {
-        storeDouble(value.reg().typedReg().fpu(), dest);
-        return;
-    }
-
-    // Store the type tag if needed.
-    if (valueType != slotType)
-        storeTypeTag(ImmType(ValueTypeFromMIRType(valueType)), dest);
-
-    // Store the payload.
-    if (value.constant())
-        storePayload(value.value(), dest);
-    else
-        storePayload(value.reg().typedReg().gpr(), dest);
-}
-
-template void
-MacroAssemblerARMCompat::storeUnboxedValue(ConstantOrRegister value, MIRType valueType,
-                                           const Address& dest, MIRType slotType);
-
-template void
-MacroAssemblerARMCompat::storeUnboxedValue(ConstantOrRegister value, MIRType valueType,
-                                           const BaseIndex& dest, MIRType slotType);
-
 void
 MacroAssemblerARMCompat::moveValue(const Value& val, Register type, Register data)
 {
     jsval_layout jv = JSVAL_TO_IMPL(val);
     ma_mov(Imm32(jv.s.tag), type);
     if (val.isMarkable())
         ma_mov(ImmGCPtr(reinterpret_cast<gc::Cell*>(val.toGCThing())), data);
     else
@@ -5076,9 +5047,39 @@ MacroAssembler::branchTestValue(Conditio
     if (rhs.isMarkable())
         ma_cmp(lhs.payloadReg(), ImmGCPtr(reinterpret_cast<gc::Cell*>(rhs.toGCThing())));
     else
         ma_cmp(lhs.payloadReg(), Imm32(jv.s.payload.i32));
     ma_cmp(lhs.typeReg(), Imm32(jv.s.tag), Equal);
     ma_b(label, cond);
 }
 
+// ========================================================================
+// Memory access primitives.
+template <typename T>
+void
+MacroAssembler::storeUnboxedValue(ConstantOrRegister value, MIRType valueType, const T& dest,
+                                  MIRType slotType)
+{
+    if (valueType == MIRType::Double) {
+        storeDouble(value.reg().typedReg().fpu(), dest);
+        return;
+    }
+
+    // Store the type tag if needed.
+    if (valueType != slotType)
+        storeTypeTag(ImmType(ValueTypeFromMIRType(valueType)), dest);
+
+    // Store the payload.
+    if (value.constant())
+        storePayload(value.value(), dest);
+    else
+        storePayload(value.reg().typedReg().gpr(), dest);
+}
+
+template void
+MacroAssembler::storeUnboxedValue(ConstantOrRegister value, MIRType valueType,
+                                  const Address& dest, MIRType slotType);
+template void
+MacroAssembler::storeUnboxedValue(ConstantOrRegister value, MIRType valueType,
+                                  const BaseIndex& dest, MIRType slotType);
+
 //}}} check_macroassembler_style
--- a/js/src/jit/arm/MacroAssembler-arm.h
+++ b/js/src/jit/arm/MacroAssembler-arm.h
@@ -765,20 +765,16 @@ class MacroAssemblerARMCompat : public M
     void loadUnboxedValue(BaseIndex address, MIRType type, AnyRegister dest) {
         if (dest.isFloat())
             loadInt32OrDouble(address.base, address.index, dest.fpu(), address.scale);
         else
             load32(address, dest.gpr());
     }
 
     template <typename T>
-    void storeUnboxedValue(ConstantOrRegister value, MIRType valueType, const T& dest,
-                           MIRType slotType);
-
-    template <typename T>
     void storeUnboxedPayload(ValueOperand value, T address, size_t nbytes) {
         switch (nbytes) {
           case 4:
             storePtr(value.payloadReg(), address);
             return;
           case 1:
             store8(value.payloadReg(), address);
             return;
@@ -943,18 +939,16 @@ class MacroAssemblerARMCompat : public M
     void storeAlignedSimd128Int(FloatRegister src, Address addr) { MOZ_CRASH("NYI"); }
     void loadUnalignedSimd128Int(const Address& addr, FloatRegister dest) { MOZ_CRASH("NYI"); }
     void loadUnalignedSimd128Int(const BaseIndex& addr, FloatRegister dest) { MOZ_CRASH("NYI"); }
     void storeUnalignedSimd128Int(FloatRegister src, Address addr) { MOZ_CRASH("NYI"); }
     void storeUnalignedSimd128Int(FloatRegister src, BaseIndex addr) { MOZ_CRASH("NYI"); }
 
     void loadFloat32x3(const Address& src, FloatRegister dest) { MOZ_CRASH("NYI"); }
     void loadFloat32x3(const BaseIndex& src, FloatRegister dest) { MOZ_CRASH("NYI"); }
-    void storeFloat32x3(FloatRegister src, const Address& dest) { MOZ_CRASH("NYI"); }
-    void storeFloat32x3(FloatRegister src, const BaseIndex& dest) { MOZ_CRASH("NYI"); }
     void loadAlignedSimd128Float(const Address& addr, FloatRegister dest) { MOZ_CRASH("NYI"); }
     void storeAlignedSimd128Float(FloatRegister src, Address addr) { MOZ_CRASH("NYI"); }
     void loadUnalignedSimd128Float(const Address& addr, FloatRegister dest) { MOZ_CRASH("NYI"); }
     void loadUnalignedSimd128Float(const BaseIndex& addr, FloatRegister dest) { MOZ_CRASH("NYI"); }
     void storeUnalignedSimd128Float(FloatRegister src, Address addr) { MOZ_CRASH("NYI"); }
     void storeUnalignedSimd128Float(FloatRegister src, BaseIndex addr) { MOZ_CRASH("NYI"); }
 
     void loadDouble(const Address& addr, FloatRegister dest);
@@ -989,35 +983,20 @@ class MacroAssemblerARMCompat : public M
     }
 
     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);
     void storePtr(Register src, const Address& address);
     void storePtr(Register src, const BaseIndex& address);
     void storePtr(Register src, AbsoluteAddress dest);
-    void storeDouble(FloatRegister src, Address addr) {
-        ma_vstr(src, addr);
-    }
-    void storeDouble(FloatRegister src, BaseIndex addr) {
-        uint32_t scale = Imm32::ShiftOf(addr.scale).value;
-        ma_vstr(src, addr.base, addr.index, scale, addr.offset);
-    }
     void moveDouble(FloatRegister src, FloatRegister dest, Condition cc = Always) {
         ma_vmov(src, dest, cc);
     }
 
-    void storeFloat32(FloatRegister src, const Address& addr) {
-        ma_vstr(VFPRegister(src).singleOverlay(), addr);
-    }
-    void storeFloat32(FloatRegister src, const BaseIndex& addr) {
-        uint32_t scale = Imm32::ShiftOf(addr.scale).value;
-        ma_vstr(VFPRegister(src).singleOverlay(), addr.base, addr.index, scale, addr.offset);
-    }
-
   private:
     template<typename T>
     Register computePointer(const T& src, Register r);
 
     template<typename T>
     void compareExchangeARMv6(int nbytes, bool signExtend, const T& mem, Register oldval,
                               Register newval, Register output);
 
--- a/js/src/jit/arm64/MacroAssembler-arm64-inl.h
+++ b/js/src/jit/arm64/MacroAssembler-arm64-inl.h
@@ -1293,16 +1293,51 @@ MacroAssembler::branchTestMagicImpl(Cond
 void
 MacroAssembler::branchTestMagic(Condition cond, const Address& valaddr, JSWhyMagic why, Label* label)
 {
     uint64_t magic = MagicValue(why).asRawBits();
     cmpPtr(valaddr, ImmWord(magic));
     B(label, cond);
 }
 
+// ========================================================================
+// Memory access primitives.
+void
+MacroAssembler::storeDouble(FloatRegister src, const Address& dest)
+{
+    Str(ARMFPRegister(src, 64), MemOperand(ARMRegister(dest.base, 64), dest.offset));
+}
+void
+MacroAssembler::storeDouble(FloatRegister src, const BaseIndex& dest)
+{
+    doBaseIndex(ARMFPRegister(src, 64), dest, vixl::STR_d);
+}
+
+void
+MacroAssembler::storeFloat32(FloatRegister src, const Address& addr)
+{
+    Str(ARMFPRegister(src, 32), MemOperand(ARMRegister(addr.base, 64), addr.offset));
+}
+void
+MacroAssembler::storeFloat32(FloatRegister src, const BaseIndex& addr)
+{
+    doBaseIndex(ARMFPRegister(src, 32), addr, vixl::STR_s);
+}
+
+void
+MacroAssembler::storeFloat32x3(FloatRegister src, const Address& dest)
+{
+    MOZ_CRASH("NYI");
+}
+void
+MacroAssembler::storeFloat32x3(FloatRegister src, const BaseIndex& dest)
+{
+    MOZ_CRASH("NYI");
+}
+
 //}}} check_macroassembler_style
 // ===============================================================
 
 template <typename T>
 void
 MacroAssemblerCompat::addToStackPtr(T t)
 {
     asMasm().addPtr(t, getStackPointer());
--- a/js/src/jit/arm64/MacroAssembler-arm64.cpp
+++ b/js/src/jit/arm64/MacroAssembler-arm64.cpp
@@ -779,12 +779,53 @@ MacroAssembler::branchTestValue(Conditio
     vixl::UseScratchRegisterScope temps(this);
     const ARMRegister scratch64 = temps.AcquireX();
     MOZ_ASSERT(scratch64.asUnsized() != lhs.valueReg());
     moveValue(rhs, ValueOperand(scratch64.asUnsized()));
     Cmp(ARMRegister(lhs.valueReg(), 64), scratch64);
     B(label, cond);
 }
 
+// ========================================================================
+// Memory access primitives.
+template <typename T>
+void
+MacroAssembler::storeUnboxedValue(ConstantOrRegister value, MIRType valueType, const T& dest,
+                                  MIRType slotType)
+{
+    if (valueType == MIRType::Double) {
+        storeDouble(value.reg().typedReg().fpu(), dest);
+        return;
+    }
+
+    // For known integers and booleans, we can just store the unboxed value if
+    // the slot has the same type.
+    if ((valueType == MIRType::Int32 || valueType == MIRType::Boolean) && slotType == valueType) {
+        if (value.constant()) {
+            Value val = value.value();
+            if (valueType == MIRType::Int32)
+                store32(Imm32(val.toInt32()), dest);
+            else
+                store32(Imm32(val.toBoolean() ? 1 : 0), dest);
+        } else {
+            store32(value.reg().typedReg().gpr(), dest);
+        }
+        return;
+    }
+
+    if (value.constant())
+        storeValue(value.value(), dest);
+    else
+        storeValue(ValueTypeFromMIRType(valueType), value.reg().typedReg().gpr(), dest);
+
+}
+
+template void
+MacroAssembler::storeUnboxedValue(ConstantOrRegister value, MIRType valueType,
+                                  const Address& dest, MIRType slotType);
+template void
+MacroAssembler::storeUnboxedValue(ConstantOrRegister value, MIRType valueType,
+                                  const BaseIndex& dest, MIRType slotType);
+
 //}}} check_macroassembler_style
 
 } // namespace jit
 } // namespace js
--- a/js/src/jit/arm64/MacroAssembler-arm64.h
+++ b/js/src/jit/arm64/MacroAssembler-arm64.h
@@ -279,44 +279,16 @@ class MacroAssemblerCompat : public vixl
     void storeValue(ValueOperand val, BaseIndex dest) {
         storePtr(val.valueReg(), dest);
     }
     void storeValue(const Address& src, const Address& dest, Register temp) {
         loadPtr(src, temp);
         storePtr(temp, dest);
     }
 
-    template <typename T>
-    void storeUnboxedValue(ConstantOrRegister value, MIRType valueType, const T& dest, MIRType slotType) {
-        if (valueType == MIRType::Double) {
-            storeDouble(value.reg().typedReg().fpu(), dest);
-            return;
-        }
-
-        // For known integers and booleans, we can just store the unboxed value if
-        // the slot has the same type.
-        if ((valueType == MIRType::Int32 || valueType == MIRType::Boolean) && slotType == valueType) {
-            if (value.constant()) {
-                Value val = value.value();
-                if (valueType == MIRType::Int32)
-                    store32(Imm32(val.toInt32()), dest);
-                else
-                    store32(Imm32(val.toBoolean() ? 1 : 0), dest);
-            } else {
-                store32(value.reg().typedReg().gpr(), dest);
-            }
-            return;
-        }
-
-        if (value.constant())
-            storeValue(value.value(), dest);
-        else
-            storeValue(ValueTypeFromMIRType(valueType), value.reg().typedReg().gpr(), dest);
-
-    }
     void loadValue(Address src, Register val) {
         Ldr(ARMRegister(val, 64), MemOperand(src));
     }
     void loadValue(Address src, ValueOperand val) {
         Ldr(ARMRegister(val.valueReg(), 64), MemOperand(src));
     }
     void loadValue(const BaseIndex& src, ValueOperand val) {
         doBaseIndex(ARMRegister(val.valueReg(), 64), src, vixl::LDR_x);
@@ -968,18 +940,16 @@ class MacroAssemblerCompat : public vixl
     void storeAlignedSimd128Int(FloatRegister src, const BaseIndex& addr) { MOZ_CRASH("NYI"); }
     void loadUnalignedSimd128Int(const Address& addr, FloatRegister dest) { MOZ_CRASH("NYI"); }
     void loadUnalignedSimd128Int(const BaseIndex& addr, FloatRegister dest) { MOZ_CRASH("NYI"); }
     void storeUnalignedSimd128Int(FloatRegister dest, const Address& addr) { MOZ_CRASH("NYI"); }
     void storeUnalignedSimd128Int(FloatRegister dest, const BaseIndex& addr) { MOZ_CRASH("NYI"); }
 
     void loadFloat32x3(const Address& src, FloatRegister dest) { MOZ_CRASH("NYI"); }
     void loadFloat32x3(const BaseIndex& src, FloatRegister dest) { MOZ_CRASH("NYI"); }
-    void storeFloat32x3(FloatRegister src, const Address& dest) { MOZ_CRASH("NYI"); }
-    void storeFloat32x3(FloatRegister src, const BaseIndex& dest) { MOZ_CRASH("NYI"); }
     void loadAlignedSimd128Float(const Address& addr, FloatRegister dest) { MOZ_CRASH("NYI"); }
     void loadAlignedSimd128Float(const BaseIndex& addr, FloatRegister dest) { MOZ_CRASH("NYI"); }
     void storeAlignedSimd128Float(FloatRegister src, const Address& addr) { MOZ_CRASH("NYI"); }
     void storeAlignedSimd128Float(FloatRegister src, const BaseIndex& addr) { MOZ_CRASH("NYI"); }
     void loadUnalignedSimd128Float(const Address& addr, FloatRegister dest) { MOZ_CRASH("NYI"); }
     void loadUnalignedSimd128Float(const BaseIndex& addr, FloatRegister dest) { MOZ_CRASH("NYI"); }
     void storeUnalignedSimd128Float(FloatRegister dest, const Address& addr) { MOZ_CRASH("NYI"); }
     void storeUnalignedSimd128Float(FloatRegister dest, const BaseIndex& addr) { MOZ_CRASH("NYI"); }
@@ -1158,30 +1128,16 @@ class MacroAssemblerCompat : public vixl
             MOZ_ASSERT(scratch64.asUnsized() != src.base);
             MOZ_ASSERT(scratch64.asUnsized() != src.index);
 
             Add(scratch64, base, Operand(index, vixl::LSL, unsigned(src.scale)));
             Ldr(ARMFPRegister(dest, 32), MemOperand(scratch64, src.offset));
         }
     }
 
-    void storeDouble(FloatRegister src, const Address& dest) {
-        Str(ARMFPRegister(src, 64), MemOperand(ARMRegister(dest.base, 64), dest.offset));
-    }
-    void storeDouble(FloatRegister src, const BaseIndex& dest) {
-        doBaseIndex(ARMFPRegister(src, 64), dest, vixl::STR_d);
-    }
-
-    void storeFloat32(FloatRegister src, Address addr) {
-        Str(ARMFPRegister(src, 32), MemOperand(ARMRegister(addr.base, 64), addr.offset));
-    }
-    void storeFloat32(FloatRegister src, BaseIndex addr) {
-        doBaseIndex(ARMFPRegister(src, 32), addr, vixl::STR_s);
-    }
-
     void moveDouble(FloatRegister src, FloatRegister dest) {
         fmov(ARMFPRegister(dest, 64), ARMFPRegister(src, 64));
     }
     void zeroDouble(FloatRegister reg) {
         fmov(ARMFPRegister(reg, 64), vixl::xzr);
     }
     void zeroFloat32(FloatRegister reg) {
         fmov(ARMFPRegister(reg, 32), vixl::wzr);
--- a/js/src/jit/mips-shared/MacroAssembler-mips-shared-inl.h
+++ b/js/src/jit/mips-shared/MacroAssembler-mips-shared-inl.h
@@ -744,15 +744,28 @@ MacroAssembler::branchTestMagic(Conditio
 void
 MacroAssembler::branchTestMagic(Condition cond, const BaseIndex& address, Label* label)
 {
     SecondScratchRegisterScope scratch2(*this);
     extractTag(address, scratch2);
     branchTestMagic(cond, scratch2, label);
 }
 
+// ========================================================================
+// Memory access primitives.
+void
+MacroAssembler::storeFloat32x3(FloatRegister src, const Address& dest)
+{
+    MOZ_CRASH("NYI");
+}
+void
+MacroAssembler::storeFloat32x3(FloatRegister src, const BaseIndex& dest)
+{
+    MOZ_CRASH("NYI");
+}
+
 //}}} check_macroassembler_style
 // ===============================================================
 
 } // namespace jit
 } // namespace js
 
 #endif /* jit_mips_shared_MacroAssembler_mips_shared_inl_h */
--- a/js/src/jit/mips32/MacroAssembler-mips32-inl.h
+++ b/js/src/jit/mips32/MacroAssembler-mips32-inl.h
@@ -415,16 +415,42 @@ MacroAssembler::branchTestMagic(Conditio
 
 void
 MacroAssembler::branchTestMagic(Condition cond, const Address& valaddr, JSWhyMagic why, Label* label)
 {
     branchTestMagic(cond, valaddr, label);
     branch32(cond, ToPayload(valaddr), Imm32(why), label);
 }
 
+// ========================================================================
+// Memory access primitives.
+void
+MacroAssembler::storeDouble(FloatRegister src, const Address& addr)
+{
+    ma_sd(src, addr);
+}
+void
+MacroAssembler::storeDouble(FloatRegister src, const BaseIndex& addr)
+{
+    MOZ_ASSERT(addr.offset == 0);
+    ma_sd(src, addr);
+}
+
+void
+MacroAssembler::storeFloat32(FloatRegister src, const Address& addr)
+{
+    ma_ss(src, addr);
+}
+void
+MacroAssembler::storeFloat32(FloatRegister src, const BaseIndex& addr)
+{
+    MOZ_ASSERT(addr.offset == 0);
+    ma_ss(src, addr);
+}
+
 //}}} check_macroassembler_style
 // ===============================================================
 
 void
 MacroAssemblerMIPSCompat::incrementInt32Value(const Address& addr)
 {
     asMasm().add32(Imm32(1), ToPayload(addr));
 }
--- a/js/src/jit/mips32/MacroAssembler-mips32.cpp
+++ b/js/src/jit/mips32/MacroAssembler-mips32.cpp
@@ -1410,45 +1410,16 @@ MacroAssemblerMIPSCompat::extractTag(con
 
 uint32_t
 MacroAssemblerMIPSCompat::getType(const Value& val)
 {
     jsval_layout jv = JSVAL_TO_IMPL(val);
     return jv.s.tag;
 }
 
-template <typename T>
-void
-MacroAssemblerMIPSCompat::storeUnboxedValue(ConstantOrRegister value, MIRType valueType, const T& dest,
-                                            MIRType slotType)
-{
-    if (valueType == MIRType::Double) {
-        storeDouble(value.reg().typedReg().fpu(), dest);
-        return;
-    }
-
-    // Store the type tag if needed.
-    if (valueType != slotType)
-        storeTypeTag(ImmType(ValueTypeFromMIRType(valueType)), dest);
-
-    // Store the payload.
-    if (value.constant())
-        storePayload(value.value(), dest);
-    else
-        storePayload(value.reg().typedReg().gpr(), dest);
-}
-
-template void
-MacroAssemblerMIPSCompat::storeUnboxedValue(ConstantOrRegister value, MIRType valueType, const Address& dest,
-                                            MIRType slotType);
-
-template void
-MacroAssemblerMIPSCompat::storeUnboxedValue(ConstantOrRegister value, MIRType valueType, const BaseIndex& dest,
-                                            MIRType slotType);
-
 void
 MacroAssemblerMIPSCompat::moveData(const Value& val, Register data)
 {
     jsval_layout jv = JSVAL_TO_IMPL(val);
     if (val.isMarkable())
         ma_li(data, ImmGCPtr(reinterpret_cast<gc::Cell*>(val.toGCThing())));
     else
         ma_li(data, Imm32(jv.s.payload.i32));
@@ -2249,9 +2220,39 @@ MacroAssembler::branchTestValue(Conditio
         bind(&done);
     } else {
         ma_b(lhs.payloadReg(), scratch, label, NotEqual);
 
         ma_b(lhs.typeReg(), Imm32(getType(rhs)), label, NotEqual);
     }
 }
 
+// ========================================================================
+// Memory access primitives.
+template <typename T>
+void
+MacroAssembler::storeUnboxedValue(ConstantOrRegister value, MIRType valueType, const T& dest,
+                                  MIRType slotType)
+{
+    if (valueType == MIRType::Double) {
+        storeDouble(value.reg().typedReg().fpu(), dest);
+        return;
+    }
+
+    // Store the type tag if needed.
+    if (valueType != slotType)
+        storeTypeTag(ImmType(ValueTypeFromMIRType(valueType)), dest);
+
+    // Store the payload.
+    if (value.constant())
+        storePayload(value.value(), dest);
+    else
+        storePayload(value.reg().typedReg().gpr(), dest);
+}
+
+template void
+MacroAssembler::storeUnboxedValue(ConstantOrRegister value, MIRType valueType, const Address& dest,
+                                  MIRType slotType);
+template void
+MacroAssembler::storeUnboxedValue(ConstantOrRegister value, MIRType valueType, const BaseIndex& dest,
+                                  MIRType slotType);
+
 //}}} check_macroassembler_style
--- a/js/src/jit/mips32/MacroAssembler-mips32.h
+++ b/js/src/jit/mips32/MacroAssembler-mips32.h
@@ -875,18 +875,16 @@ class MacroAssemblerMIPSCompat : public 
     void storeAlignedSimd128Int(FloatRegister src, Address addr) { MOZ_CRASH("NYI"); }
     void loadUnalignedSimd128Int(const Address& addr, FloatRegister dest) { MOZ_CRASH("NYI"); }
     void loadUnalignedSimd128Int(const BaseIndex& addr, FloatRegister dest) { MOZ_CRASH("NYI"); }
     void storeUnalignedSimd128Int(FloatRegister src, Address addr) { MOZ_CRASH("NYI"); }
     void storeUnalignedSimd128Int(FloatRegister src, BaseIndex addr) { MOZ_CRASH("NYI"); }
 
     void loadFloat32x3(const Address& src, FloatRegister dest) { MOZ_CRASH("NYI"); }
     void loadFloat32x3(const BaseIndex& src, FloatRegister dest) { MOZ_CRASH("NYI"); }
-    void storeFloat32x3(FloatRegister src, const Address& dest) { MOZ_CRASH("NYI"); }
-    void storeFloat32x3(FloatRegister src, const BaseIndex& dest) { MOZ_CRASH("NYI"); }
     void loadAlignedSimd128Float(const Address& addr, FloatRegister dest) { MOZ_CRASH("NYI"); }
     void storeAlignedSimd128Float(FloatRegister src, Address addr) { MOZ_CRASH("NYI"); }
     void loadUnalignedSimd128Float(const Address& addr, FloatRegister dest) { MOZ_CRASH("NYI"); }
     void loadUnalignedSimd128Float(const BaseIndex& addr, FloatRegister dest) { MOZ_CRASH("NYI"); }
     void storeUnalignedSimd128Float(FloatRegister src, Address addr) { MOZ_CRASH("NYI"); }
     void storeUnalignedSimd128Float(FloatRegister src, BaseIndex addr) { MOZ_CRASH("NYI"); }
 
     void loadDouble(const Address& addr, FloatRegister dest);
@@ -927,35 +925,20 @@ class MacroAssemblerMIPSCompat : public 
     }
 
     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);
     void storePtr(Register src, const Address& address);
     void storePtr(Register src, const BaseIndex& address);
     void storePtr(Register src, AbsoluteAddress dest);
-    void storeDouble(FloatRegister src, Address addr) {
-        ma_sd(src, addr);
-    }
-    void storeDouble(FloatRegister src, BaseIndex addr) {
-        MOZ_ASSERT(addr.offset == 0);
-        ma_sd(src, addr);
-    }
     void moveDouble(FloatRegister src, FloatRegister dest) {
         as_movd(dest, src);
     }
 
-    void storeFloat32(FloatRegister src, Address addr) {
-        ma_ss(src, addr);
-    }
-    void storeFloat32(FloatRegister src, BaseIndex addr) {
-        MOZ_ASSERT(addr.offset == 0);
-        ma_ss(src, addr);
-    }
-
     void zeroDouble(FloatRegister reg) {
         moveToDoubleLo(zero, reg);
         moveToDoubleHi(zero, reg);
     }
 
     void clampIntToUint8(Register reg);
 
     void convertUInt64ToDouble(Register64 src, Register temp, FloatRegister dest);
--- a/js/src/jit/mips64/MacroAssembler-mips64-inl.h
+++ b/js/src/jit/mips64/MacroAssembler-mips64-inl.h
@@ -372,16 +372,42 @@ void
 MacroAssembler::branchTestMagic(Condition cond, const Address& valaddr, JSWhyMagic why, Label* label)
 {
     uint64_t magic = MagicValue(why).asRawBits();
     ScratchRegisterScope scratch(*this);
     loadPtr(valaddr, scratch);
     ma_b(scratch, ImmWord(magic), label, cond);
 }
 
+// ========================================================================
+// Memory access primitives.
+void
+MacroAssembler::storeDouble(FloatRegister src, const Address& addr)
+{
+    ma_sd(src, addr);
+}
+void
+MacroAssembler::storeDouble(FloatRegister src, const BaseIndex& addr)
+{
+    MOZ_ASSERT(addr.offset == 0);
+    ma_sd(src, addr);
+}
+
+void
+MacroAssembler::storeFloat32(FloatRegister src, const Address& addr)
+{
+    ma_ss(src, addr);
+}
+void
+MacroAssembler::storeFloat32(FloatRegister src, const BaseIndex& addr)
+{
+    MOZ_ASSERT(addr.offset == 0);
+    ma_ss(src, addr);
+}
+
 //}}} check_macroassembler_style
 // ===============================================================
 
 void
 MacroAssemblerMIPS64Compat::incrementInt32Value(const Address& addr)
 {
     asMasm().add32(Imm32(1), addr);
 }
--- a/js/src/jit/mips64/MacroAssembler-mips64.cpp
+++ b/js/src/jit/mips64/MacroAssembler-mips64.cpp
@@ -1589,55 +1589,16 @@ MacroAssemblerMIPS64Compat::extractTag(c
 
 Register
 MacroAssemblerMIPS64Compat::extractTag(const BaseIndex& address, Register scratch)
 {
     computeScaledAddress(address, scratch);
     return extractTag(Address(scratch, address.offset), scratch);
 }
 
-template <typename T>
-void
-MacroAssemblerMIPS64Compat::storeUnboxedValue(ConstantOrRegister value, MIRType valueType, const T& dest,
-                                              MIRType slotType)
-{
-    if (valueType == MIRType::Double) {
-        storeDouble(value.reg().typedReg().fpu(), dest);
-        return;
-    }
-
-    // For known integers and booleans, we can just store the unboxed value if
-    // the slot has the same type.
-    if ((valueType == MIRType::Int32 || valueType == MIRType::Boolean) && slotType == valueType) {
-        if (value.constant()) {
-            Value val = value.value();
-            if (valueType == MIRType::Int32)
-                store32(Imm32(val.toInt32()), dest);
-            else
-                store32(Imm32(val.toBoolean() ? 1 : 0), dest);
-        } else {
-            store32(value.reg().typedReg().gpr(), dest);
-        }
-        return;
-    }
-
-    if (value.constant())
-        storeValue(value.value(), dest);
-    else
-        storeValue(ValueTypeFromMIRType(valueType), value.reg().typedReg().gpr(), dest);
-}
-
-template void
-MacroAssemblerMIPS64Compat::storeUnboxedValue(ConstantOrRegister value, MIRType valueType, const Address& dest,
-                                              MIRType slotType);
-
-template void
-MacroAssemblerMIPS64Compat::storeUnboxedValue(ConstantOrRegister value, MIRType valueType, const BaseIndex& dest,
-                                              MIRType slotType);
-
 void
 MacroAssemblerMIPS64Compat::moveValue(const Value& val, Register dest)
 {
     jsval_layout jv = JSVAL_TO_IMPL(val);
     writeDataRelocation(val);
     movWithPatch(ImmWord(jv.asBits), dest);
 }
 
@@ -2354,9 +2315,49 @@ MacroAssembler::branchTestValue(Conditio
                                 const Value& rhs, Label* label)
 {
     MOZ_ASSERT(cond == Equal || cond == NotEqual);
     ScratchRegisterScope scratch(*this);
     moveValue(rhs, scratch);
     ma_b(lhs.valueReg(), scratch, label, cond);
 }
 
+// ========================================================================
+// Memory access primitives.
+template <typename T>
+void
+MacroAssembler::storeUnboxedValue(ConstantOrRegister value, MIRType valueType, const T& dest,
+                                  MIRType slotType)
+{
+    if (valueType == MIRType::Double) {
+        storeDouble(value.reg().typedReg().fpu(), dest);
+        return;
+    }
+
+    // For known integers and booleans, we can just store the unboxed value if
+    // the slot has the same type.
+    if ((valueType == MIRType::Int32 || valueType == MIRType::Boolean) && slotType == valueType) {
+        if (value.constant()) {
+            Value val = value.value();
+            if (valueType == MIRType::Int32)
+                store32(Imm32(val.toInt32()), dest);
+            else
+                store32(Imm32(val.toBoolean() ? 1 : 0), dest);
+        } else {
+            store32(value.reg().typedReg().gpr(), dest);
+        }
+        return;
+    }
+
+    if (value.constant())
+        storeValue(value.value(), dest);
+    else
+        storeValue(ValueTypeFromMIRType(valueType), value.reg().typedReg().gpr(), dest);
+}
+
+template void
+MacroAssembler::storeUnboxedValue(ConstantOrRegister value, MIRType valueType, const Address& dest,
+                                  MIRType slotType);
+template void
+MacroAssembler::storeUnboxedValue(ConstantOrRegister value, MIRType valueType, const BaseIndex& dest,
+                                  MIRType slotType);
+
 //}}} check_macroassembler_style
--- a/js/src/jit/mips64/MacroAssembler-mips64.h
+++ b/js/src/jit/mips64/MacroAssembler-mips64.h
@@ -430,20 +430,16 @@ class MacroAssemblerMIPS64Compat : publi
             unboxInt32(address, dest.gpr());
         else if (type == MIRType::Boolean)
             unboxBoolean(address, dest.gpr());
         else
             unboxNonDouble(address, dest.gpr());
     }
 
     template <typename T>
-    void storeUnboxedValue(ConstantOrRegister value, MIRType valueType, const T& dest,
-                           MIRType slotType);
-
-    template <typename T>
     void storeUnboxedPayload(ValueOperand value, T address, size_t nbytes) {
         switch (nbytes) {
           case 8:
             unboxNonDouble(value, ScratchRegister);
             storePtr(ScratchRegister, address);
             return;
           case 4:
             store32(value.valueReg(), address);
@@ -886,18 +882,16 @@ class MacroAssemblerMIPS64Compat : publi
     void storeAlignedSimd128Int(FloatRegister src, Address addr) { MOZ_CRASH("NYI"); }
     void loadUnalignedSimd128Int(const Address& addr, FloatRegister dest) { MOZ_CRASH("NYI"); }
     void loadUnalignedSimd128Int(const BaseIndex& addr, FloatRegister dest) { MOZ_CRASH("NYI"); }
     void storeUnalignedSimd128Int(FloatRegister src, Address addr) { MOZ_CRASH("NYI"); }
     void storeUnalignedSimd128Int(FloatRegister src, BaseIndex addr) { MOZ_CRASH("NYI"); }
 
     void loadFloat32x3(const Address& src, FloatRegister dest) { MOZ_CRASH("NYI"); }
     void loadFloat32x3(const BaseIndex& src, FloatRegister dest) { MOZ_CRASH("NYI"); }
-    void storeFloat32x3(FloatRegister src, const Address& dest) { MOZ_CRASH("NYI"); }
-    void storeFloat32x3(FloatRegister src, const BaseIndex& dest) { MOZ_CRASH("NYI"); }
     void loadAlignedSimd128Float(const Address& addr, FloatRegister dest) { MOZ_CRASH("NYI"); }
     void storeAlignedSimd128Float(FloatRegister src, Address addr) { MOZ_CRASH("NYI"); }
     void loadUnalignedSimd128Float(const Address& addr, FloatRegister dest) { MOZ_CRASH("NYI"); }
     void loadUnalignedSimd128Float(const BaseIndex& addr, FloatRegister dest) { MOZ_CRASH("NYI"); }
     void storeUnalignedSimd128Float(FloatRegister src, Address addr) { MOZ_CRASH("NYI"); }
     void storeUnalignedSimd128Float(FloatRegister src, BaseIndex addr) { MOZ_CRASH("NYI"); }
 
     void loadDouble(const Address& addr, FloatRegister dest);
@@ -937,35 +931,20 @@ class MacroAssemblerMIPS64Compat : publi
     }
 
     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);
     void storePtr(Register src, const Address& address);
     void storePtr(Register src, const BaseIndex& address);
     void storePtr(Register src, AbsoluteAddress dest);
-    void storeDouble(FloatRegister src, Address addr) {
-        ma_sd(src, addr);
-    }
-    void storeDouble(FloatRegister src, BaseIndex addr) {
-        MOZ_ASSERT(addr.offset == 0);
-        ma_sd(src, addr);
-    }
     void moveDouble(FloatRegister src, FloatRegister dest) {
         as_movd(dest, src);
     }
 
-    void storeFloat32(FloatRegister src, Address addr) {
-        ma_ss(src, addr);
-    }
-    void storeFloat32(FloatRegister src, BaseIndex addr) {
-        MOZ_ASSERT(addr.offset == 0);
-        ma_ss(src, addr);
-    }
-
     void zeroDouble(FloatRegister reg) {
         moveToDouble(zero, reg);
     }
 
     void clampIntToUint8(Register reg);
 
     void convertUInt64ToDouble(Register64 src, Register temp, FloatRegister dest);
 
--- a/js/src/jit/x64/MacroAssembler-x64.cpp
+++ b/js/src/jit/x64/MacroAssembler-x64.cpp
@@ -212,55 +212,16 @@ MacroAssemblerX64::handleFailureWithHand
     // If we are bailing out to baseline to handle an exception, jump to
     // the bailout tail stub.
     bind(&bailout);
     loadPtr(Address(esp, offsetof(ResumeFromException, bailoutInfo)), r9);
     mov(ImmWord(BAILOUT_RETURN_OK), rax);
     jmp(Operand(rsp, offsetof(ResumeFromException, target)));
 }
 
-template <typename T>
-void
-MacroAssemblerX64::storeUnboxedValue(ConstantOrRegister value, MIRType valueType, const T& dest,
-                                     MIRType slotType)
-{
-    if (valueType == MIRType::Double) {
-        storeDouble(value.reg().typedReg().fpu(), dest);
-        return;
-    }
-
-    // For known integers and booleans, we can just store the unboxed value if
-    // the slot has the same type.
-    if ((valueType == MIRType::Int32 || valueType == MIRType::Boolean) && slotType == valueType) {
-        if (value.constant()) {
-            Value val = value.value();
-            if (valueType == MIRType::Int32)
-                store32(Imm32(val.toInt32()), dest);
-            else
-                store32(Imm32(val.toBoolean() ? 1 : 0), dest);
-        } else {
-            store32(value.reg().typedReg().gpr(), dest);
-        }
-        return;
-    }
-
-    if (value.constant())
-        storeValue(value.value(), dest);
-    else
-        storeValue(ValueTypeFromMIRType(valueType), value.reg().typedReg().gpr(), dest);
-}
-
-template void
-MacroAssemblerX64::storeUnboxedValue(ConstantOrRegister value, MIRType valueType, const Address& dest,
-                                     MIRType slotType);
-
-template void
-MacroAssemblerX64::storeUnboxedValue(ConstantOrRegister value, MIRType valueType, const BaseIndex& dest,
-                                     MIRType slotType);
-
 void
 MacroAssemblerX64::profilerEnterFrame(Register framePtr, Register scratch)
 {
     AbsoluteAddress activation(GetJitContext()->runtime->addressOfProfilingActivation());
     loadPtr(activation, scratch);
     storePtr(framePtr, Address(scratch, JitActivation::offsetOfLastProfilingFrame()));
     storePtr(ImmPtr(nullptr), Address(scratch, JitActivation::offsetOfLastProfilingCallSite()));
 }
@@ -481,9 +442,48 @@ MacroAssembler::branchTestValue(Conditio
     MOZ_ASSERT(cond == Equal || cond == NotEqual);
     ScratchRegisterScope scratch(*this);
     MOZ_ASSERT(lhs.valueReg() != scratch);
     moveValue(rhs, scratch);
     cmpPtr(lhs.valueReg(), scratch);
     j(cond, label);
 }
 
+// ========================================================================
+// Memory access primitives.
+template <typename T>
+void
+MacroAssembler::storeUnboxedValue(ConstantOrRegister value, MIRType valueType, const T& dest,
+                                  MIRType slotType)
+{
+    if (valueType == MIRType::Double) {
+        storeDouble(value.reg().typedReg().fpu(), dest);
+        return;
+    }
+
+    // For known integers and booleans, we can just store the unboxed value if
+    // the slot has the same type.
+    if ((valueType == MIRType::Int32 || valueType == MIRType::Boolean) && slotType == valueType) {
+        if (value.constant()) {
+            Value val = value.value();
+            if (valueType == MIRType::Int32)
+                store32(Imm32(val.toInt32()), dest);
+            else
+                store32(Imm32(val.toBoolean() ? 1 : 0), dest);
+        } else {
+            store32(value.reg().typedReg().gpr(), dest);
+        }
+        return;
+    }
+
+    if (value.constant())
+        storeValue(value.value(), dest);
+    else
+        storeValue(ValueTypeFromMIRType(valueType), value.reg().typedReg().gpr(), dest);
+}
+
+template void
+MacroAssembler::storeUnboxedValue(ConstantOrRegister value, MIRType valueType, const Address& dest,
+                                  MIRType slotType);
+template void
+MacroAssembler::storeUnboxedValue(ConstantOrRegister value, MIRType valueType, const BaseIndex& dest,
+                                  MIRType slotType);
 //}}} check_macroassembler_style
--- a/js/src/jit/x64/MacroAssembler-x64.h
+++ b/js/src/jit/x64/MacroAssembler-x64.h
@@ -884,19 +884,16 @@ class MacroAssemblerX64 : public MacroAs
             loadInt32OrDouble(src, dest.fpu());
         else if (type == MIRType::Int32 || type == MIRType::Boolean)
             movl(Operand(src), dest.gpr());
         else
             unboxNonDouble(Operand(src), dest.gpr());
     }
 
     template <typename T>
-    void storeUnboxedValue(ConstantOrRegister value, MIRType valueType, const T& dest, MIRType slotType);
-
-    template <typename T>
     void storeUnboxedPayload(ValueOperand value, T address, size_t nbytes) {
         switch (nbytes) {
           case 8: {
             ScratchRegisterScope scratch(asMasm());
             unboxNonDouble(value, scratch);
             storePtr(scratch, address);
             return;
           }
--- a/js/src/jit/x86-shared/MacroAssembler-x86-shared-inl.h
+++ b/js/src/jit/x86-shared/MacroAssembler-x86-shared-inl.h
@@ -905,16 +905,89 @@ MacroAssembler::branchTestMagic(Conditio
 template <typename T, class L>
 void
 MacroAssembler::branchTestMagicImpl(Condition cond, const T& t, L label)
 {
     cond = testMagic(cond, t);
     j(cond, label);
 }
 
+// ========================================================================
+// Memory access primitives.
+void
+MacroAssembler::storeDouble(FloatRegister src, const Address& dest)
+{
+    vmovsd(src, dest);
+}
+void
+MacroAssembler::storeDouble(FloatRegister src, const BaseIndex& dest)
+{
+    vmovsd(src, dest);
+}
+void
+MacroAssembler::storeDouble(FloatRegister src, const Operand& dest)
+{
+    switch (dest.kind()) {
+      case Operand::MEM_REG_DISP:
+        storeDouble(src, dest.toAddress());
+        break;
+      case Operand::MEM_SCALE:
+        storeDouble(src, dest.toBaseIndex());
+        break;
+      default:
+        MOZ_CRASH("unexpected operand kind");
+    }
+}
+
+void
+MacroAssembler::storeFloat32(FloatRegister src, const Address& dest)
+{
+    vmovss(src, dest);
+}
+void
+MacroAssembler::storeFloat32(FloatRegister src, const BaseIndex& dest)
+{
+    vmovss(src, dest);
+}
+void
+MacroAssembler::storeFloat32(FloatRegister src, const Operand& dest)
+{
+    switch (dest.kind()) {
+      case Operand::MEM_REG_DISP:
+        storeFloat32(src, dest.toAddress());
+        break;
+      case Operand::MEM_SCALE:
+        storeFloat32(src, dest.toBaseIndex());
+        break;
+      default:
+        MOZ_CRASH("unexpected operand kind");
+    }
+}
+
+void
+MacroAssembler::storeFloat32x3(FloatRegister src, const Address& dest)
+{
+    Address destZ(dest);
+    destZ.offset += 2 * sizeof(int32_t);
+    storeDouble(src, dest);
+    ScratchSimd128Scope scratch(*this);
+    vmovhlps(src, scratch, scratch);
+    storeFloat32(scratch, destZ);
+}
+void
+MacroAssembler::storeFloat32x3(FloatRegister src, const BaseIndex& dest)
+{
+    BaseIndex destZ(dest);
+    destZ.offset += 2 * sizeof(int32_t);
+    storeDouble(src, dest);
+    ScratchSimd128Scope scratch(*this);
+    vmovhlps(src, scratch, scratch);
+    storeFloat32(scratch, destZ);
+}
+
 //}}} check_macroassembler_style
 // ===============================================================
 
 void
 MacroAssemblerX86Shared::clampIntToUint8(Register reg)
 {
     Label inRange;
     asMasm().branchTest32(Assembler::Zero, reg, Imm32(0xffffff00), &inRange);
--- a/js/src/jit/x86-shared/MacroAssembler-x86-shared.h
+++ b/js/src/jit/x86-shared/MacroAssembler-x86-shared.h
@@ -771,34 +771,16 @@ class MacroAssemblerX86Shared : public A
             break;
           case Operand::MEM_SCALE:
             loadDouble(src.toBaseIndex(), dest);
             break;
           default:
             MOZ_CRASH("unexpected operand kind");
         }
     }
-    void storeDouble(FloatRegister src, const Address& dest) {
-        vmovsd(src, dest);
-    }
-    void storeDouble(FloatRegister src, const BaseIndex& dest) {
-        vmovsd(src, dest);
-    }
-    void storeDouble(FloatRegister src, const Operand& dest) {
-        switch (dest.kind()) {
-          case Operand::MEM_REG_DISP:
-            storeDouble(src, dest.toAddress());
-            break;
-          case Operand::MEM_SCALE:
-            storeDouble(src, dest.toBaseIndex());
-            break;
-          default:
-            MOZ_CRASH("unexpected operand kind");
-        }
-    }
     void moveDouble(FloatRegister src, FloatRegister dest) {
         // Use vmovapd instead of vmovsd to avoid dependencies.
         vmovapd(src, dest);
     }
     void zeroDouble(FloatRegister reg) {
         vxorpd(reg, reg, reg);
     }
     void zeroFloat32(FloatRegister reg) {
@@ -1015,32 +997,16 @@ class MacroAssemblerX86Shared : public A
 
     void loadAlignedSimd128Float(const Address& src, FloatRegister dest) {
         vmovaps(Operand(src), dest);
     }
     void loadAlignedSimd128Float(const Operand& src, FloatRegister dest) {
         vmovaps(src, dest);
     }
 
-    void storeFloat32x3(FloatRegister src, const Address& dest) {
-        Address destZ(dest);
-        destZ.offset += 2 * sizeof(int32_t);
-        storeDouble(src, dest);
-        ScratchSimd128Scope scratch(asMasm());
-        vmovhlps(src, scratch, scratch);
-        storeFloat32(scratch, destZ);
-    }
-    void storeFloat32x3(FloatRegister src, const BaseIndex& dest) {
-        BaseIndex destZ(dest);
-        destZ.offset += 2 * sizeof(int32_t);
-        storeDouble(src, dest);
-        ScratchSimd128Scope scratch(asMasm());
-        vmovhlps(src, scratch, scratch);
-        storeFloat32(scratch, destZ);
-    }
     void storeAlignedSimd128Float(FloatRegister src, const Address& dest) {
         vmovaps(src, Operand(dest));
     }
     void moveSimd128Float(FloatRegister src, FloatRegister dest) {
         vmovaps(src, dest);
     }
     FloatRegister reusedInputFloat32x4(FloatRegister src, FloatRegister dest) {
         if (HasAVX())
@@ -1148,34 +1114,16 @@ class MacroAssemblerX86Shared : public A
             break;
           case Operand::MEM_SCALE:
             loadFloat32(src.toBaseIndex(), dest);
             break;
           default:
             MOZ_CRASH("unexpected operand kind");
         }
     }
-    void storeFloat32(FloatRegister src, const Address& dest) {
-        vmovss(src, dest);
-    }
-    void storeFloat32(FloatRegister src, const BaseIndex& dest) {
-        vmovss(src, dest);
-    }
-    void storeFloat32(FloatRegister src, const Operand& dest) {
-        switch (dest.kind()) {
-          case Operand::MEM_REG_DISP:
-            storeFloat32(src, dest.toAddress());
-            break;
-          case Operand::MEM_SCALE:
-            storeFloat32(src, dest.toBaseIndex());
-            break;
-          default:
-            MOZ_CRASH("unexpected operand kind");
-        }
-    }
     void moveFloat32(FloatRegister src, FloatRegister dest) {
         // Use vmovaps instead of vmovss to avoid dependencies.
         vmovaps(src, dest);
     }
 
     // Checks whether a double is representable as a 32-bit integer. If so, the
     // integer is written to the output register. Otherwise, a bailout is taken to
     // the given snapshot. This function overwrites the scratch float register.
@@ -1381,17 +1329,17 @@ MacroAssemblerX86Shared::loadScalar<floa
 }
 
 template <> inline void
 MacroAssemblerX86Shared::storeScalar<int32_t>(Register src, const Address& dest) {
     store32(src, dest);
 }
 template <> inline void
 MacroAssemblerX86Shared::storeScalar<float>(FloatRegister src, const Address& dest) {
-    storeFloat32(src, dest);
+    vmovss(src, dest);
 }
 
 } // namespace jit
 } // namespace js
 
 #undef CHECK_BYTEREG
 #undef CHECK_BYTEREGS
 
--- a/js/src/jit/x86/MacroAssembler-x86.cpp
+++ b/js/src/jit/x86/MacroAssembler-x86.cpp
@@ -260,45 +260,16 @@ MacroAssemblerX86::handleFailureWithHand
     // If we are bailing out to baseline to handle an exception, jump to
     // the bailout tail stub.
     bind(&bailout);
     loadPtr(Address(esp, offsetof(ResumeFromException, bailoutInfo)), ecx);
     movl(Imm32(BAILOUT_RETURN_OK), eax);
     jmp(Operand(esp, offsetof(ResumeFromException, target)));
 }
 
-template <typename T>
-void
-MacroAssemblerX86::storeUnboxedValue(ConstantOrRegister value, MIRType valueType, const T& dest,
-                                     MIRType slotType)
-{
-    if (valueType == MIRType::Double) {
-        storeDouble(value.reg().typedReg().fpu(), dest);
-        return;
-    }
-
-    // Store the type tag if needed.
-    if (valueType != slotType)
-        storeTypeTag(ImmType(ValueTypeFromMIRType(valueType)), Operand(dest));
-
-    // Store the payload.
-    if (value.constant())
-        storePayload(value.value(), Operand(dest));
-    else
-        storePayload(value.reg().typedReg().gpr(), Operand(dest));
-}
-
-template void
-MacroAssemblerX86::storeUnboxedValue(ConstantOrRegister value, MIRType valueType, const Address& dest,
-                                     MIRType slotType);
-
-template void
-MacroAssemblerX86::storeUnboxedValue(ConstantOrRegister value, MIRType valueType, const BaseIndex& dest,
-                                     MIRType slotType);
-
 void
 MacroAssemblerX86::profilerEnterFrame(Register framePtr, Register scratch)
 {
     AbsoluteAddress activation(GetJitContext()->runtime->addressOfProfilingActivation());
     loadPtr(activation, scratch);
     storePtr(framePtr, Address(scratch, JitActivation::offsetOfLastProfilingFrame()));
     storePtr(ImmPtr(nullptr), Address(scratch, JitActivation::offsetOfLastProfilingCallSite()));
 }
@@ -518,9 +489,39 @@ MacroAssembler::branchTestValue(Conditio
     } else {
         j(NotEqual, label);
 
         cmp32(lhs.typeReg(), Imm32(jv.s.tag));
         j(NotEqual, label);
     }
 }
 
+// ========================================================================
+// Memory access primitives.
+template <typename T>
+void
+MacroAssembler::storeUnboxedValue(ConstantOrRegister value, MIRType valueType, const T& dest,
+                                     MIRType slotType)
+{
+    if (valueType == MIRType::Double) {
+        storeDouble(value.reg().typedReg().fpu(), dest);
+        return;
+    }
+
+    // Store the type tag if needed.
+    if (valueType != slotType)
+        storeTypeTag(ImmType(ValueTypeFromMIRType(valueType)), Operand(dest));
+
+    // Store the payload.
+    if (value.constant())
+        storePayload(value.value(), Operand(dest));
+    else
+        storePayload(value.reg().typedReg().gpr(), Operand(dest));
+}
+
+template void
+MacroAssembler::storeUnboxedValue(ConstantOrRegister value, MIRType valueType, const Address& dest,
+                                     MIRType slotType);
+template void
+MacroAssembler::storeUnboxedValue(ConstantOrRegister value, MIRType valueType, const BaseIndex& dest,
+                                     MIRType slotType);
+
 //}}} check_macroassembler_style
--- a/js/src/jit/x86/MacroAssembler-x86.h
+++ b/js/src/jit/x86/MacroAssembler-x86.h
@@ -800,20 +800,16 @@ class MacroAssemblerX86 : public MacroAs
 
     template <typename T>
     inline void loadInt32OrDouble(const T& src, FloatRegister dest);
 
     template <typename T>
     inline void loadUnboxedValue(const T& src, MIRType type, AnyRegister dest);
 
     template <typename T>
-    void storeUnboxedValue(ConstantOrRegister value, MIRType valueType, const T& dest,
-                           MIRType slotType);
-
-    template <typename T>
     void storeUnboxedPayload(ValueOperand value, T address, size_t nbytes) {
         switch (nbytes) {
           case 4:
             storePtr(value.payloadReg(), address);
             return;
           case 1:
             store8(value.payloadReg(), address);
             return;