Bug 1168807 - Move MacroAssemblerSpecific::framePushed_ fields to the generic MacroAssembler. r=jandem
authorNicolas B. Pierron <nicolas.b.pierron@mozilla.com>
Mon, 01 Jun 2015 15:15:07 +0200
changeset 277333 06ca9c794fd0e417162368e3d24cf14d5f0b0435
parent 277332 ff36a419222a50e3b534aaae9a39a2e273228c5f
child 277334 0af01d7abf3d5076b80c615fb1298d5558ba2afc
push id4932
push userjlund@mozilla.com
push dateMon, 10 Aug 2015 18:23:06 +0000
treeherdermozilla-beta@6dd5a4f5f745 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjandem
bugs1168807
milestone41.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 1168807 - Move MacroAssemblerSpecific::framePushed_ fields to the generic MacroAssembler. r=jandem
js/src/asmjs/AsmJSFrameIterator.cpp
js/src/asmjs/AsmJSModule.cpp
js/src/asmjs/AsmJSValidate.cpp
js/src/irregexp/NativeRegExpMacroAssembler.cpp
js/src/jit/CodeGenerator.cpp
js/src/jit/IonCaches.cpp
js/src/jit/MacroAssembler-inl.h
js/src/jit/MacroAssembler.cpp
js/src/jit/MacroAssembler.h
js/src/jit/arm/CodeGenerator-arm.cpp
js/src/jit/arm/CodeGenerator-arm.h
js/src/jit/arm/MacroAssembler-arm.cpp
js/src/jit/arm/MacroAssembler-arm.h
js/src/jit/arm/MoveEmitter-arm.cpp
js/src/jit/arm/Trampoline-arm.cpp
js/src/jit/mips/CodeGenerator-mips.cpp
js/src/jit/mips/CodeGenerator-mips.h
js/src/jit/mips/MacroAssembler-mips.cpp
js/src/jit/mips/MacroAssembler-mips.h
js/src/jit/mips/MoveEmitter-mips.cpp
js/src/jit/mips/Trampoline-mips.cpp
js/src/jit/none/CodeGenerator-none.h
js/src/jit/none/MacroAssembler-none.h
js/src/jit/none/Trampoline-none.cpp
js/src/jit/shared/BaselineCompiler-shared.cpp
js/src/jit/shared/BaselineCompiler-shared.h
js/src/jit/shared/CodeGenerator-shared-inl.h
js/src/jit/shared/CodeGenerator-shared.cpp
js/src/jit/shared/CodeGenerator-shared.h
js/src/jit/x64/MacroAssembler-x64.cpp
js/src/jit/x64/MacroAssembler-x64.h
js/src/jit/x86-shared/CodeGenerator-x86-shared.cpp
js/src/jit/x86-shared/CodeGenerator-x86-shared.h
js/src/jit/x86-shared/MacroAssembler-x86-shared.cpp
js/src/jit/x86-shared/MacroAssembler-x86-shared.h
js/src/jit/x86-shared/MoveEmitter-x86-shared.cpp
js/src/jit/x86/MacroAssembler-x86.cpp
js/src/jit/x86/MacroAssembler-x86.h
--- a/js/src/asmjs/AsmJSFrameIterator.cpp
+++ b/js/src/asmjs/AsmJSFrameIterator.cpp
@@ -17,16 +17,18 @@
  */
 
 #include "asmjs/AsmJSFrameIterator.h"
 
 #include "asmjs/AsmJSModule.h"
 #include "asmjs/AsmJSValidate.h"
 #include "jit/MacroAssembler.h"
 
+#include "jit/MacroAssembler-inl.h"
+
 using namespace js;
 using namespace js::jit;
 
 using mozilla::DebugOnly;
 
 /*****************************************************************************/
 // AsmJSFrameIterator implementation
 
--- a/js/src/asmjs/AsmJSModule.cpp
+++ b/js/src/asmjs/AsmJSModule.cpp
@@ -40,16 +40,17 @@
 #include "jit/IonCode.h"
 #include "js/Class.h"
 #include "js/Conversions.h"
 #include "js/MemoryMetrics.h"
 
 #include "jsobjinlines.h"
 
 #include "frontend/ParseNode-inl.h"
+#include "jit/MacroAssembler-inl.h"
 #include "vm/ArrayBufferObject-inl.h"
 #include "vm/Stack-inl.h"
 
 using namespace js;
 using namespace jit;
 using namespace frontend;
 using mozilla::BinarySearch;
 using mozilla::Compression::LZ4;
--- a/js/src/asmjs/AsmJSValidate.cpp
+++ b/js/src/asmjs/AsmJSValidate.cpp
@@ -44,16 +44,17 @@
 #endif
 #include "vm/HelperThreads.h"
 #include "vm/Interpreter.h"
 
 #include "jsobjinlines.h"
 
 #include "frontend/ParseNode-inl.h"
 #include "frontend/Parser-inl.h"
+#include "jit/MacroAssembler-inl.h"
 
 using namespace js;
 using namespace js::frontend;
 using namespace js::jit;
 
 using mozilla::AddToHash;
 using mozilla::ArrayLength;
 using mozilla::CountLeadingZeroes32;
--- a/js/src/irregexp/NativeRegExpMacroAssembler.cpp
+++ b/js/src/irregexp/NativeRegExpMacroAssembler.cpp
@@ -32,16 +32,18 @@
 
 #include "irregexp/RegExpStack.h"
 #include "jit/Linker.h"
 #ifdef JS_ION_PERF
 # include "jit/PerfSpewer.h"
 #endif
 #include "vm/MatchPairs.h"
 
+#include "jit/MacroAssembler-inl.h"
+
 using namespace js;
 using namespace js::irregexp;
 using namespace js::jit;
 
 /*
  * This assembler uses the following register assignment convention:
  *
  * - current_character :
--- a/js/src/jit/CodeGenerator.cpp
+++ b/js/src/jit/CodeGenerator.cpp
@@ -34,16 +34,17 @@
 #include "jit/MoveEmitter.h"
 #include "jit/RangeAnalysis.h"
 #include "vm/MatchPairs.h"
 #include "vm/RegExpStatics.h"
 #include "vm/TraceLogging.h"
 
 #include "jsboolinlines.h"
 
+#include "jit/MacroAssembler-inl.h"
 #include "jit/shared/CodeGenerator-shared-inl.h"
 #include "vm/Interpreter-inl.h"
 
 using namespace js;
 using namespace js::jit;
 
 using mozilla::DebugOnly;
 using mozilla::FloatingPoint;
--- a/js/src/jit/IonCaches.cpp
+++ b/js/src/jit/IonCaches.cpp
@@ -21,16 +21,17 @@
 #ifdef JS_ION_PERF
 # include "jit/PerfSpewer.h"
 #endif
 #include "jit/VMFunctions.h"
 #include "js/Proxy.h"
 #include "vm/Shape.h"
 
 #include "jit/JitFrames-inl.h"
+#include "jit/MacroAssembler-inl.h"
 #include "vm/Interpreter-inl.h"
 #include "vm/Shape-inl.h"
 
 using namespace js;
 using namespace js::jit;
 
 using mozilla::tl::FloorLog2;
 
new file mode 100644
--- /dev/null
+++ b/js/src/jit/MacroAssembler-inl.h
@@ -0,0 +1,117 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef jit_MacroAssembler_inl_h
+#define jit_MacroAssembler_inl_h
+
+#include "jit/MacroAssembler.h"
+
+namespace js {
+namespace jit {
+
+// ===============================================================
+// Frame manipulation functions.
+
+uint32_t
+MacroAssembler::framePushed() const
+{
+    return framePushed_;
+}
+
+void
+MacroAssembler::setFramePushed(uint32_t framePushed)
+{
+    framePushed_ = framePushed;
+}
+
+void
+MacroAssembler::adjustFrame(int value)
+{
+    setFramePushed(framePushed_ + value);
+}
+
+void
+MacroAssembler::implicitPop(uint32_t bytes)
+{
+    MOZ_ASSERT(bytes % sizeof(intptr_t) == 0);
+    adjustFrame(-bytes);
+}
+
+// ===============================================================
+// Stack manipulation functions.
+
+CodeOffsetLabel
+MacroAssembler::PushWithPatch(ImmWord word)
+{
+    framePushed_ += sizeof(word.value);
+    return pushWithPatch(word);
+}
+
+CodeOffsetLabel
+MacroAssembler::PushWithPatch(ImmPtr imm)
+{
+    return PushWithPatch(ImmWord(uintptr_t(imm.value)));
+}
+
+// ===============================================================
+// Call functions.
+
+void
+MacroAssembler::call(const CallSiteDesc& desc, const Register reg)
+{
+    call(reg);
+    append(desc, currentOffset(), framePushed());
+}
+
+void
+MacroAssembler::call(const CallSiteDesc& desc, Label* label)
+{
+    call(label);
+    append(desc, currentOffset(), framePushed());
+}
+
+// ===============================================================
+
+void
+MacroAssembler::PushStubCode()
+{
+    exitCodePatch_ = PushWithPatch(ImmWord(-1));
+}
+
+void
+MacroAssembler::enterExitFrame(const VMFunction* f)
+{
+    linkExitFrame();
+    // Push the ioncode. (Bailout or VM wrapper)
+    PushStubCode();
+    // Push VMFunction pointer, to mark arguments.
+    Push(ImmPtr(f));
+}
+
+void
+MacroAssembler::enterFakeExitFrame(JitCode* codeVal)
+{
+    linkExitFrame();
+    Push(ImmPtr(codeVal));
+    Push(ImmPtr(nullptr));
+}
+
+void
+MacroAssembler::leaveExitFrame(size_t extraFrame)
+{
+    freeStack(ExitFooterFrame::Size() + extraFrame);
+}
+
+bool
+MacroAssembler::hasEnteredExitFrame() const
+{
+    return exitCodePatch_.offset() != 0;
+}
+
+} // namespace jit
+} // namespace js
+
+#endif /* jit_MacroAssembler_inl_h */
--- a/js/src/jit/MacroAssembler.cpp
+++ b/js/src/jit/MacroAssembler.cpp
@@ -1,15 +1,15 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  * vim: set ts=8 sts=4 et sw=4 tw=99:
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-#include "jit/MacroAssembler.h"
+#include "jit/MacroAssembler-inl.h"
 
 #include "jsprf.h"
 
 #include "builtin/TypedObject.h"
 #include "gc/GCTrace.h"
 #include "jit/AtomicOp.h"
 #include "jit/Bailouts.h"
 #include "jit/BaselineFrame.h"
@@ -2473,16 +2473,69 @@ MacroAssembler::alignJitStackBasedOnNArg
         bind(&end);
         assertStackAlignment(JitStackAlignment, sizeof(Value));
     } else {
         andToStackPtr(Imm32(~(JitStackAlignment - 1)));
     }
 }
 
 // ===============================================================
+
+MacroAssembler::MacroAssembler(JSContext* cx, IonScript* ion,
+                               JSScript* script, jsbytecode* pc)
+  : emitProfilingInstrumentation_(false),
+    framePushed_(0)
+{
+    constructRoot(cx);
+    jitContext_.emplace(cx, (js::jit::TempAllocator*)nullptr);
+    alloc_.emplace(cx);
+    moveResolver_.setAllocator(*jitContext_->temp);
+#ifdef JS_CODEGEN_ARM
+    initWithAllocator();
+    m_buffer.id = GetJitContext()->getNextAssemblerId();
+#endif
+    if (ion) {
+        setFramePushed(ion->frameSize());
+        if (pc && cx->runtime()->spsProfiler.enabled())
+            emitProfilingInstrumentation_ = true;
+    }
+}
+
+void
+MacroAssembler::resetForNewCodeGenerator(TempAllocator& alloc)
+{
+    setFramePushed(0);
+    moveResolver_.clearTempObjectPool();
+    moveResolver_.setAllocator(alloc);
+}
+
+MacroAssembler::AfterICSaveLive
+MacroAssembler::icSaveLive(LiveRegisterSet& liveRegs)
+{
+    PushRegsInMask(liveRegs);
+    AfterICSaveLive aic(framePushed());
+    alignFrameForICArguments(aic);
+    return aic;
+}
+
+bool
+MacroAssembler::icBuildOOLFakeExitFrame(void* fakeReturnAddr, AfterICSaveLive& aic)
+{
+    return buildOOLFakeExitFrame(fakeReturnAddr);
+}
+
+void
+MacroAssembler::icRestoreLive(LiveRegisterSet& liveRegs, AfterICSaveLive& aic)
+{
+    restoreFrameAlignmentForICArguments(aic);
+    MOZ_ASSERT(framePushed() == aic.initialStack);
+    PopRegsInMask(liveRegs);
+}
+
+// ===============================================================
 // Stack manipulation functions.
 
 void
 MacroAssembler::PushRegsInMask(LiveGeneralRegisterSet set)
 {
     PushRegsInMask(LiveRegisterSet(set.set(), FloatRegisterSet()));
 }
 
@@ -2621,8 +2674,23 @@ MacroAssembler::popRooted(VMFunction::Ro
 void
 MacroAssembler::adjustStack(int amount)
 {
     if (amount > 0)
         freeStack(amount);
     else if (amount < 0)
         reserveStack(-amount);
 }
+
+void
+MacroAssembler::freeStack(uint32_t amount)
+{
+    MOZ_ASSERT(amount <= framePushed_);
+    if (amount)
+        addPtr(Imm32(amount), StackPointer);
+    framePushed_ -= amount;
+}
+
+void
+MacroAssembler::freeStack(Register amount)
+{
+    addPtr(amount, StackPointer);
+}
--- a/js/src/jit/MacroAssembler.h
+++ b/js/src/jit/MacroAssembler.h
@@ -214,17 +214,18 @@ class MacroAssembler : public MacroAssem
     // sites.
     bool emitProfilingInstrumentation_;
 
     // Labels for handling exceptions and failures.
     NonAssertingLabel failureLabel_;
 
   public:
     MacroAssembler()
-      : emitProfilingInstrumentation_(false)
+      : emitProfilingInstrumentation_(false),
+        framePushed_(0)
     {
         JitContext* jcx = GetJitContext();
         JSContext* cx = jcx->cx;
         if (cx)
             constructRoot(cx);
 
         if (!jcx->temp) {
             MOZ_ASSERT(cx);
@@ -236,69 +237,70 @@ class MacroAssembler : public MacroAssem
         initWithAllocator();
         m_buffer.id = jcx->getNextAssemblerId();
 #endif
     }
 
     // This constructor should only be used when there is no JitContext active
     // (for example, Trampoline-$(ARCH).cpp and IonCaches.cpp).
     explicit MacroAssembler(JSContext* cx, IonScript* ion = nullptr,
-                            JSScript* script = nullptr, jsbytecode* pc = nullptr)
-      : emitProfilingInstrumentation_(false)
-    {
-        constructRoot(cx);
-        jitContext_.emplace(cx, (js::jit::TempAllocator*)nullptr);
-        alloc_.emplace(cx);
-        moveResolver_.setAllocator(*jitContext_->temp);
-#ifdef JS_CODEGEN_ARM
-        initWithAllocator();
-        m_buffer.id = GetJitContext()->getNextAssemblerId();
-#endif
-        if (ion) {
-            setFramePushed(ion->frameSize());
-            if (pc && cx->runtime()->spsProfiler.enabled())
-                emitProfilingInstrumentation_ = true;
-        }
-    }
+                            JSScript* script = nullptr, jsbytecode* pc = nullptr);
 
     // asm.js compilation handles its own JitContext-pushing
     struct AsmJSToken {};
     explicit MacroAssembler(AsmJSToken)
-      : emitProfilingInstrumentation_(false)
+      : emitProfilingInstrumentation_(false),
+        framePushed_(0)
     {
 #ifdef JS_CODEGEN_ARM
         initWithAllocator();
         m_buffer.id = 0;
 #endif
     }
 
     void enableProfilingInstrumentation() {
         emitProfilingInstrumentation_ = true;
     }
 
-    void resetForNewCodeGenerator(TempAllocator& alloc) {
-        setFramePushed(0);
-        moveResolver_.clearTempObjectPool();
-        moveResolver_.setAllocator(alloc);
-    }
+    void resetForNewCodeGenerator(TempAllocator& alloc);
 
     void constructRoot(JSContext* cx) {
         autoRooter_.emplace(cx, this);
     }
 
     MoveResolver& moveResolver() {
         return moveResolver_;
     }
 
     size_t instructionsSize() const {
         return size();
     }
 
   public:
     // ===============================================================
+    // Frame manipulation functions.
+
+    inline uint32_t framePushed() const;
+    inline void setFramePushed(uint32_t framePushed);
+    inline void adjustFrame(int value);
+
+    // Adjust the frame, to account for implicit modification of the stack
+    // pointer, such that callee can remove arguments on the behalf of the
+    // caller.
+    inline void implicitPop(uint32_t bytes);
+
+  private:
+    // This field is used to statically (at compilation time) emulate a frame
+    // pointer by keeping track of stack manipulations.
+    //
+    // It is maintained by all stack manipulation functions below.
+    uint32_t framePushed_;
+
+  public:
+    // ===============================================================
     // Stack manipulation functions.
 
     void PushRegsInMask(LiveRegisterSet set) PER_ARCH;
     void PushRegsInMask(LiveGeneralRegisterSet set);
 
     void PopRegsInMask(LiveRegisterSet set);
     void PopRegsInMask(LiveGeneralRegisterSet set);
     void PopRegsInMaskIgnore(LiveRegisterSet set, LiveRegisterSet ignore) PER_ARCH;
@@ -313,24 +315,41 @@ class MacroAssembler : public MacroAssem
     void Push(jsid id, Register scratchReg);
     void Push(TypedOrValueRegister v);
     void Push(ConstantOrRegister v);
     void Push(const ValueOperand& val);
     void Push(const Value& val);
     void Push(JSValueType type, Register reg);
     void PushValue(const Address& addr);
     void PushEmptyRooted(VMFunction::RootType rootType);
+    inline CodeOffsetLabel PushWithPatch(ImmWord word);
+    inline CodeOffsetLabel PushWithPatch(ImmPtr imm);
 
     void Pop(const Operand op) PER_ARCH ONLY_X86_X64;
     void Pop(Register reg) PER_ARCH;
     void Pop(FloatRegister t) PER_ARCH ONLY_X86_X64;
     void Pop(const ValueOperand& val) PER_ARCH;
     void popRooted(VMFunction::RootType rootType, Register cellReg, const ValueOperand& valueReg);
 
+    // Move the stack pointer based on the requested amount.
     void adjustStack(int amount);
+    void reserveStack(uint32_t amount) PER_ARCH;
+    void freeStack(uint32_t amount);
+
+    // Warning: This method does not update the framePushed() counter.
+    void freeStack(Register amount);
+
+  public:
+    // ===============================================================
+    // Call functions.
+
+    using MacroAssemblerSpecific::call; // legacy
+
+    inline void call(const CallSiteDesc& desc, const Register reg);
+    inline void call(const CallSiteDesc& desc, Label* label);
 
   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);
 
@@ -750,17 +769,17 @@ class MacroAssembler : public MacroAssem
         if (reg.hasValue())
             return extractObject(reg.valueReg(), scratch);
         MOZ_ASSERT(reg.type() == MIRType_Object);
         return reg.typedReg().gpr();
     }
 
     // Inline version of js_TypedArray_uint8_clamp_double.
     // This function clobbers the input register.
-    void clampDoubleToUint8(FloatRegister input, Register output);
+    void clampDoubleToUint8(FloatRegister input, Register output) PER_ARCH;
 
     using MacroAssemblerSpecific::ensureDouble;
 
     template <typename S>
     void ensureDouble(const S& source, FloatRegister dest, Label* failure) {
         Label isDouble, done;
         branchTestDouble(Assembler::Equal, source, &isDouble);
         branchTestInt32(Assembler::NotEqual, source, failure);
@@ -821,43 +840,29 @@ class MacroAssembler : public MacroAssem
     // This is a reference to a patch location where the JitCode* will be written.
   private:
     CodeOffsetLabel exitCodePatch_;
 
   private:
     void linkExitFrame();
 
   public:
-    void PushStubCode() {
-        exitCodePatch_ = PushWithPatch(ImmWord(-1));
-    }
+    inline void PushStubCode();
 
-    void enterExitFrame(const VMFunction* f = nullptr) {
-        linkExitFrame();
-        // Push the ioncode. (Bailout or VM wrapper)
-        PushStubCode();
-        // Push VMFunction pointer, to mark arguments.
-        Push(ImmPtr(f));
-    }
+    // Push stub code, and the VMFunction pointer.
+    inline void enterExitFrame(const VMFunction* f = nullptr);
 
     // The JitCode * argument here is one of the tokens defined in the various
     // exit frame layout classes, e.g. NativeExitFrameLayout::Token().
-    void enterFakeExitFrame(JitCode* codeVal) {
-        linkExitFrame();
-        Push(ImmPtr(codeVal));
-        Push(ImmPtr(nullptr));
-    }
+    inline void enterFakeExitFrame(JitCode* codeVal);
 
-    void leaveExitFrame(size_t extraFrame = 0) {
-        freeStack(ExitFooterFrame::Size() + extraFrame);
-    }
+    // Pop ExitFrame footer in addition to the extra frame.
+    inline void leaveExitFrame(size_t extraFrame = 0);
 
-    bool hasEnteredExitFrame() const {
-        return exitCodePatch_.offset() != 0;
-    }
+    inline bool hasEnteredExitFrame() const;
 
     // Generates code used to complete a bailout.
     void generateBailoutTail(Register scratch, Register bailoutInfo);
 
     // These functions exist as small wrappers around sites where execution can
     // leave the currently running stream of instructions. They exist so that
     // instrumentation may be put in place around them if necessary and the
     // instrumentation is enabled. For the functions that return a uint32_t,
@@ -1265,35 +1270,22 @@ class MacroAssembler : public MacroAssem
 
       public:
 #ifdef JS_DEBUG
         uint32_t initialStack;
 #endif
         uint32_t alignmentPadding;
     };
 
-    void alignFrameForICArguments(AfterICSaveLive& aic);
-    void restoreFrameAlignmentForICArguments(AfterICSaveLive& aic);
-
-    AfterICSaveLive icSaveLive(LiveRegisterSet& liveRegs) {
-        PushRegsInMask(liveRegs);
-        AfterICSaveLive aic(framePushed());
-        alignFrameForICArguments(aic);
-        return aic;
-    }
+    void alignFrameForICArguments(AfterICSaveLive& aic) PER_ARCH;
+    void restoreFrameAlignmentForICArguments(AfterICSaveLive& aic) PER_ARCH;
 
-    bool icBuildOOLFakeExitFrame(void* fakeReturnAddr, AfterICSaveLive& aic) {
-        return buildOOLFakeExitFrame(fakeReturnAddr);
-    }
-
-    void icRestoreLive(LiveRegisterSet& liveRegs, AfterICSaveLive& aic) {
-        restoreFrameAlignmentForICArguments(aic);
-        MOZ_ASSERT(framePushed() == aic.initialStack);
-        PopRegsInMask(liveRegs);
-    }
+    AfterICSaveLive icSaveLive(LiveRegisterSet& liveRegs);
+    bool icBuildOOLFakeExitFrame(void* fakeReturnAddr, AfterICSaveLive& aic);
+    void icRestoreLive(LiveRegisterSet& liveRegs, AfterICSaveLive& aic);
 
     // Align the stack pointer based on the number of arguments which are pushed
     // on the stack, such that the JitFrameLayout would be correctly aligned on
     // the JitStackAlignment.
     void alignJitStackBasedOnNArgs(Register nargs);
     void alignJitStackBasedOnNArgs(uint32_t nargs);
 
     void assertStackAlignment(uint32_t alignment, int32_t offset = 0) {
--- a/js/src/jit/arm/CodeGenerator-arm.cpp
+++ b/js/src/jit/arm/CodeGenerator-arm.cpp
@@ -18,16 +18,17 @@
 #include "jit/MIR.h"
 #include "jit/MIRGraph.h"
 #include "js/Conversions.h"
 #include "vm/Shape.h"
 #include "vm/TraceLogging.h"
 
 #include "jsscriptinlines.h"
 
+#include "jit/MacroAssembler-inl.h"
 #include "jit/shared/CodeGenerator-shared-inl.h"
 
 using namespace js;
 using namespace js::jit;
 
 using mozilla::FloorLog2;
 using mozilla::NegativeInfinity;
 using JS::GenericNaN;
--- a/js/src/jit/arm/CodeGenerator-arm.h
+++ b/js/src/jit/arm/CodeGenerator-arm.h
@@ -21,32 +21,16 @@ class CodeGeneratorARM : public CodeGene
     friend class MoveResolverARM;
 
     CodeGeneratorARM* thisFromCtor() {return this;}
 
   protected:
     // Label for the common return path.
     NonAssertingLabel returnLabel_;
     NonAssertingLabel deoptLabel_;
-    // Ugh. This is not going to be pretty to move over. Stack slotted variables
-    // are not useful on arm. It looks like this will need to return one of two
-    // types.
-    inline Operand ToOperand(const LAllocation& a) {
-        if (a.isGeneralReg())
-            return Operand(a.toGeneralReg()->reg());
-        if (a.isFloatReg())
-            return Operand(a.toFloatReg()->reg());
-        return Operand(StackPointer, ToStackOffset(&a));
-    }
-    inline Operand ToOperand(const LAllocation* a) {
-        return ToOperand(*a);
-    }
-    inline Operand ToOperand(const LDefinition* def) {
-        return ToOperand(def->output());
-    }
 
     MoveOperand toMoveOperand(LAllocation a) const;
 
     void bailoutIf(Assembler::Condition condition, LSnapshot* snapshot);
     void bailoutFrom(Label* label, LSnapshot* snapshot);
     void bailout(LSnapshot* snapshot);
 
     template <typename T1, typename T2>
--- a/js/src/jit/arm/MacroAssembler-arm.cpp
+++ b/js/src/jit/arm/MacroAssembler-arm.cpp
@@ -12,16 +12,18 @@
 
 #include "jit/arm/Simulator-arm.h"
 #include "jit/Bailouts.h"
 #include "jit/BaselineFrame.h"
 #include "jit/JitFrames.h"
 #include "jit/MacroAssembler.h"
 #include "jit/MoveEmitter.h"
 
+#include "jit/MacroAssembler-inl.h"
+
 using namespace js;
 using namespace jit;
 
 using mozilla::Abs;
 using mozilla::BitwiseCast;
 
 bool
 isValueDTRDCandidate(ValueOperand& val)
@@ -1798,80 +1800,80 @@ MacroAssemblerARM::ma_vstr(VFPRegister s
 {
     as_add(ScratchRegister, base, lsl(index, shift), LeaveCC, cc);
     return ma_vstr(src, Address(ScratchRegister, offset), cc);
 }
 
 void
 MacroAssemblerARMCompat::buildFakeExitFrame(Register scratch, uint32_t* offset)
 {
-    DebugOnly<uint32_t> initialDepth = framePushed();
-    uint32_t descriptor = MakeFrameDescriptor(framePushed(), JitFrame_IonJS);
+    DebugOnly<uint32_t> initialDepth = asMasm().framePushed();
+    uint32_t descriptor = MakeFrameDescriptor(asMasm().framePushed(), JitFrame_IonJS);
 
     asMasm().Push(Imm32(descriptor)); // descriptor_
 
     enterNoPool(2);
     DebugOnly<uint32_t> offsetBeforePush = currentOffset();
     asMasm().Push(pc); // actually pushes $pc + 8.
 
     // Consume an additional 4 bytes. The start of the next instruction will
     // then be 8 bytes after the instruction for Push(pc); this offset can
     // therefore be fed to the safepoint.
     ma_nop();
     uint32_t pseudoReturnOffset = currentOffset();
     leaveNoPool();
 
-    MOZ_ASSERT(framePushed() == initialDepth + ExitFrameLayout::Size());
+    MOZ_ASSERT(asMasm().framePushed() == initialDepth + ExitFrameLayout::Size());
     MOZ_ASSERT(pseudoReturnOffset - offsetBeforePush == 8);
 
     *offset = pseudoReturnOffset;
 }
 
 bool
 MacroAssemblerARMCompat::buildOOLFakeExitFrame(void* fakeReturnAddr)
 {
-    DebugOnly<uint32_t> initialDepth = framePushed();
-    uint32_t descriptor = MakeFrameDescriptor(framePushed(), JitFrame_IonJS);
+    DebugOnly<uint32_t> initialDepth = asMasm().framePushed();
+    uint32_t descriptor = MakeFrameDescriptor(asMasm().framePushed(), JitFrame_IonJS);
 
     asMasm().Push(Imm32(descriptor)); // descriptor_
     asMasm().Push(ImmPtr(fakeReturnAddr));
 
     return true;
 }
 
 void
 MacroAssemblerARMCompat::callWithExitFrame(Label* target)
 {
-    uint32_t descriptor = MakeFrameDescriptor(framePushed(), JitFrame_IonJS);
+    uint32_t descriptor = MakeFrameDescriptor(asMasm().framePushed(), JitFrame_IonJS);
     asMasm().Push(Imm32(descriptor)); // descriptor
 
     ma_callJitHalfPush(target);
 }
 
 void
 MacroAssemblerARMCompat::callWithExitFrame(JitCode* target)
 {
-    uint32_t descriptor = MakeFrameDescriptor(framePushed(), JitFrame_IonJS);
+    uint32_t descriptor = MakeFrameDescriptor(asMasm().framePushed(), JitFrame_IonJS);
     asMasm().Push(Imm32(descriptor)); // descriptor
 
     addPendingJump(m_buffer.nextOffset(), ImmPtr(target->raw()), Relocation::JITCODE);
     RelocStyle rs;
     if (HasMOVWT())
         rs = L_MOVWT;
     else
         rs = L_LDR;
 
     ma_movPatchable(ImmPtr(target->raw()), ScratchRegister, Always, rs);
     ma_callJitHalfPush(ScratchRegister);
 }
 
 void
 MacroAssemblerARMCompat::callWithExitFrame(JitCode* target, Register dynStack)
 {
-    ma_add(Imm32(framePushed()), dynStack);
+    ma_add(Imm32(asMasm().framePushed()), dynStack);
     makeFrameDescriptor(dynStack, JitFrame_IonJS);
     asMasm().Push(dynStack); // descriptor
 
     addPendingJump(m_buffer.nextOffset(), ImmPtr(target->raw()), Relocation::JITCODE);
     RelocStyle rs;
     if (HasMOVWT())
         rs = L_MOVWT;
     else
@@ -1879,21 +1881,21 @@ MacroAssemblerARMCompat::callWithExitFra
 
     ma_movPatchable(ImmPtr(target->raw()), ScratchRegister, Always, rs);
     ma_callJitHalfPush(ScratchRegister);
 }
 
 void
 MacroAssemblerARMCompat::callJit(Register callee)
 {
-    MOZ_ASSERT((framePushed() & 3) == 0);
-    if ((framePushed() & 7) == 4) {
+    MOZ_ASSERT((asMasm().framePushed() & 3) == 0);
+    if ((asMasm().framePushed() & 7) == 4) {
         ma_callJitHalfPush(callee);
     } else {
-        adjustFrame(sizeof(void*));
+        asMasm().adjustFrame(sizeof(void*));
         ma_callJit(callee);
     }
 }
 
 void
 MacroAssembler::alignFrameForICArguments(AfterICSaveLive& aic)
 {
     // Exists for MIPS compatibility.
@@ -1901,37 +1903,16 @@ MacroAssembler::alignFrameForICArguments
 
 void
 MacroAssembler::restoreFrameAlignmentForICArguments(AfterICSaveLive& aic)
 {
     // Exists for MIPS compatibility.
 }
 
 void
-MacroAssemblerARMCompat::reserveStack(uint32_t amount)
-{
-    if (amount)
-        ma_sub(Imm32(amount), sp);
-    adjustFrame(amount);
-}
-void
-MacroAssemblerARMCompat::freeStack(uint32_t amount)
-{
-    MOZ_ASSERT(amount <= framePushed_);
-    if (amount)
-        ma_add(Imm32(amount), sp);
-    adjustFrame(-amount);
-}
-void
-MacroAssemblerARMCompat::freeStack(Register amount)
-{
-    ma_add(amount, sp);
-}
-
-void
 MacroAssemblerARMCompat::add32(Register src, Register dest)
 {
     ma_add(src, dest, SetCC);
 }
 
 void
 MacroAssemblerARMCompat::add32(Imm32 imm, Register dest)
 {
@@ -3975,25 +3956,25 @@ MacroAssemblerARMCompat::callWithABIPre(
     *stackAdjust = ((usedIntSlots_ > NumIntArgRegs) ? usedIntSlots_ - NumIntArgRegs : 0) * sizeof(intptr_t);
 #if defined(JS_CODEGEN_ARM_HARDFP) || defined(JS_ARM_SIMULATOR)
     if (UseHardFpABI())
         *stackAdjust += 2*((usedFloatSlots_ > NumFloatArgRegs) ? usedFloatSlots_ - NumFloatArgRegs : 0) * sizeof(intptr_t);
 #endif
     uint32_t alignmentAtPrologue = callFromAsmJS ? sizeof(AsmJSFrame) : 0;
 
     if (!dynamicAlignment_) {
-        *stackAdjust += ComputeByteAlignment(framePushed_ + *stackAdjust + alignmentAtPrologue,
+        *stackAdjust += ComputeByteAlignment(asMasm().framePushed() + *stackAdjust + alignmentAtPrologue,
                                              ABIStackAlignment);
     } else {
         // sizeof(intptr_t) accounts for the saved stack pointer pushed by
         // setupUnalignedABICall.
         *stackAdjust += ComputeByteAlignment(*stackAdjust + sizeof(intptr_t), ABIStackAlignment);
     }
 
-    reserveStack(*stackAdjust);
+    asMasm().reserveStack(*stackAdjust);
 
     // Position all arguments.
     {
         enoughMemory_ = enoughMemory_ && moveResolver_.resolve();
         if (!enoughMemory_)
             return;
 
         MoveEmitter emitter(asMasm());
@@ -4061,17 +4042,17 @@ MacroAssemblerARMCompat::callWithABIPost
         }
       case MoveOp::GENERAL:
         break;
 
       default:
         MOZ_CRASH("unexpected callWithABI result");
     }
 
-    freeStack(stackAdjust);
+    asMasm().freeStack(stackAdjust);
 
     if (dynamicAlignment_) {
         // While the x86 supports pop esp, on ARM that isn't well defined, so
         // just do it manually.
         as_dtr(IsLoad, 32, Offset, sp, DTRAddr(sp, DtrOffImm(0)));
     }
 
     MOZ_ASSERT(inCall_);
@@ -5243,10 +5224,18 @@ MacroAssembler::Pop(Register reg)
     ma_pop(reg);
     adjustFrame(-sizeof(intptr_t));
 }
 
 void
 MacroAssembler::Pop(const ValueOperand& val)
 {
     popValue(val);
-    framePushed_ -= sizeof(Value);
-}
+    adjustFrame(-sizeof(Value));
+}
+
+void
+MacroAssembler::reserveStack(uint32_t amount)
+{
+    if (amount)
+        ma_sub(Imm32(amount), sp);
+    adjustFrame(amount);
+}
--- a/js/src/jit/arm/MacroAssembler-arm.h
+++ b/js/src/jit/arm/MacroAssembler-arm.h
@@ -527,29 +527,19 @@ class MacroAssemblerARMCompat : public M
     // function.
     //
     // arg            Number of arguments of the function.
     void setupABICall(uint32_t arg);
 
   protected:
     MoveResolver moveResolver_;
 
-    // Extra bytes currently pushed onto the frame beyond frameDepth_. This is
-    // needed to compute offsets to stack slots while temporary space has been
-    // reserved for unexpected spills or C++ function calls. It is maintained by
-    // functions which track stack alignment, which for clear distinction use
-    // StudlyCaps (for example, Push, Pop).
-    uint32_t framePushed_;
-    void adjustFrame(int value) {
-        setFramePushed(framePushed_ + value);
-    }
   public:
     MacroAssemblerARMCompat()
-      : inCall_(false),
-        framePushed_(0)
+      : inCall_(false)
     { }
 
   public:
     using MacroAssemblerARM::call;
 
     // Jumps + other functions that should be called from non-arm specific
     // code. Basically, an x86 front end on top of the ARM code.
     void j(Condition code , Label* dest)
@@ -603,24 +593,16 @@ class MacroAssemblerARMCompat : public M
         if (HasMOVWT())
             rs = L_MOVWT;
         else
             rs = L_LDR;
 
         ma_movPatchable(ImmPtr(c->raw()), ScratchRegister, Always, rs);
         ma_callJitHalfPush(ScratchRegister);
     }
-    void call(const CallSiteDesc& desc, const Register reg) {
-        call(reg);
-        append(desc, currentOffset(), framePushed_);
-    }
-    void call(const CallSiteDesc& desc, Label* label) {
-        call(label);
-        append(desc, currentOffset(), framePushed_);
-    }
     void callAndPushReturnAddress(Label* label) {
         AutoForbidPools afp(this, 2);
         ma_push(pc);
         call(label);
     }
 
     void branch(JitCode* c) {
         BufferOffset bo = m_buffer.nextOffset();
@@ -1256,63 +1238,29 @@ class MacroAssemblerARMCompat : public M
     }
 
     void handleFailureWithHandlerTail(void* handler);
 
     /////////////////////////////////////////////////////////////////
     // Common interface.
     /////////////////////////////////////////////////////////////////
   public:
-    // The following functions are exposed for use in platform-shared code.
-
-    CodeOffsetLabel PushWithPatch(ImmWord word) {
-        framePushed_ += sizeof(word.value);
-        return pushWithPatch(word);
-    }
-    CodeOffsetLabel PushWithPatch(ImmPtr imm) {
-        return PushWithPatch(ImmWord(uintptr_t(imm.value)));
-    }
-
-    void PushWithPadding(Register reg, const Imm32 extraSpace) {
-        pushWithPadding(reg, extraSpace);
-        adjustFrame(sizeof(intptr_t) + extraSpace.value);
-    }
-    void PushWithPadding(const Imm32 imm, const Imm32 extraSpace) {
-        pushWithPadding(imm, extraSpace);
-        adjustFrame(sizeof(intptr_t) + extraSpace.value);
-    }
-
-    void implicitPop(uint32_t args) {
-        MOZ_ASSERT(args % sizeof(intptr_t) == 0);
-        adjustFrame(-args);
-    }
-    uint32_t framePushed() const {
-        return framePushed_;
-    }
-    void setFramePushed(uint32_t framePushed) {
-        framePushed_ = framePushed;
-    }
-
     // Builds an exit frame on the stack, with a return address to an internal
     // non-function. Returns offset to be passed to markSafepointAt().
     void buildFakeExitFrame(Register scratch, uint32_t* offset);
 
     void callWithExitFrame(Label* target);
     void callWithExitFrame(JitCode* target);
     void callWithExitFrame(JitCode* target, Register dynStack);
 
     // Makes a call using the only two methods that it is sane for
     // independent code to make a call.
     void callJit(Register callee);
     void callJitFromAsmJS(Register callee) { as_blx(callee); }
 
-    void reserveStack(uint32_t amount);
-    void freeStack(uint32_t amount);
-    void freeStack(Register amount);
-
     void add32(Register src, Register dest);
     void add32(Imm32 imm, Register dest);
     void add32(Imm32 imm, const Address& dest);
     void sub32(Imm32 imm, Register dest);
     void sub32(Register src, Register dest);
     template <typename T>
     void branchAdd32(Condition cond, T src, Register dest, Label* label) {
         add32(src, dest);
--- a/js/src/jit/arm/MoveEmitter-arm.cpp
+++ b/js/src/jit/arm/MoveEmitter-arm.cpp
@@ -1,16 +1,18 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  * vim: set ts=8 sts=4 et sw=4 tw=99:
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "jit/arm/MoveEmitter-arm.h"
 
+#include "jit/MacroAssembler-inl.h"
+
 using namespace js;
 using namespace js::jit;
 
 MoveEmitterARM::MoveEmitterARM(MacroAssembler& masm)
   : inCycle_(0),
     masm(masm),
     pushedAtCycle_(-1),
     pushedAtSpill_(-1),
--- a/js/src/jit/arm/Trampoline-arm.cpp
+++ b/js/src/jit/arm/Trampoline-arm.cpp
@@ -12,16 +12,18 @@
 #include "jit/JitFrames.h"
 #include "jit/JitSpewer.h"
 #include "jit/Linker.h"
 #ifdef JS_ION_PERF
 # include "jit/PerfSpewer.h"
 #endif
 #include "jit/VMFunctions.h"
 
+#include "jit/MacroAssembler-inl.h"
+
 using namespace js;
 using namespace js::jit;
 
 static const FloatRegisterSet NonVolatileFloatRegs =
     FloatRegisterSet((1ULL << FloatRegisters::d8) |
                      (1ULL << FloatRegisters::d9) |
                      (1ULL << FloatRegisters::d10) |
                      (1ULL << FloatRegisters::d11) |
--- a/js/src/jit/mips/CodeGenerator-mips.cpp
+++ b/js/src/jit/mips/CodeGenerator-mips.cpp
@@ -18,26 +18,45 @@
 #include "jit/MIR.h"
 #include "jit/MIRGraph.h"
 #include "js/Conversions.h"
 #include "vm/Shape.h"
 #include "vm/TraceLogging.h"
 
 #include "jsscriptinlines.h"
 
+#include "jit/MacroAssembler-inl.h"
 #include "jit/shared/CodeGenerator-shared-inl.h"
 
 using namespace js;
 using namespace js::jit;
 
 using mozilla::FloorLog2;
 using mozilla::NegativeInfinity;
 using JS::GenericNaN;
 using JS::ToInt32;
 
+// inline
+Address
+CodeGeneratorMIPS::ToAddress(const LAllocation& a)
+{
+    MOZ_ASSERT(a.isMemory());
+    int32_t offset = ToStackOffset(&a);
+
+    return Address(StackPointer, offset);
+}
+
+// inline
+Address
+CodeGeneratorMIPS::ToAddress(const LAllocation* a)
+{
+    return ToAddress(*a);
+}
+
+
 // shared
 CodeGeneratorMIPS::CodeGeneratorMIPS(MIRGenerator* gen, LIRGraph* graph, MacroAssembler* masm)
   : CodeGeneratorShared(gen, graph, masm)
 {
 }
 
 bool
 CodeGeneratorMIPS::generatePrologue()
--- a/js/src/jit/mips/CodeGenerator-mips.h
+++ b/js/src/jit/mips/CodeGenerator-mips.h
@@ -24,44 +24,18 @@ class CodeGeneratorMIPS : public CodeGen
         return this;
     }
 
   protected:
     // Label for the common return path.
     NonAssertingLabel returnLabel_;
     NonAssertingLabel deoptLabel_;
 
-    inline Address ToAddress(const LAllocation& a) {
-        MOZ_ASSERT(a.isMemory());
-        int32_t offset = ToStackOffset(&a);
-
-        return Address(StackPointer, offset);
-    }
-
-    inline Address ToAddress(const LAllocation* a) {
-        return ToAddress(*a);
-    }
-
-    inline Operand ToOperand(const LAllocation& a) {
-        if (a.isGeneralReg())
-            return Operand(a.toGeneralReg()->reg());
-        if (a.isFloatReg())
-            return Operand(a.toFloatReg()->reg());
-
-        MOZ_ASSERT(a.isMemory());
-        int32_t offset = ToStackOffset(&a);
-
-        return Operand(StackPointer, offset);
-    }
-    inline Operand ToOperand(const LAllocation* a) {
-        return ToOperand(*a);
-    }
-    inline Operand ToOperand(const LDefinition* def) {
-        return ToOperand(def->output());
-    }
+    inline Address ToAddress(const LAllocation& a);
+    inline Address ToAddress(const LAllocation* a);
 
     MoveOperand toMoveOperand(LAllocation a) const;
 
     template <typename T1, typename T2>
     void bailoutCmp32(Assembler::Condition c, T1 lhs, T2 rhs, LSnapshot* snapshot) {
         Label skip;
         masm.ma_b(lhs, rhs, &skip, Assembler::InvertCondition(c), ShortJump);
         bailout(snapshot);
--- a/js/src/jit/mips/MacroAssembler-mips.cpp
+++ b/js/src/jit/mips/MacroAssembler-mips.cpp
@@ -12,16 +12,18 @@
 #include "jit/Bailouts.h"
 #include "jit/BaselineFrame.h"
 #include "jit/BaselineRegisters.h"
 #include "jit/JitFrames.h"
 #include "jit/MacroAssembler.h"
 #include "jit/mips/Simulator-mips.h"
 #include "jit/MoveEmitter.h"
 
+#include "jit/MacroAssembler-inl.h"
+
 using namespace js;
 using namespace jit;
 
 using mozilla::Abs;
 
 static const int32_t PAYLOAD_OFFSET = NUNBOX32_PAYLOAD_OFFSET;
 static const int32_t TAG_OFFSET = NUNBOX32_TYPE_OFFSET;
 
@@ -1494,111 +1496,88 @@ MacroAssemblerMIPS::ma_bc1d(FloatRegiste
     FloatTestKind testKind;
     compareFloatingPoint(DoubleFloat, lhs, rhs, c, &testKind, fcc);
     branchWithCode(getBranchCode(testKind, fcc), label, jumpKind);
 }
 
 void
 MacroAssemblerMIPSCompat::buildFakeExitFrame(Register scratch, uint32_t* offset)
 {
-    mozilla::DebugOnly<uint32_t> initialDepth = framePushed();
+    mozilla::DebugOnly<uint32_t> initialDepth = asMasm().framePushed();
 
     CodeLabel cl;
     ma_li(scratch, cl.dest());
 
-    uint32_t descriptor = MakeFrameDescriptor(framePushed(), JitFrame_IonJS);
+    uint32_t descriptor = MakeFrameDescriptor(asMasm().framePushed(), JitFrame_IonJS);
     asMasm().Push(Imm32(descriptor));
     asMasm().Push(scratch);
 
     bind(cl.src());
     *offset = currentOffset();
 
-    MOZ_ASSERT(framePushed() == initialDepth + ExitFrameLayout::Size());
+    MOZ_ASSERT(asMasm().framePushed() == initialDepth + ExitFrameLayout::Size());
     addCodeLabel(cl);
 }
 
 bool
 MacroAssemblerMIPSCompat::buildOOLFakeExitFrame(void* fakeReturnAddr)
 {
-    uint32_t descriptor = MakeFrameDescriptor(framePushed(), JitFrame_IonJS);
+    uint32_t descriptor = MakeFrameDescriptor(asMasm().framePushed(), JitFrame_IonJS);
 
     asMasm().Push(Imm32(descriptor)); // descriptor_
     asMasm().Push(ImmPtr(fakeReturnAddr));
 
     return true;
 }
 
 void
 MacroAssemblerMIPSCompat::callWithExitFrame(Label* target)
 {
-    uint32_t descriptor = MakeFrameDescriptor(framePushed(), JitFrame_IonJS);
+    uint32_t descriptor = MakeFrameDescriptor(asMasm().framePushed(), JitFrame_IonJS);
     asMasm().Push(Imm32(descriptor)); // descriptor
 
     ma_callJitHalfPush(target);
 }
 
 void
 MacroAssemblerMIPSCompat::callWithExitFrame(JitCode* target)
 {
-    uint32_t descriptor = MakeFrameDescriptor(framePushed(), JitFrame_IonJS);
+    uint32_t descriptor = MakeFrameDescriptor(asMasm().framePushed(), JitFrame_IonJS);
     asMasm().Push(Imm32(descriptor)); // descriptor
 
     addPendingJump(m_buffer.nextOffset(), ImmPtr(target->raw()), Relocation::JITCODE);
     ma_liPatchable(ScratchRegister, ImmPtr(target->raw()));
     ma_callJitHalfPush(ScratchRegister);
 }
 
 void
 MacroAssemblerMIPSCompat::callWithExitFrame(JitCode* target, Register dynStack)
 {
-    ma_addu(dynStack, dynStack, Imm32(framePushed()));
+    ma_addu(dynStack, dynStack, Imm32(asMasm().framePushed()));
     makeFrameDescriptor(dynStack, JitFrame_IonJS);
     asMasm().Push(dynStack); // descriptor
 
     addPendingJump(m_buffer.nextOffset(), ImmPtr(target->raw()), Relocation::JITCODE);
     ma_liPatchable(ScratchRegister, ImmPtr(target->raw()));
     ma_callJitHalfPush(ScratchRegister);
 }
 
 void
 MacroAssemblerMIPSCompat::callJit(Register callee)
 {
-    MOZ_ASSERT((framePushed() & 3) == 0);
-    if ((framePushed() & 7) == 4) {
+    MOZ_ASSERT((asMasm().framePushed() & 3) == 0);
+    if ((asMasm().framePushed() & 7) == 4) {
         ma_callJitHalfPush(callee);
     } else {
-        adjustFrame(sizeof(uint32_t));
+        asMasm().adjustFrame(sizeof(uint32_t));
         ma_callJit(callee);
     }
 }
 
 void
-MacroAssemblerMIPSCompat::reserveStack(uint32_t amount)
-{
-    if (amount)
-        ma_subu(StackPointer, StackPointer, Imm32(amount));
-    adjustFrame(amount);
-}
-
-void
-MacroAssemblerMIPSCompat::freeStack(uint32_t amount)
-{
-    MOZ_ASSERT(amount <= framePushed_);
-    if (amount)
-        ma_addu(StackPointer, StackPointer, Imm32(amount));
-    adjustFrame(-amount);
-}
-
-void
-MacroAssemblerMIPSCompat::freeStack(Register amount)
-{
-    as_addu(StackPointer, StackPointer, amount);
-}
-
-void
 MacroAssemblerMIPSCompat::add32(Register src, Register dest)
 {
     as_addu(dest, dest, src);
 }
 
 void
 MacroAssemblerMIPSCompat::add32(Imm32 imm, Register dest)
 {
@@ -3354,21 +3333,21 @@ MacroAssemblerMIPSCompat::callWithABIPre
                     usedArgSlots_ * sizeof(intptr_t) :
                     NumIntArgRegs * sizeof(intptr_t);
 
     uint32_t alignmentAtPrologue = callFromAsmJS ? sizeof(AsmJSFrame) : 0;
 
     if (dynamicAlignment_) {
         *stackAdjust += ComputeByteAlignment(*stackAdjust, ABIStackAlignment);
     } else {
-        *stackAdjust += ComputeByteAlignment(framePushed_ + alignmentAtPrologue + *stackAdjust,
+        *stackAdjust += ComputeByteAlignment(asMasm().framePushed() + alignmentAtPrologue + *stackAdjust,
                                              ABIStackAlignment);
     }
 
-    reserveStack(*stackAdjust);
+    asMasm().reserveStack(*stackAdjust);
 
     // Save $ra because call is going to clobber it. Restore it in
     // callWithABIPost. NOTE: This is needed for calls from BaselineIC.
     // Maybe we can do this differently.
     ma_sw(ra, Address(StackPointer, *stackAdjust - sizeof(intptr_t)));
 
     // Position all arguments.
     {
@@ -3389,19 +3368,19 @@ MacroAssemblerMIPSCompat::callWithABIPos
 {
     // Restore ra value (as stored in callWithABIPre()).
     ma_lw(ra, Address(StackPointer, stackAdjust - sizeof(intptr_t)));
 
     if (dynamicAlignment_) {
         // Restore sp value from stack (as stored in setupUnalignedABICall()).
         ma_lw(StackPointer, Address(StackPointer, stackAdjust));
         // Use adjustFrame instead of freeStack because we already restored sp.
-        adjustFrame(-stackAdjust);
+        asMasm().adjustFrame(-stackAdjust);
     } else {
-        freeStack(stackAdjust);
+        asMasm().freeStack(stackAdjust);
     }
 
     MOZ_ASSERT(inCall_);
     inCall_ = false;
 }
 
 #if defined(DEBUG) && defined(JS_MIPS_SIMULATOR)
 static void
@@ -3783,8 +3762,16 @@ MacroAssembler::Pop(Register reg)
 }
 
 void
 MacroAssembler::Pop(const ValueOperand& val)
 {
     popValue(val);
     framePushed_ -= sizeof(Value);
 }
+
+void
+MacroAssembler::reserveStack(uint32_t amount)
+{
+    if (amount)
+        ma_subu(StackPointer, StackPointer, Imm32(amount));
+    adjustFrame(amount);
+}
--- a/js/src/jit/mips/MacroAssembler-mips.h
+++ b/js/src/jit/mips/MacroAssembler-mips.h
@@ -372,29 +372,19 @@ class MacroAssemblerMIPSCompat : public 
     // function.
     //
     // arg            Number of arguments of the function.
     void setupABICall(uint32_t arg);
 
   protected:
     MoveResolver moveResolver_;
 
-    // Extra bytes currently pushed onto the frame beyond frameDepth_. This is
-    // needed to compute offsets to stack slots while temporary space has been
-    // reserved for unexpected spills or C++ function calls. It is maintained
-    // by functions which track stack alignment, which for clear distinction
-    // use StudlyCaps (for example, Push, Pop).
-    uint32_t framePushed_;
-    void adjustFrame(int value) {
-        setFramePushed(framePushed_ + value);
-    }
   public:
     MacroAssemblerMIPSCompat()
-      : inCall_(false),
-        framePushed_(0)
+      : inCall_(false)
     { }
 
   public:
     using MacroAssemblerMIPS::call;
 
     void j(Label* dest) {
         ma_b(dest);
     }
@@ -437,24 +427,16 @@ class MacroAssemblerMIPSCompat : public 
         call(CallReg);
     }
     void call(JitCode* c) {
         BufferOffset bo = m_buffer.nextOffset();
         addPendingJump(bo, ImmPtr(c->raw()), Relocation::JITCODE);
         ma_liPatchable(ScratchRegister, Imm32((uint32_t)c->raw()));
         ma_callJitHalfPush(ScratchRegister);
     }
-    void call(const CallSiteDesc& desc, const Register reg) {
-        call(reg);
-        append(desc, currentOffset(), framePushed_);
-    }
-    void call(const CallSiteDesc& desc, Label* label) {
-        call(label);
-        append(desc, currentOffset(), framePushed_);
-    }
 
     void callAndPushReturnAddress(Label* label) {
         ma_callJitHalfPush(label);
     }
 
     void branch(JitCode* c) {
         BufferOffset bo = m_buffer.nextOffset();
         addPendingJump(bo, ImmPtr(c->raw()), Relocation::JITCODE);
@@ -1165,52 +1147,29 @@ public:
     void atomicXor16(const T& value, const S& mem) {
         MOZ_CRASH("NYI");
     }
     template <typename T, typename S>
     void atomicXor32(const T& value, const S& mem) {
         MOZ_CRASH("NYI");
     }
 
-    CodeOffsetLabel PushWithPatch(ImmWord word) {
-        framePushed_ += sizeof(word.value);
-        return pushWithPatch(word);
-    }
-    CodeOffsetLabel PushWithPatch(ImmPtr imm) {
-        return PushWithPatch(ImmWord(uintptr_t(imm.value)));
-    }
-
-    void implicitPop(uint32_t args) {
-        MOZ_ASSERT(args % sizeof(intptr_t) == 0);
-        adjustFrame(-args);
-    }
-    uint32_t framePushed() const {
-        return framePushed_;
-    }
-    void setFramePushed(uint32_t framePushed) {
-        framePushed_ = framePushed;
-    }
-
     // Builds an exit frame on the stack, with a return address to an internal
     // non-function. Returns offset to be passed to markSafepointAt().
     void buildFakeExitFrame(Register scratch, uint32_t* offset);
 
     void callWithExitFrame(Label* target);
     void callWithExitFrame(JitCode* target);
     void callWithExitFrame(JitCode* target, Register dynStack);
 
     // Makes a call using the only two methods that it is sane for indep code
     // to make a call.
     void callJit(Register callee);
     void callJitFromAsmJS(Register callee) { callJit(callee); }
 
-    void reserveStack(uint32_t amount);
-    void freeStack(uint32_t amount);
-    void freeStack(Register amount);
-
     void add32(Register src, Register dest);
     void add32(Imm32 imm, Register dest);
     void add32(Imm32 imm, const Address& dest);
     void sub32(Imm32 imm, Register dest);
     void sub32(Register src, Register dest);
 
     void incrementInt32Value(const Address& addr) {
         add32(Imm32(1), ToPayload(addr));
--- a/js/src/jit/mips/MoveEmitter-mips.cpp
+++ b/js/src/jit/mips/MoveEmitter-mips.cpp
@@ -1,16 +1,18 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  * vim: set ts=8 sts=4 et sw=4 tw=99:
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "jit/mips/MoveEmitter-mips.h"
 
+#include "jit/MacroAssembler-inl.h"
+
 using namespace js;
 using namespace js::jit;
 
 MoveEmitterMIPS::MoveEmitterMIPS(MacroAssembler& masm)
   : inCycle_(0),
     masm(masm),
     pushedAtCycle_(-1),
     pushedAtSpill_(-1),
--- a/js/src/jit/mips/Trampoline-mips.cpp
+++ b/js/src/jit/mips/Trampoline-mips.cpp
@@ -15,16 +15,18 @@
 #include "jit/Linker.h"
 #include "jit/mips/Bailouts-mips.h"
 #include "jit/mips/BaselineHelpers-mips.h"
 #ifdef JS_ION_PERF
 # include "jit/PerfSpewer.h"
 #endif
 #include "jit/VMFunctions.h"
 
+#include "jit/MacroAssembler-inl.h"
+
 using namespace js;
 using namespace js::jit;
 
 static_assert(sizeof(uintptr_t) == sizeof(uint32_t), "Not 64-bit clean.");
 
 struct EnterJITRegs
 {
     double f30;
--- a/js/src/jit/none/CodeGenerator-none.h
+++ b/js/src/jit/none/CodeGenerator-none.h
@@ -18,18 +18,17 @@ class CodeGeneratorNone : public CodeGen
     NonAssertingLabel returnLabel_;
 
     CodeGeneratorNone(MIRGenerator* gen, LIRGraph* graph, MacroAssembler* masm)
       : CodeGeneratorShared(gen, graph, masm)
     {
         MOZ_CRASH();
     }
 
-    template <typename T> inline Register ToOperand(T) { MOZ_CRASH(); }
-    MoveOperand toMoveOperand(const LAllocation) const { MOZ_CRASH(); }
+    MoveOperand toMoveOperand(LAllocation) const { MOZ_CRASH(); }
     template <typename T1, typename T2>
     void bailoutCmp32(Assembler::Condition, T1, T2, LSnapshot*) { MOZ_CRASH(); }
     template<typename T>
     void bailoutTest32(Assembler::Condition, Register, T, LSnapshot*) { MOZ_CRASH(); }
     template <typename T1, typename T2>
     void bailoutCmpPtr(Assembler::Condition, T1, T2, LSnapshot*) { MOZ_CRASH(); }
     void bailoutTestPtr(Assembler::Condition, Register, Register, LSnapshot*) { MOZ_CRASH(); }
     void bailoutIfFalseBool(Register, LSnapshot*) { MOZ_CRASH(); }
--- a/js/src/jit/none/MacroAssembler-none.h
+++ b/js/src/jit/none/MacroAssembler-none.h
@@ -147,20 +147,16 @@ class Operand
 };
 
 class MacroAssemblerNone : public Assembler
 {
   public:
     MacroAssemblerNone() { MOZ_CRASH(); }
 
     MoveResolver moveResolver_;
-    size_t framePushed_;
-
-    uint32_t framePushed() const { MOZ_CRASH(); }
-    void setFramePushed(uint32_t) { MOZ_CRASH(); }
 
     size_t size() const { MOZ_CRASH(); }
     size_t bytesNeeded() const { MOZ_CRASH(); }
     size_t jumpRelocationTableBytes() const { MOZ_CRASH(); }
     size_t dataRelocationTableBytes() const { MOZ_CRASH(); }
     size_t preBarrierTableBytes() const { MOZ_CRASH(); }
 
     size_t numCodeLabels() const { MOZ_CRASH(); }
@@ -236,35 +232,32 @@ class MacroAssemblerNone : public Assemb
     template <typename T, typename S> void pushValue(T, S) { MOZ_CRASH(); }
     void popValue(ValueOperand) { MOZ_CRASH(); }
     void tagValue(JSValueType, Register, ValueOperand) { MOZ_CRASH(); }
     void retn(Imm32 n) { MOZ_CRASH(); }
     template <typename T> void push(T) { MOZ_CRASH(); }
     template <typename T> void Push(T) { MOZ_CRASH(); }
     template <typename T> void pop(T) { MOZ_CRASH(); }
     template <typename T> void Pop(T) { MOZ_CRASH(); }
-    template <typename T> CodeOffsetLabel PushWithPatch(T) { MOZ_CRASH(); }
-    void implicitPop(uint32_t) { MOZ_CRASH(); }
+    template <typename T> CodeOffsetLabel pushWithPatch(T) { MOZ_CRASH(); }
 
     CodeOffsetJump jumpWithPatch(RepatchLabel*) { MOZ_CRASH(); }
     CodeOffsetJump jumpWithPatch(RepatchLabel*, Condition) { MOZ_CRASH(); }
     CodeOffsetJump backedgeJump(RepatchLabel* label) { MOZ_CRASH(); }
     template <typename T, typename S>
     CodeOffsetJump branchPtrWithPatch(Condition, T, S, RepatchLabel*) { MOZ_CRASH(); }
 
     template <typename T, typename S> void branchTestValue(Condition, T, S, Label*) { MOZ_CRASH(); }
     void testNullSet(Condition, ValueOperand, Register) { MOZ_CRASH(); }
     void testObjectSet(Condition, ValueOperand, Register) { MOZ_CRASH(); }
     void testUndefinedSet(Condition, ValueOperand, Register) { MOZ_CRASH(); }
 
     template <typename T, typename S> void cmpPtrSet(Condition, T, S, Register) { MOZ_CRASH(); }
     template <typename T, typename S> void cmp32Set(Condition, T, S, Register) { MOZ_CRASH(); }
 
-    void reserveStack(uint32_t) { MOZ_CRASH(); }
-    template <typename T> void freeStack(T) { MOZ_CRASH(); }
     template <typename T, typename S> void add32(T, S) { MOZ_CRASH(); }
     template <typename T, typename S> void addPtr(T, S) { MOZ_CRASH(); }
     template <typename T, typename S> void sub32(T, S) { MOZ_CRASH(); }
     template <typename T, typename S> void subPtr(T, S) { MOZ_CRASH(); }
     void neg32(Register) { MOZ_CRASH(); }
     void mulBy3(Register, Register) { MOZ_CRASH(); }
 
     void negateDouble(FloatRegister) { MOZ_CRASH(); }
--- a/js/src/jit/none/Trampoline-none.cpp
+++ b/js/src/jit/none/Trampoline-none.cpp
@@ -49,23 +49,30 @@ BailoutFrameInfo::BailoutFrameInfo(const
 }
 
 bool ICCompare_Int32::Compiler::generateStubCode(MacroAssembler&) { MOZ_CRASH(); }
 bool ICCompare_Double::Compiler::generateStubCode(MacroAssembler&) { MOZ_CRASH(); }
 bool ICBinaryArith_Int32::Compiler::generateStubCode(MacroAssembler&) { MOZ_CRASH(); }
 bool ICUnaryArith_Int32::Compiler::generateStubCode(MacroAssembler&) { MOZ_CRASH(); }
 JitCode* JitRuntime::generateProfilerExitFrameTailStub(JSContext*) { MOZ_CRASH(); }
 
+void MacroAssembler::alignFrameForICArguments(AfterICSaveLive& aic) { MOZ_CRASH(); }
+void MacroAssembler::restoreFrameAlignmentForICArguments(AfterICSaveLive& aic) { MOZ_CRASH(); }
+
+void MacroAssembler::clampDoubleToUint8(FloatRegister input, Register output) { MOZ_CRASH(); }
+
 // ===============================================================
 // Stack manipulation functions.
 
 void MacroAssembler::PushRegsInMask(LiveRegisterSet) { MOZ_CRASH(); }
 void MacroAssembler::PopRegsInMaskIgnore(LiveRegisterSet, LiveRegisterSet) { MOZ_CRASH(); }
 
 void MacroAssembler::Push(Register reg) { MOZ_CRASH(); }
 void MacroAssembler::Push(const Imm32 imm) { MOZ_CRASH(); }
 void MacroAssembler::Push(const ImmWord imm) { MOZ_CRASH(); }
 void MacroAssembler::Push(const ImmPtr imm) { MOZ_CRASH(); }
 void MacroAssembler::Push(const ImmGCPtr ptr) { MOZ_CRASH(); }
 void MacroAssembler::Push(FloatRegister reg) { MOZ_CRASH(); }
 
 void MacroAssembler::Pop(Register reg) { MOZ_CRASH(); }
 void MacroAssembler::Pop(const ValueOperand& val) { MOZ_CRASH(); }
+
+void MacroAssembler::reserveStack(uint32_t amount) { MOZ_CRASH(); }
--- a/js/src/jit/shared/BaselineCompiler-shared.cpp
+++ b/js/src/jit/shared/BaselineCompiler-shared.cpp
@@ -5,16 +5,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "jit/shared/BaselineCompiler-shared.h"
 
 #include "jit/BaselineIC.h"
 #include "jit/VMFunctions.h"
 
 #include "jsscriptinlines.h"
+#include "jit/MacroAssembler-inl.h"
 
 using namespace js;
 using namespace js::jit;
 
 BaselineCompilerShared::BaselineCompilerShared(JSContext* cx, TempAllocator& alloc, JSScript* script)
   : cx(cx),
     script(script),
     pc(script->code()),
@@ -33,16 +34,29 @@ BaselineCompilerShared::BaselineCompiler
     spsPushToggleOffset_(),
     profilerEnterFrameToggleOffset_(),
     profilerExitFrameToggleOffset_(),
     traceLoggerEnterToggleOffset_(),
     traceLoggerExitToggleOffset_(),
     traceLoggerScriptTextIdOffset_()
 { }
 
+void
+BaselineCompilerShared::prepareVMCall()
+{
+    pushedBeforeCall_ = masm.framePushed();
+    inCall_ = true;
+
+    // Ensure everything is synced.
+    frame.syncStack(0);
+
+    // Save the frame pointer.
+    masm.Push(BaselineFrameReg);
+}
+
 bool
 BaselineCompilerShared::callVM(const VMFunction& fun, CallVMPhase phase)
 {
     JitCode* code = cx->runtime()->jitRuntime()->getVMWrapper(fun);
     if (!code)
         return false;
 
 #ifdef DEBUG
--- a/js/src/jit/shared/BaselineCompiler-shared.h
+++ b/js/src/jit/shared/BaselineCompiler-shared.h
@@ -136,26 +136,17 @@ class BaselineCompilerShared
                                                    PCMappingSlotInfo::ToSlotLocation(frame.peek(-2)));
         }
     }
 
     template <typename T>
     void pushArg(const T& t) {
         masm.Push(t);
     }
-    void prepareVMCall() {
-        pushedBeforeCall_ = masm.framePushed();
-        inCall_ = true;
-
-        // Ensure everything is synced.
-        frame.syncStack(0);
-
-        // Save the frame pointer.
-        masm.Push(BaselineFrameReg);
-    }
+    void prepareVMCall();
 
     enum CallVMPhase {
         POST_INITIALIZE,
         PRE_INITIALIZE,
         CHECK_OVER_RECURSED
     };
     bool callVM(const VMFunction& fun, CallVMPhase phase=POST_INITIALIZE);
 
--- a/js/src/jit/shared/CodeGenerator-shared-inl.h
+++ b/js/src/jit/shared/CodeGenerator-shared-inl.h
@@ -5,16 +5,18 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef jit_shared_CodeGenerator_shared_inl_h
 #define jit_shared_CodeGenerator_shared_inl_h
 
 #include "jit/shared/CodeGenerator-shared.h"
 #include "jit/Disassembler.h"
 
+#include "jit/MacroAssembler-inl.h"
+
 namespace js {
 namespace jit {
 
 static inline int32_t
 ToInt32(const LAllocation* a)
 {
     if (a->isConstantValue())
         return a->toConstant()->toInt32();
@@ -137,16 +139,108 @@ GetTempValue(Register type, Register pay
 #elif defined(JS_PUNBOX64)
     (void)type;
     return ValueOperand(payload);
 #else
 #error "Unknown"
 #endif
 }
 
+int32_t
+CodeGeneratorShared::ArgToStackOffset(int32_t slot) const
+{
+    return masm.framePushed() +
+           (gen->compilingAsmJS() ? sizeof(AsmJSFrame) : sizeof(JitFrameLayout)) +
+           slot;
+}
+
+int32_t
+CodeGeneratorShared::CalleeStackOffset() const
+{
+    return masm.framePushed() + JitFrameLayout::offsetOfCalleeToken();
+}
+
+int32_t
+CodeGeneratorShared::SlotToStackOffset(int32_t slot) const
+{
+    MOZ_ASSERT(slot > 0 && slot <= int32_t(graph.localSlotCount()));
+    int32_t offset = masm.framePushed() - frameInitialAdjustment_ - slot;
+    MOZ_ASSERT(offset >= 0);
+    return offset;
+}
+
+int32_t
+CodeGeneratorShared::StackOffsetToSlot(int32_t offset) const
+{
+    // See: SlotToStackOffset. This is used to convert pushed arguments
+    // to a slot index that safepoints can use.
+    //
+    // offset = framePushed - frameInitialAdjustment - slot
+    // offset + slot = framePushed - frameInitialAdjustment
+    // slot = framePushed - frameInitialAdjustement - offset
+    return masm.framePushed() - frameInitialAdjustment_ - offset;
+}
+
+// For argument construction for calls. Argslots are Value-sized.
+int32_t
+CodeGeneratorShared::StackOffsetOfPassedArg(int32_t slot) const
+{
+    // A slot of 0 is permitted only to calculate %esp offset for calls.
+    MOZ_ASSERT(slot >= 0 && slot <= int32_t(graph.argumentSlotCount()));
+    int32_t offset = masm.framePushed() -
+                     graph.paddedLocalSlotsSize() -
+                     (slot * sizeof(Value));
+
+    // Passed arguments go below A function's local stack storage.
+    // When arguments are being pushed, there is nothing important on the stack.
+    // Therefore, It is safe to push the arguments down arbitrarily.  Pushing
+    // by sizeof(Value) is desirable since everything on the stack is a Value.
+    // Note that paddedLocalSlotCount() aligns to at least a Value boundary
+    // specifically to support this.
+    MOZ_ASSERT(offset >= 0);
+    MOZ_ASSERT(offset % sizeof(Value) == 0);
+    return offset;
+}
+
+int32_t
+CodeGeneratorShared::ToStackOffset(LAllocation a) const
+{
+    if (a.isArgument())
+        return ArgToStackOffset(a.toArgument()->index());
+    return SlotToStackOffset(a.toStackSlot()->slot());
+}
+
+int32_t
+CodeGeneratorShared::ToStackOffset(const LAllocation* a) const
+{
+    return ToStackOffset(*a);
+}
+
+Operand
+CodeGeneratorShared::ToOperand(const LAllocation& a)
+{
+    if (a.isGeneralReg())
+        return Operand(a.toGeneralReg()->reg());
+    if (a.isFloatReg())
+        return Operand(a.toFloatReg()->reg());
+    return Operand(StackPointer, ToStackOffset(&a));
+}
+
+Operand
+CodeGeneratorShared::ToOperand(const LAllocation* a)
+{
+    return ToOperand(*a);
+}
+
+Operand
+CodeGeneratorShared::ToOperand(const LDefinition* def)
+{
+    return ToOperand(def->output());
+}
+
 void
 CodeGeneratorShared::saveLive(LInstruction* ins)
 {
     MOZ_ASSERT(!ins->isCall());
     LSafepoint* safepoint = ins->safepoint();
     masm.PushRegsInMask(safepoint->liveRegs());
 }
 
@@ -234,12 +328,12 @@ CodeGeneratorShared::verifyHeapAccessDis
     size_t size = Scalar::isSimdType(type)
                   ? Scalar::scalarByteSize(type) * numElems
                   : TypedArrayElemSize(type);
     masm.verifyHeapAccessDisassembly(begin, end,
                                      HeapAccess(kind, size, ComplexAddress(mem), op));
 #endif
 }
 
-} // ion
-} // js
+} // namespace jit
+} // namespace js
 
 #endif /* jit_shared_CodeGenerator_shared_inl_h */
--- a/js/src/jit/shared/CodeGenerator-shared.cpp
+++ b/js/src/jit/shared/CodeGenerator-shared.cpp
@@ -15,16 +15,17 @@
 #include "jit/MacroAssembler.h"
 #include "jit/MIR.h"
 #include "jit/MIRGenerator.h"
 #include "jit/OptimizationTracking.h"
 #include "js/Conversions.h"
 #include "vm/TraceLogging.h"
 
 #include "jit/JitFrames-inl.h"
+#include "jit/MacroAssembler-inl.h"
 
 using namespace js;
 using namespace js::jit;
 
 using mozilla::BitwiseCast;
 using mozilla::DebugOnly;
 
 namespace js {
--- a/js/src/jit/shared/CodeGenerator-shared.h
+++ b/js/src/jit/shared/CodeGenerator-shared.h
@@ -184,75 +184,38 @@ class CodeGeneratorShared : public LElem
     // also CodeGeneratorShared constructor. This value records the adjustment
     // we've done.
     int32_t frameInitialAdjustment_;
 
     // Frame class this frame's size falls into (see IonFrame.h).
     FrameSizeClass frameClass_;
 
     // For arguments to the current function.
-    inline int32_t ArgToStackOffset(int32_t slot) const {
-        return masm.framePushed() +
-               (gen->compilingAsmJS() ? sizeof(AsmJSFrame) : sizeof(JitFrameLayout)) +
-               slot;
-    }
+    inline int32_t ArgToStackOffset(int32_t slot) const;
 
     // For the callee of the current function.
-    inline int32_t CalleeStackOffset() const {
-        return masm.framePushed() + JitFrameLayout::offsetOfCalleeToken();
-    }
+    inline int32_t CalleeStackOffset() const;
 
-    inline int32_t SlotToStackOffset(int32_t slot) const {
-        MOZ_ASSERT(slot > 0 && slot <= int32_t(graph.localSlotCount()));
-        int32_t offset = masm.framePushed() - frameInitialAdjustment_ - slot;
-        MOZ_ASSERT(offset >= 0);
-        return offset;
-    }
-    inline int32_t StackOffsetToSlot(int32_t offset) const {
-        // See: SlotToStackOffset. This is used to convert pushed arguments
-        // to a slot index that safepoints can use.
-        //
-        // offset = framePushed - frameInitialAdjustment - slot
-        // offset + slot = framePushed - frameInitialAdjustment
-        // slot = framePushed - frameInitialAdjustement - offset
-        return masm.framePushed() - frameInitialAdjustment_ - offset;
-    }
+    inline int32_t SlotToStackOffset(int32_t slot) const;
+    inline int32_t StackOffsetToSlot(int32_t offset) const;
 
     // For argument construction for calls. Argslots are Value-sized.
-    inline int32_t StackOffsetOfPassedArg(int32_t slot) const {
-        // A slot of 0 is permitted only to calculate %esp offset for calls.
-        MOZ_ASSERT(slot >= 0 && slot <= int32_t(graph.argumentSlotCount()));
-        int32_t offset = masm.framePushed() -
-                       graph.paddedLocalSlotsSize() -
-                       (slot * sizeof(Value));
+    inline int32_t StackOffsetOfPassedArg(int32_t slot) const;
 
-        // Passed arguments go below A function's local stack storage.
-        // When arguments are being pushed, there is nothing important on the stack.
-        // Therefore, It is safe to push the arguments down arbitrarily.  Pushing
-        // by sizeof(Value) is desirable since everything on the stack is a Value.
-        // Note that paddedLocalSlotCount() aligns to at least a Value boundary
-        // specifically to support this.
-        MOZ_ASSERT(offset >= 0);
-        MOZ_ASSERT(offset % sizeof(Value) == 0);
-        return offset;
-    }
-
-    inline int32_t ToStackOffset(LAllocation a) const {
-        if (a.isArgument())
-            return ArgToStackOffset(a.toArgument()->index());
-        return SlotToStackOffset(a.toStackSlot()->slot());
-    }
-    inline int32_t ToStackOffset(const LAllocation* a) const {
-        return ToStackOffset(*a);
-    }
+    inline int32_t ToStackOffset(LAllocation a) const;
+    inline int32_t ToStackOffset(const LAllocation* a) const;
 
     uint32_t frameSize() const {
         return frameClass_ == FrameSizeClass::None() ? frameDepth_ : frameClass_.frameSize();
     }
 
+    inline Operand ToOperand(const LAllocation& a);
+    inline Operand ToOperand(const LAllocation* a);
+    inline Operand ToOperand(const LDefinition* def);
+
   protected:
     // Ensure the cache is an IonCache while expecting the size of the derived
     // class. We only need the cache list at GC time. Everyone else can just take
     // runtimeData offsets.
     size_t allocateCache(const IonCache&, size_t size) {
         size_t dataOffset = allocateData(size);
         masm.propagateOOM(cacheList_.append(dataOffset));
         return dataOffset;
--- a/js/src/jit/x64/MacroAssembler-x64.cpp
+++ b/js/src/jit/x64/MacroAssembler-x64.cpp
@@ -8,16 +8,18 @@
 
 #include "jit/Bailouts.h"
 #include "jit/BaselineFrame.h"
 #include "jit/JitCompartment.h"
 #include "jit/JitFrames.h"
 #include "jit/MacroAssembler.h"
 #include "jit/MoveEmitter.h"
 
+#include "jit/MacroAssembler-inl.h"
+
 using namespace js;
 using namespace js::jit;
 
 void
 MacroAssemblerX64::loadConstantDouble(double d, FloatRegister dest)
 {
     if (maybeInlineDouble(d, dest))
         return;
@@ -272,21 +274,21 @@ MacroAssemblerX64::callWithABIPre(uint32
     MOZ_ASSERT(args_ == passedIntArgs_ + passedFloatArgs_);
 
     if (dynamicAlignment_) {
         *stackAdjust = stackForCall_
                      + ComputeByteAlignment(stackForCall_ + sizeof(intptr_t),
                                             ABIStackAlignment);
     } else {
         *stackAdjust = stackForCall_
-                     + ComputeByteAlignment(stackForCall_ + framePushed_,
+                     + ComputeByteAlignment(stackForCall_ + asMasm().framePushed(),
                                             ABIStackAlignment);
     }
 
-    reserveStack(*stackAdjust);
+    asMasm().reserveStack(*stackAdjust);
 
     // Position all arguments.
     {
         enoughMemory_ &= moveResolver_.resolve();
         if (!enoughMemory_)
             return;
 
         MoveEmitter emitter(asMasm());
@@ -303,17 +305,17 @@ MacroAssemblerX64::callWithABIPre(uint32
         bind(&good);
     }
 #endif
 }
 
 void
 MacroAssemblerX64::callWithABIPost(uint32_t stackAdjust, MoveOp::Type result)
 {
-    freeStack(stackAdjust);
+    asMasm().freeStack(stackAdjust);
     if (dynamicAlignment_)
         pop(rsp);
 
     MOZ_ASSERT(inCall_);
     inCall_ = false;
 }
 
 void
@@ -503,17 +505,17 @@ MacroAssemblerX64::storeUnboxedValue(Con
 
 template void
 MacroAssemblerX64::storeUnboxedValue(ConstantOrRegister value, MIRType valueType, const BaseIndex& dest,
                                      MIRType slotType);
 
 void
 MacroAssemblerX64::callWithExitFrame(JitCode* target, Register dynStack)
 {
-    addPtr(Imm32(framePushed()), dynStack);
+    addPtr(Imm32(asMasm().framePushed()), dynStack);
     makeFrameDescriptor(dynStack, JitFrame_IonJS);
     asMasm().Push(dynStack);
     call(target);
 }
 
 void
 MacroAssemblerX64::branchPtrInNurseryRange(Condition cond, Register ptr, Register temp, Label* label)
 {
@@ -570,8 +572,31 @@ MacroAssemblerX64::asMasm()
     return *static_cast<MacroAssembler*>(this);
 }
 
 const MacroAssembler&
 MacroAssemblerX64::asMasm() const
 {
     return *static_cast<const MacroAssembler*>(this);
 }
+
+// ===============================================================
+// Stack manipulation functions.
+
+void
+MacroAssembler::reserveStack(uint32_t amount)
+{
+    if (amount) {
+        // On windows, we cannot skip very far down the stack without touching the
+        // memory pages in-between.  This is a corner-case code for situations where the
+        // Ion frame data for a piece of code is very large.  To handle this special case,
+        // for frames over 1k in size we allocate memory on the stack incrementally, touching
+        // it as we go.
+        uint32_t amountLeft = amount;
+        while (amountLeft > 4096) {
+            subq(Imm32(4096), StackPointer);
+            store32(Imm32(0), Address(StackPointer, 0));
+            amountLeft -= 4096;
+        }
+        subq(Imm32(amountLeft), StackPointer);
+    }
+    framePushed_ += amount;
+}
--- a/js/src/jit/x64/MacroAssembler-x64.h
+++ b/js/src/jit/x64/MacroAssembler-x64.h
@@ -555,42 +555,16 @@ class MacroAssemblerX64 : public MacroAs
     {
         cmpPtr(lhs, rhs);
         emitSet(cond, dest);
     }
 
     /////////////////////////////////////////////////////////////////
     // Common interface.
     /////////////////////////////////////////////////////////////////
-    void reserveStack(uint32_t amount) {
-        if (amount) {
-            // On windows, we cannot skip very far down the stack without touching the
-            // memory pages in-between.  This is a corner-case code for situations where the
-            // Ion frame data for a piece of code is very large.  To handle this special case,
-            // for frames over 1k in size we allocate memory on the stack incrementally, touching
-            // it as we go.
-            uint32_t amountLeft = amount;
-            while (amountLeft > 4096) {
-                subq(Imm32(4096), StackPointer);
-                store32(Imm32(0), Address(StackPointer, 0));
-                amountLeft -= 4096;
-            }
-            subq(Imm32(amountLeft), StackPointer);
-        }
-        framePushed_ += amount;
-    }
-    void freeStack(uint32_t amount) {
-        MOZ_ASSERT(amount <= framePushed_);
-        if (amount)
-            addq(Imm32(amount), StackPointer);
-        framePushed_ -= amount;
-    }
-    void freeStack(Register amount) {
-        addq(amount, StackPointer);
-    }
 
     void addPtr(Register src, Register dest) {
         addq(src, dest);
     }
     void addPtr(Imm32 imm, Register dest) {
         addq(imm, dest);
     }
     void addPtr(Imm32 imm, const Address& dest) {
--- a/js/src/jit/x86-shared/CodeGenerator-x86-shared.cpp
+++ b/js/src/jit/x86-shared/CodeGenerator-x86-shared.cpp
@@ -12,16 +12,17 @@
 #include "jsmath.h"
 
 #include "jit/JitCompartment.h"
 #include "jit/JitFrames.h"
 #include "jit/Linker.h"
 #include "jit/RangeAnalysis.h"
 #include "vm/TraceLogging.h"
 
+#include "jit/MacroAssembler-inl.h"
 #include "jit/shared/CodeGenerator-shared-inl.h"
 
 using namespace js;
 using namespace js::jit;
 
 using mozilla::Abs;
 using mozilla::FloatingPoint;
 using mozilla::FloorLog2;
--- a/js/src/jit/x86-shared/CodeGenerator-x86-shared.h
+++ b/js/src/jit/x86-shared/CodeGenerator-x86-shared.h
@@ -96,30 +96,16 @@ class CodeGeneratorX86Shared : public Co
     uint32_t emitAsmJSBoundsCheckBranch(const MAsmJSHeapAccess* mir, const MInstruction* ins,
                                         Register ptr, Label* fail);
     void cleanupAfterAsmJSBoundsCheckBranch(const MAsmJSHeapAccess* mir, Register ptr);
 
     // Label for the common return path.
     NonAssertingLabel returnLabel_;
     NonAssertingLabel deoptLabel_;
 
-    inline Operand ToOperand(const LAllocation& a) {
-        if (a.isGeneralReg())
-            return Operand(a.toGeneralReg()->reg());
-        if (a.isFloatReg())
-            return Operand(a.toFloatReg()->reg());
-        return Operand(StackPointer, ToStackOffset(&a));
-    }
-    inline Operand ToOperand(const LAllocation* a) {
-        return ToOperand(*a);
-    }
-    inline Operand ToOperand(const LDefinition* def) {
-        return ToOperand(def->output());
-    }
-
     MoveOperand toMoveOperand(LAllocation a) const;
 
     void bailoutIf(Assembler::Condition condition, LSnapshot* snapshot);
     void bailoutIf(Assembler::DoubleCondition condition, LSnapshot* snapshot);
     void bailoutFrom(Label* label, LSnapshot* snapshot);
     void bailout(LSnapshot* snapshot);
 
     template <typename T1, typename T2>
--- a/js/src/jit/x86-shared/MacroAssembler-x86-shared.cpp
+++ b/js/src/jit/x86-shared/MacroAssembler-x86-shared.cpp
@@ -4,16 +4,18 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "jit/x86-shared/MacroAssembler-x86-shared.h"
 
 #include "jit/JitFrames.h"
 #include "jit/MacroAssembler.h"
 
+#include "jit/MacroAssembler-inl.h"
+
 using namespace js;
 using namespace js::jit;
 
 // Note: this function clobbers the input register.
 void
 MacroAssembler::clampDoubleToUint8(FloatRegister input, Register output)
 {
     MOZ_ASSERT(input != ScratchDoubleReg);
@@ -60,44 +62,44 @@ MacroAssembler::clampDoubleToUint8(Float
     bind(&done);
 }
 
 // Builds an exit frame on the stack, with a return address to an internal
 // non-function. Returns offset to be passed to markSafepointAt().
 void
 MacroAssemblerX86Shared::buildFakeExitFrame(Register scratch, uint32_t* offset)
 {
-    mozilla::DebugOnly<uint32_t> initialDepth = framePushed();
+    mozilla::DebugOnly<uint32_t> initialDepth = asMasm().framePushed();
 
     CodeLabel cl;
     mov(cl.dest(), scratch);
 
-    uint32_t descriptor = MakeFrameDescriptor(framePushed(), JitFrame_IonJS);
+    uint32_t descriptor = MakeFrameDescriptor(asMasm().framePushed(), JitFrame_IonJS);
     asMasm().Push(Imm32(descriptor));
     asMasm().Push(scratch);
 
     bind(cl.src());
     *offset = currentOffset();
 
-    MOZ_ASSERT(framePushed() == initialDepth + ExitFrameLayout::Size());
+    MOZ_ASSERT(asMasm().framePushed() == initialDepth + ExitFrameLayout::Size());
     addCodeLabel(cl);
 }
 
 void
 MacroAssemblerX86Shared::callWithExitFrame(Label* target)
 {
-    uint32_t descriptor = MakeFrameDescriptor(framePushed(), JitFrame_IonJS);
+    uint32_t descriptor = MakeFrameDescriptor(asMasm().framePushed(), JitFrame_IonJS);
     asMasm().Push(Imm32(descriptor));
     call(target);
 }
 
 void
 MacroAssemblerX86Shared::callWithExitFrame(JitCode* target)
 {
-    uint32_t descriptor = MakeFrameDescriptor(framePushed(), JitFrame_IonJS);
+    uint32_t descriptor = MakeFrameDescriptor(asMasm().framePushed(), JitFrame_IonJS);
     asMasm().Push(Imm32(descriptor));
     call(target);
 }
 
 void
 MacroAssembler::alignFrameForICArguments(AfterICSaveLive& aic)
 {
     // Exists for MIPS compatibility.
@@ -107,17 +109,17 @@ void
 MacroAssembler::restoreFrameAlignmentForICArguments(AfterICSaveLive& aic)
 {
     // Exists for MIPS compatibility.
 }
 
 bool
 MacroAssemblerX86Shared::buildOOLFakeExitFrame(void* fakeReturnAddr)
 {
-    uint32_t descriptor = MakeFrameDescriptor(framePushed(), JitFrame_IonJS);
+    uint32_t descriptor = MakeFrameDescriptor(asMasm().framePushed(), JitFrame_IonJS);
     asMasm().Push(Imm32(descriptor));
     asMasm().Push(ImmPtr(fakeReturnAddr));
     return true;
 }
 
 void
 MacroAssemblerX86Shared::branchNegativeZero(FloatRegister reg,
                                             Register scratch,
--- a/js/src/jit/x86-shared/MacroAssembler-x86-shared.h
+++ b/js/src/jit/x86-shared/MacroAssembler-x86-shared.h
@@ -40,29 +40,20 @@ class MacroAssembler;
 
 class MacroAssemblerX86Shared : public Assembler
 {
   private:
     // Perform a downcast. Should be removed by Bug 996602.
     MacroAssembler& asMasm();
     const MacroAssembler& asMasm() const;
 
-  protected:
-    // Bytes pushed onto the frame by the callee; includes frameDepth_. This is
-    // needed to compute offsets to stack slots while temporary space has been
-    // reserved for unexpected spills or C++ function calls. It is maintained
-    // by functions which track stack alignment, which for clear distinction
-    // use StudlyCaps (for example, Push, Pop).
-    uint32_t framePushed_;
-
   public:
     using Assembler::call;
 
     MacroAssemblerX86Shared()
-      : framePushed_(0)
     { }
 
     void compareDouble(DoubleCondition cond, FloatRegister lhs, FloatRegister rhs) {
         if (cond & DoubleConditionBitInvert)
             vucomisd(lhs, rhs);
         else
             vucomisd(rhs, lhs);
     }
@@ -629,36 +620,16 @@ class MacroAssemblerX86Shared : public A
         j(cond, label);
     }
     void branchTest32(Condition cond, const Address& address, Imm32 imm, Label* label) {
         MOZ_ASSERT(cond == Zero || cond == NonZero || cond == Signed || cond == NotSigned);
         test32(Operand(address), imm);
         j(cond, label);
     }
 
-    // The following functions are exposed for use in platform-shared code.
-    CodeOffsetLabel PushWithPatch(ImmWord word) {
-        framePushed_ += sizeof(word.value);
-        return pushWithPatch(word);
-    }
-    CodeOffsetLabel PushWithPatch(ImmPtr imm) {
-        return PushWithPatch(ImmWord(uintptr_t(imm.value)));
-    }
-
-    void implicitPop(uint32_t args) {
-        MOZ_ASSERT(args % sizeof(intptr_t) == 0);
-        framePushed_ -= args;
-    }
-    uint32_t framePushed() const {
-        return framePushed_;
-    }
-    void setFramePushed(uint32_t framePushed) {
-        framePushed_ = framePushed;
-    }
-
     void jump(Label* label) {
         jmp(label);
     }
     void jump(JitCode* code) {
         jmp(code);
     }
     void jump(RepatchLabel* label) {
         jmp(label);
@@ -1452,24 +1423,16 @@ class MacroAssemblerX86Shared : public A
     }
 
     // Builds an exit frame on the stack, with a return address to an internal
     // non-function. Returns offset to be passed to markSafepointAt().
     void buildFakeExitFrame(Register scratch, uint32_t* offset);
     void callWithExitFrame(Label* target);
     void callWithExitFrame(JitCode* target);
 
-    void call(const CallSiteDesc& desc, Label* label) {
-        call(label);
-        append(desc, currentOffset(), framePushed_);
-    }
-    void call(const CallSiteDesc& desc, Register reg) {
-        call(reg);
-        append(desc, currentOffset(), framePushed_);
-    }
     void callJit(Register callee) {
         call(callee);
     }
     void callJitFromAsmJS(Register callee) {
         call(callee);
     }
     void call(AsmJSImmPtr target) {
         mov(target, eax);
--- a/js/src/jit/x86-shared/MoveEmitter-x86-shared.cpp
+++ b/js/src/jit/x86-shared/MoveEmitter-x86-shared.cpp
@@ -1,16 +1,18 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  * vim: set ts=8 sts=4 et sw=4 tw=99:
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "jit/x86-shared/MoveEmitter-x86-shared.h"
 
+#include "jit/MacroAssembler-inl.h"
+
 using namespace js;
 using namespace js::jit;
 
 MoveEmitterX86::MoveEmitterX86(MacroAssembler& masm)
   : inCycle_(false),
     masm(masm),
     pushedAtCycle_(-1)
 {
--- a/js/src/jit/x86/MacroAssembler-x86.cpp
+++ b/js/src/jit/x86/MacroAssembler-x86.cpp
@@ -10,16 +10,17 @@
 
 #include "jit/Bailouts.h"
 #include "jit/BaselineFrame.h"
 #include "jit/JitFrames.h"
 #include "jit/MacroAssembler.h"
 #include "jit/MoveEmitter.h"
 
 #include "jsscriptinlines.h"
+#include "jit/MacroAssembler-inl.h"
 
 using namespace js;
 using namespace js::jit;
 
 MacroAssemblerX86::Double*
 MacroAssemblerX86::getDouble(double d)
 {
     if (!doubleMap_.initialized()) {
@@ -266,21 +267,21 @@ MacroAssemblerX86::callWithABIPre(uint32
     MOZ_ASSERT(args_ == passedArgs_);
 
     if (dynamicAlignment_) {
         *stackAdjust = stackForCall_
                      + ComputeByteAlignment(stackForCall_ + sizeof(intptr_t),
                                             ABIStackAlignment);
     } else {
         *stackAdjust = stackForCall_
-                     + ComputeByteAlignment(stackForCall_ + framePushed_,
+                     + ComputeByteAlignment(stackForCall_ + asMasm().framePushed(),
                                             ABIStackAlignment);
     }
 
-    reserveStack(*stackAdjust);
+    asMasm().reserveStack(*stackAdjust);
 
     // Position all arguments.
     {
         enoughMemory_ &= moveResolver_.resolve();
         if (!enoughMemory_)
             return;
 
         MoveEmitter emitter(asMasm());
@@ -298,27 +299,27 @@ MacroAssemblerX86::callWithABIPre(uint32
         bind(&good);
     }
 #endif
 }
 
 void
 MacroAssemblerX86::callWithABIPost(uint32_t stackAdjust, MoveOp::Type result)
 {
-    freeStack(stackAdjust);
+    asMasm().freeStack(stackAdjust);
     if (result == MoveOp::DOUBLE) {
-        reserveStack(sizeof(double));
+        asMasm().reserveStack(sizeof(double));
         fstp(Operand(esp, 0));
         loadDouble(Operand(esp, 0), ReturnDoubleReg);
-        freeStack(sizeof(double));
+        asMasm().freeStack(sizeof(double));
     } else if (result == MoveOp::FLOAT32) {
-        reserveStack(sizeof(float));
+        asMasm().reserveStack(sizeof(float));
         fstp32(Operand(esp, 0));
         loadFloat32(Operand(esp, 0), ReturnFloat32Reg);
-        freeStack(sizeof(float));
+        asMasm().freeStack(sizeof(float));
     }
     if (dynamicAlignment_)
         pop(esp);
 
     MOZ_ASSERT(inCall_);
     inCall_ = false;
 }
 
@@ -497,17 +498,17 @@ MacroAssemblerX86::storeUnboxedValue(Con
 
 template void
 MacroAssemblerX86::storeUnboxedValue(ConstantOrRegister value, MIRType valueType, const BaseIndex& dest,
                                      MIRType slotType);
 
 void
 MacroAssemblerX86::callWithExitFrame(JitCode* target, Register dynStack)
 {
-    addPtr(ImmWord(framePushed()), dynStack);
+    addPtr(ImmWord(asMasm().framePushed()), dynStack);
     makeFrameDescriptor(dynStack, JitFrame_IonJS);
     asMasm().Push(dynStack);
     call(target);
 }
 
 void
 MacroAssemblerX86::branchPtrInNurseryRange(Condition cond, Register ptr, Register temp,
                                            Label* label)
@@ -558,8 +559,31 @@ MacroAssemblerX86::asMasm()
     return *static_cast<MacroAssembler*>(this);
 }
 
 const MacroAssembler&
 MacroAssemblerX86::asMasm() const
 {
     return *static_cast<const MacroAssembler*>(this);
 }
+
+// ===============================================================
+// Stack manipulation functions.
+
+void
+MacroAssembler::reserveStack(uint32_t amount)
+{
+    if (amount) {
+        // On windows, we cannot skip very far down the stack without touching the
+        // memory pages in-between.  This is a corner-case code for situations where the
+        // Ion frame data for a piece of code is very large.  To handle this special case,
+        // for frames over 1k in size we allocate memory on the stack incrementally, touching
+        // it as we go.
+        uint32_t amountLeft = amount;
+        while (amountLeft > 4096) {
+            subl(Imm32(4096), StackPointer);
+            store32(Imm32(0), Address(StackPointer, 0));
+            amountLeft -= 4096;
+        }
+        subl(Imm32(amountLeft), StackPointer);
+    }
+    framePushed_ += amount;
+}
--- a/js/src/jit/x86/MacroAssembler-x86.h
+++ b/js/src/jit/x86/MacroAssembler-x86.h
@@ -593,42 +593,16 @@ class MacroAssemblerX86 : public MacroAs
     {
         cmpPtr(lhs, rhs);
         emitSet(cond, dest);
     }
 
     /////////////////////////////////////////////////////////////////
     // Common interface.
     /////////////////////////////////////////////////////////////////
-    void reserveStack(uint32_t amount) {
-        if (amount) {
-            // On windows, we cannot skip very far down the stack without touching the
-            // memory pages in-between.  This is a corner-case code for situations where the
-            // Ion frame data for a piece of code is very large.  To handle this special case,
-            // for frames over 1k in size we allocate memory on the stack incrementally, touching
-            // it as we go.
-            uint32_t amountLeft = amount;
-            while (amountLeft > 4096) {
-                subl(Imm32(4096), StackPointer);
-                store32(Imm32(0), Address(StackPointer, 0));
-                amountLeft -= 4096;
-            }
-            subl(Imm32(amountLeft), StackPointer);
-        }
-        framePushed_ += amount;
-    }
-    void freeStack(uint32_t amount) {
-        MOZ_ASSERT(amount <= framePushed_);
-        if (amount)
-            addl(Imm32(amount), StackPointer);
-        framePushed_ -= amount;
-    }
-    void freeStack(Register amount) {
-        addl(amount, StackPointer);
-    }
 
     void addPtr(Register src, Register dest) {
         add32(src, dest);
     }
     void addPtr(Imm32 imm, Register dest) {
         add32(imm, dest);
     }
     void addPtr(ImmWord imm, Register dest) {