Bug 1313024: Generalize stack guard page touching in subFromStackPtr; r=jandem
authorBenjamin Bouvier <benj@benj.me>
Thu, 27 Oct 2016 18:45:48 +0200
changeset 320011 9a5184bfa3877779da110696be3e68ce43b05227
parent 320010 fb3cd4dc8aef5f2e33a274c21e5e0acc7cce230a
child 320012 94efce672651a0dadb9fff2325103f4e22d89362
push id20749
push userryanvm@gmail.com
push dateSat, 29 Oct 2016 13:21:21 +0000
treeherderfx-team@1b170b39ed6b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjandem
bugs1313024
milestone52.0a1
Bug 1313024: Generalize stack guard page touching in subFromStackPtr; r=jandem MozReview-Commit-ID: 4MZ5xyPimIv
js/src/jit/MacroAssembler-inl.h
js/src/jit/MacroAssembler.cpp
js/src/jit/MacroAssembler.h
js/src/jit/arm/MacroAssembler-arm.cpp
js/src/jit/arm64/MacroAssembler-arm64.cpp
js/src/jit/mips32/MacroAssembler-mips32.cpp
js/src/jit/mips64/MacroAssembler-mips64.cpp
js/src/jit/x64/MacroAssembler-x64.cpp
js/src/jit/x86/MacroAssembler-x86.cpp
--- a/js/src/jit/MacroAssembler-inl.h
+++ b/js/src/jit/MacroAssembler-inl.h
@@ -709,16 +709,22 @@ MacroAssembler::addToStackPtr(T t)
 }
 
 template <typename T> void
 MacroAssembler::addStackPtrTo(T t)
 {
     addPtr(getStackPointer(), t);
 }
 
+void
+MacroAssembler::reserveStack(uint32_t amount)
+{
+    subFromStackPtr(Imm32(amount));
+    adjustFrame(amount);
+}
 #endif // !JS_CODEGEN_ARM64
 
 template <typename T>
 void
 MacroAssembler::storeObjectOrNull(Register src, const T& dest)
 {
     Label notNull, done;
     branchTestPtr(Assembler::NonZero, src, src, &notNull);
--- a/js/src/jit/MacroAssembler.cpp
+++ b/js/src/jit/MacroAssembler.cpp
@@ -2382,16 +2382,24 @@ MacroAssembler::icBuildOOLFakeExitFrame(
 void
 MacroAssembler::icRestoreLive(LiveRegisterSet& liveRegs, AfterICSaveLive& aic)
 {
     restoreFrameAlignmentForICArguments(aic);
     MOZ_ASSERT(framePushed() == aic.initialStack);
     PopRegsInMask(liveRegs);
 }
 
+#ifndef JS_CODEGEN_ARM64
+void
+MacroAssembler::subFromStackPtr(Register reg)
+{
+    subPtr(reg, getStackPointer());
+}
+#endif // JS_CODEGEN_ARM64
+
 //{{{ check_macroassembler_style
 // ===============================================================
 // Stack manipulation functions.
 
 void
 MacroAssembler::PushRegsInMask(LiveGeneralRegisterSet set)
 {
     PushRegsInMask(LiveRegisterSet(set.set(), FloatRegisterSet()));
--- a/js/src/jit/MacroAssembler.h
+++ b/js/src/jit/MacroAssembler.h
@@ -450,17 +450,16 @@ class MacroAssembler : public MacroAssem
     void Pop(const Operand op) DEFINED_ON(x86_shared);
     void Pop(Register reg) PER_SHARED_ARCH;
     void Pop(FloatRegister t) PER_SHARED_ARCH;
     void Pop(const ValueOperand& val) PER_SHARED_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);
 
   private:
     // ===============================================================
     // Register allocation fields.
@@ -1718,18 +1717,19 @@ class MacroAssembler : public MacroAssem
   public:
 #ifndef JS_CODEGEN_ARM64
     // StackPointer manipulation functions.
     // On ARM64, the StackPointer is implemented as two synchronized registers.
     // Code shared across platforms must use these functions to be valid.
     template <typename T> inline void addToStackPtr(T t);
     template <typename T> inline void addStackPtrTo(T t);
 
-    template <typename T>
-    void subFromStackPtr(T t) { subPtr(t, getStackPointer()); }
+    void subFromStackPtr(Imm32 imm32) DEFINED_ON(mips32, mips64, arm, x86, x64);
+    void subFromStackPtr(Register reg);
+
     template <typename T>
     void subStackPtrFrom(T t) { subPtr(getStackPointer(), t); }
 
     template <typename T>
     void andToStackPtr(T t) { andPtr(t, getStackPointer()); }
     template <typename T>
     void andStackPtrTo(T t) { andPtr(getStackPointer(), t); }
 
@@ -1747,17 +1747,22 @@ class MacroAssembler : public MacroAssem
     // On ARM64, sp can function as the zero register depending on context.
     // Code shared across platforms must use these functions to be valid.
     template <typename T>
     inline void branchTestStackPtr(Condition cond, T t, Label* label);
     template <typename T>
     inline void branchStackPtr(Condition cond, T rhs, Label* label);
     template <typename T>
     inline void branchStackPtrRhs(Condition cond, T lhs, Label* label);
-#endif // !JS_CODEGEN_ARM64
+
+    // Move the stack pointer based on the requested amount.
+    inline void reserveStack(uint32_t amount);
+#else // !JS_CODEGEN_ARM64
+    void reserveStack(uint32_t amount);
+#endif
 
   public:
     void enableProfilingInstrumentation() {
         emitProfilingInstrumentation_ = true;
     }
 
   private:
     // This class is used to surround call sites throughout the assembler. This
--- a/js/src/jit/arm/MacroAssembler-arm.cpp
+++ b/js/src/jit/arm/MacroAssembler-arm.cpp
@@ -4767,16 +4767,24 @@ MacroAssemblerARMCompat::asMasm()
 }
 
 const MacroAssembler&
 MacroAssemblerARMCompat::asMasm() const
 {
     return *static_cast<const MacroAssembler*>(this);
 }
 
+void
+MacroAssembler::subFromStackPtr(Imm32 imm32)
+{
+    ScratchRegisterScope scratch(*this);
+    if (imm32.value)
+        ma_sub(imm32, sp, scratch);
+}
+
 //{{{ check_macroassembler_style
 // ===============================================================
 // MacroAssembler high-level usage.
 
 void
 MacroAssembler::flush()
 {
     Assembler::flush();
@@ -4921,25 +4929,16 @@ MacroAssembler::Pop(FloatRegister reg)
 
 void
 MacroAssembler::Pop(const ValueOperand& val)
 {
     popValue(val);
     adjustFrame(-sizeof(Value));
 }
 
-void
-MacroAssembler::reserveStack(uint32_t amount)
-{
-    ScratchRegisterScope scratch(*this);
-    if (amount)
-        ma_sub(Imm32(amount), sp, scratch);
-    adjustFrame(amount);
-}
-
 // ===============================================================
 // Simple call functions.
 
 CodeOffset
 MacroAssembler::call(Register reg)
 {
     as_blx(reg);
     return CodeOffset(currentOffset());
--- a/js/src/jit/arm64/MacroAssembler-arm64.cpp
+++ b/js/src/jit/arm64/MacroAssembler-arm64.cpp
@@ -302,16 +302,25 @@ MacroAssemblerCompat::atomicExchangeToTy
 
 template void
 MacroAssemblerCompat::atomicExchangeToTypedIntArray(Scalar::Type arrayType, const Address& mem,
                                                     Register value, Register temp, AnyRegister output);
 template void
 MacroAssemblerCompat::atomicExchangeToTypedIntArray(Scalar::Type arrayType, const BaseIndex& mem,
                                                     Register value, Register temp, AnyRegister output);
 
+void
+MacroAssembler::reserveStack(uint32_t amount)
+{
+    // TODO: This bumps |sp| every time we reserve using a second register.
+    // It would save some instructions if we had a fixed frame size.
+    vixl::MacroAssembler::Claim(Operand(amount));
+    adjustFrame(amount);
+}
+
 //{{{ check_macroassembler_style
 // ===============================================================
 // MacroAssembler high-level usage.
 
 void
 MacroAssembler::flush()
 {
     Assembler::flush();
@@ -465,25 +474,16 @@ MacroAssembler::Pop(FloatRegister f)
 
 void
 MacroAssembler::Pop(const ValueOperand& val)
 {
     pop(val);
     adjustFrame(-1 * int64_t(sizeof(int64_t)));
 }
 
-void
-MacroAssembler::reserveStack(uint32_t amount)
-{
-    // TODO: This bumps |sp| every time we reserve using a second register.
-    // It would save some instructions if we had a fixed frame size.
-    vixl::MacroAssembler::Claim(Operand(amount));
-    adjustFrame(amount);
-}
-
 // ===============================================================
 // Simple call functions.
 
 CodeOffset
 MacroAssembler::call(Register reg)
 {
     syncStackPtr();
     Blr(ARMRegister(reg, 64));
--- a/js/src/jit/mips32/MacroAssembler-mips32.cpp
+++ b/js/src/jit/mips32/MacroAssembler-mips32.cpp
@@ -2104,16 +2104,23 @@ MacroAssemblerMIPSCompat::profilerEnterF
 }
 
 void
 MacroAssemblerMIPSCompat::profilerExitFrame()
 {
     branch(GetJitContext()->runtime->jitRuntime()->getProfilerExitFrameTail());
 }
 
+void
+MacroAssembler::subFromStackPtr(Imm32 imm32)
+{
+    if (imm32.value)
+        asMasm().subPtr(imm32, StackPointer);
+}
+
 //{{{ check_macroassembler_style
 // ===============================================================
 // Stack manipulation functions.
 
 void
 MacroAssembler::PushRegsInMask(LiveRegisterSet set)
 {
     int32_t diffF = set.fpus().getPushSizeInBytes();
@@ -2165,24 +2172,16 @@ MacroAssembler::PopRegsInMaskIgnore(Live
         diffG -= sizeof(intptr_t);
         if (!ignore.has(*iter))
             loadPtr(Address(StackPointer, diffG), *iter);
     }
     freeStack(reservedG);
     MOZ_ASSERT(diffG == 0);
 }
 
-void
-MacroAssembler::reserveStack(uint32_t amount)
-{
-    if (amount)
-        asMasm().subPtr(Imm32(amount), StackPointer);
-    adjustFrame(amount);
-}
-
 // ===============================================================
 // ABI function calls.
 
 void
 MacroAssembler::setupUnalignedABICall(Register scratch)
 {
     setupABICall();
     dynamicAlignment_ = true;
--- a/js/src/jit/mips64/MacroAssembler-mips64.cpp
+++ b/js/src/jit/mips64/MacroAssembler-mips64.cpp
@@ -2265,16 +2265,23 @@ MacroAssemblerMIPS64Compat::profilerEnte
 }
 
 void
 MacroAssemblerMIPS64Compat::profilerExitFrame()
 {
     branch(GetJitContext()->runtime->jitRuntime()->getProfilerExitFrameTail());
 }
 
+void
+MacroAssembler::subFromStackPtr(Imm32 imm32)
+{
+    if (imm32.value)
+        asMasm().subPtr(imm32, StackPointer);
+}
+
 //{{{ check_macroassembler_style
 // ===============================================================
 // Stack manipulation functions.
 
 void
 MacroAssembler::PushRegsInMask(LiveRegisterSet set)
 {
     int32_t diff = set.gprs().size() * sizeof(intptr_t) +
@@ -2309,24 +2316,16 @@ MacroAssembler::PopRegsInMaskIgnore(Live
         diff -= sizeof(double);
         if (!ignore.has(*iter))
           loadDouble(Address(StackPointer, diff), *iter);
     }
     MOZ_ASSERT(diff == 0);
     freeStack(reserved);
 }
 
-void
-MacroAssembler::reserveStack(uint32_t amount)
-{
-    if (amount)
-        asMasm().subPtr(Imm32(amount), StackPointer);
-    adjustFrame(amount);
-}
-
 // ===============================================================
 // ABI function calls.
 
 void
 MacroAssembler::setupUnalignedABICall(Register scratch)
 {
     setupABICall();
     dynamicAlignment_ = true;
--- a/js/src/jit/x64/MacroAssembler-x64.cpp
+++ b/js/src/jit/x64/MacroAssembler-x64.cpp
@@ -412,41 +412,36 @@ MacroAssemblerX64::asMasm()
 }
 
 const MacroAssembler&
 MacroAssemblerX64::asMasm() const
 {
     return *static_cast<const MacroAssembler*>(this);
 }
 
-//{{{ check_macroassembler_style
-// ===============================================================
-// Stack manipulation functions.
-
 void
-MacroAssembler::reserveStack(uint32_t amount)
+MacroAssembler::subFromStackPtr(Imm32 imm32)
 {
-    if (amount) {
+    if (imm32.value) {
         // 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;
+        uint32_t amountLeft = imm32.value;
         while (amountLeft > 4096) {
             subq(Imm32(4096), StackPointer);
             store32(Imm32(0), Address(StackPointer, 0));
             amountLeft -= 4096;
         }
         subq(Imm32(amountLeft), StackPointer);
     }
-    framePushed_ += amount;
 }
 
-
+//{{{ check_macroassembler_style
 // ===============================================================
 // ABI function calls.
 
 void
 MacroAssembler::setupUnalignedABICall(Register scratch)
 {
     setupABICall();
     dynamicAlignment_ = true;
--- a/js/src/jit/x86/MacroAssembler-x86.cpp
+++ b/js/src/jit/x86/MacroAssembler-x86.cpp
@@ -319,40 +319,36 @@ MacroAssemblerX86::asMasm()
 }
 
 const MacroAssembler&
 MacroAssemblerX86::asMasm() const
 {
     return *static_cast<const MacroAssembler*>(this);
 }
 
-//{{{ check_macroassembler_style
-// ===============================================================
-// Stack manipulation functions.
-
 void
-MacroAssembler::reserveStack(uint32_t amount)
+MacroAssembler::subFromStackPtr(Imm32 imm32)
 {
-    if (amount) {
+    if (imm32.value) {
         // 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;
+        uint32_t amountLeft = imm32.value;
         while (amountLeft > 4096) {
             subl(Imm32(4096), StackPointer);
             store32(Imm32(0), Address(StackPointer, 0));
             amountLeft -= 4096;
         }
         subl(Imm32(amountLeft), StackPointer);
     }
-    framePushed_ += amount;
 }
 
+//{{{ check_macroassembler_style
 // ===============================================================
 // ABI function calls.
 
 void
 MacroAssembler::setupUnalignedABICall(Register scratch)
 {
     setupABICall();
     dynamicAlignment_ = true;