Bug 1488763 - Unify stack touch logic across all platforms r=jandem
authorMatthew Gaudet <mgaudet@mozilla.com>
Mon, 05 Nov 2018 09:35:01 +0000
changeset 444443 e3a9e32b069a38af83b0f3b2a311dd5b3ce4d0d1
parent 444442 25d0d3ae255458d0392f8ce556d96bf86f9943fd
child 444444 d52d219bbf6baae4a868316e3edc6c83be32f83b
push id109593
push usernbeleuzu@mozilla.com
push dateMon, 05 Nov 2018 21:54:22 +0000
treeherdermozilla-inbound@c58b8835f297 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjandem
bugs1488763
milestone65.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 1488763 - Unify stack touch logic across all platforms r=jandem This incidentally also -adds- the stack touch logic to ARM64. Differential Revision: https://phabricator.services.mozilla.com/D10395
js/src/jit/JitRealm.h
js/src/jit/MacroAssembler.cpp
js/src/jit/MacroAssembler.h
js/src/jit/arm/Trampoline-arm.cpp
js/src/jit/arm64/Trampoline-arm64.cpp
js/src/jit/x64/Trampoline-x64.cpp
js/src/jit/x86/Trampoline-x86.cpp
--- a/js/src/jit/JitRealm.h
+++ b/js/src/jit/JitRealm.h
@@ -616,22 +616,16 @@ class JitRealm
 
     bool stringsCanBeInNursery;
 };
 
 // Called from Zone::discardJitCode().
 void InvalidateAll(FreeOp* fop, JS::Zone* zone);
 void FinishInvalidation(FreeOp* fop, JSScript* script);
 
-// On windows systems, really large frames need to be incrementally touched.
-// The following constant defines the minimum increment of the touch.
-#ifdef XP_WIN
-const unsigned WINDOWS_BIG_FRAME_TOUCH_INCREMENT = 4096 - 1;
-#endif
-
 // This class ensures JIT code is executable on its destruction. Creators
 // must call makeWritable(), and not attempt to write to the buffer if it fails.
 //
 // AutoWritableJitCodeFallible may only fail to make code writable; it cannot fail to
 // make JIT code executable (because the creating code has no chance to
 // recover from a failed destructor).
 class MOZ_RAII AutoWritableJitCodeFallible
 {
--- a/js/src/jit/MacroAssembler.cpp
+++ b/js/src/jit/MacroAssembler.cpp
@@ -3960,16 +3960,45 @@ MacroAssembler::performPendingReadBarrie
     for (JSObject* object : pendingObjectReadBarriers_) {
         JSObject::readBarrier(object);
     }
     for (ObjectGroup* group : pendingObjectGroupReadBarriers_) {
         ObjectGroup::readBarrier(group);
     }
 }
 
+// Can't push large frames blindly on windows, so we must touch frame memory
+// incrementally, with no more than 4096 - 1 bytes between touches.
+//
+// This is used across all platforms for simplicity.
+void
+MacroAssembler::touchFrameValues(Register numStackValues, Register scratch1, Register scratch2)
+{
+    const size_t FRAME_TOUCH_INCREMENT = 2048;
+    static_assert(FRAME_TOUCH_INCREMENT < 4096 -1, "Frame increment is too large");
+
+    moveStackPtrTo(scratch2);
+    mov(numStackValues, scratch1);
+    lshiftPtr(Imm32(3), scratch1);
+    subPtr(scratch1, scratch2);
+    {
+        moveStackPtrTo(scratch1);
+        subPtr(Imm32(FRAME_TOUCH_INCREMENT), scratch1);
+
+        Label touchFrameLoop;
+        Label touchFrameLoopEnd;
+        bind(&touchFrameLoop);
+        branchPtr(Assembler::Below, scratch1, scratch2, &touchFrameLoopEnd);
+        store32(Imm32(0), Address(scratch1, 0));
+        subPtr(Imm32(FRAME_TOUCH_INCREMENT), scratch1);
+        jump(&touchFrameLoop);
+        bind(&touchFrameLoopEnd);
+    }
+}
+
 namespace js {
 namespace jit {
 
 #ifdef DEBUG
 template <class RegisterType>
 AutoGenericRegisterScope<RegisterType>::AutoGenericRegisterScope(MacroAssembler& masm, RegisterType reg)
   : RegisterType(reg), masm_(masm), released_(false)
 {
--- a/js/src/jit/MacroAssembler.h
+++ b/js/src/jit/MacroAssembler.h
@@ -2766,16 +2766,18 @@ class MacroAssembler : public MacroAssem
     // the JitStackAlignment.
     void alignJitStackBasedOnNArgs(Register nargs);
     void alignJitStackBasedOnNArgs(uint32_t nargs);
 
     inline void assertStackAlignment(uint32_t alignment, int32_t offset = 0);
 
     void performPendingReadBarriers();
 
+    void touchFrameValues(Register numStackValues, Register scratch1, Register scratch2);
+
   private:
     // Methods to get a singleton object or object group from a type set without
     // a read barrier, and record the result so that we can perform the barrier
     // later.
     JSObject* getSingletonAndDelayBarrier(const TypeSet* types, size_t i);
     ObjectGroup* getGroupAndDelayBarrier(const TypeSet* types, size_t i);
 
     Vector<JSObject*, 0, SystemAllocPolicy> pendingObjectReadBarriers_;
--- a/js/src/jit/arm/Trampoline-arm.cpp
+++ b/js/src/jit/arm/Trampoline-arm.cpp
@@ -250,40 +250,20 @@ JitRuntime::generateEnterJIT(JSContext* 
         }
 
         // Push previous frame pointer.
         masm.push(r11);
 
         // Reserve frame.
         Register framePtr = r11;
         masm.subPtr(Imm32(BaselineFrame::Size()), sp);
+
+        masm.touchFrameValues(numStackValues, scratch, framePtr);
         masm.mov(sp, framePtr);
 
-#ifdef XP_WIN
-        // Can't push large frames blindly on windows. Touch frame memory
-        // incrementally.
-        masm.ma_lsl(Imm32(3), numStackValues, scratch);
-        masm.subPtr(scratch, framePtr);
-        {
-            ScratchRegisterScope asmScratch(masm);
-            masm.ma_sub(sp, Imm32(WINDOWS_BIG_FRAME_TOUCH_INCREMENT), scratch, asmScratch);
-        }
-        {
-            Label touchFrameLoop;
-            Label touchFrameLoopEnd;
-            masm.bind(&touchFrameLoop);
-            masm.branchPtr(Assembler::Below, scratch, framePtr, &touchFrameLoopEnd);
-            masm.store32(Imm32(0), Address(scratch, 0));
-            masm.subPtr(Imm32(WINDOWS_BIG_FRAME_TOUCH_INCREMENT), scratch);
-            masm.jump(&touchFrameLoop);
-            masm.bind(&touchFrameLoopEnd);
-        }
-        masm.mov(sp, framePtr);
-#endif
-
         // Reserve space for locals and stack values.
         masm.ma_lsl(Imm32(3), numStackValues, scratch);
         masm.ma_sub(sp, scratch, sp);
 
         // Enter exit frame.
         masm.addPtr(Imm32(BaselineFrame::Size() + BaselineFrame::FramePointerOffset), scratch);
         masm.makeFrameDescriptor(scratch, FrameType::BaselineJS, ExitFrameLayout::Size());
         masm.push(scratch);
--- a/js/src/jit/arm64/Trampoline-arm64.cpp
+++ b/js/src/jit/arm64/Trampoline-arm64.cpp
@@ -168,16 +168,18 @@ JitRuntime::generateEnterJIT(JSContext* 
         masm.branchTestPtr(Assembler::Zero, OsrFrameReg, OsrFrameReg, &notOsr);
 
         // Push return address and previous frame pointer.
         masm.Adr(ScratchReg2_64, &osrReturnPoint);
         masm.push(ScratchReg2, BaselineFrameReg);
 
         // Reserve frame.
         masm.subFromStackPtr(Imm32(BaselineFrame::Size()));
+
+        masm.touchFrameValues(reg_osrNStack, ScratchReg2, BaselineFrameReg);
         masm.moveStackPtrTo(BaselineFrameReg);
 
         // Reserve space for locals and stack values.
         masm.Lsl(w19, ARMRegister(reg_osrNStack, 32), 3); // w19 = num_stack_values * sizeof(Value).
         masm.subFromStackPtr(r19);
 
         // Enter exit frame.
         masm.addPtr(Imm32(BaselineFrame::Size() + BaselineFrame::FramePointerOffset), r19);
--- a/js/src/jit/x64/Trampoline-x64.cpp
+++ b/js/src/jit/x64/Trampoline-x64.cpp
@@ -192,39 +192,20 @@ JitRuntime::generateEnterJIT(JSContext* 
         masm.push(scratch);
 
         // Push previous frame pointer.
         masm.push(rbp);
 
         // Reserve frame.
         Register framePtr = rbp;
         masm.subPtr(Imm32(BaselineFrame::Size()), rsp);
+
+        masm.touchFrameValues(numStackValues, scratch, framePtr);
         masm.mov(rsp, framePtr);
 
-#ifdef XP_WIN
-        // Can't push large frames blindly on windows.  Touch frame memory incrementally.
-        masm.mov(numStackValues, scratch);
-        masm.lshiftPtr(Imm32(3), scratch);
-        masm.subPtr(scratch, framePtr);
-        {
-            masm.movePtr(rsp, scratch);
-            masm.subPtr(Imm32(WINDOWS_BIG_FRAME_TOUCH_INCREMENT), scratch);
-
-            Label touchFrameLoop;
-            Label touchFrameLoopEnd;
-            masm.bind(&touchFrameLoop);
-            masm.branchPtr(Assembler::Below, scratch, framePtr, &touchFrameLoopEnd);
-            masm.store32(Imm32(0), Address(scratch, 0));
-            masm.subPtr(Imm32(WINDOWS_BIG_FRAME_TOUCH_INCREMENT), scratch);
-            masm.jump(&touchFrameLoop);
-            masm.bind(&touchFrameLoopEnd);
-        }
-        masm.mov(rsp, framePtr);
-#endif
-
         // Reserve space for locals and stack values.
         Register valuesSize = regs.takeAny();
         masm.mov(numStackValues, valuesSize);
         masm.shll(Imm32(3), valuesSize);
         masm.subPtr(valuesSize, rsp);
 
         // Enter exit frame.
         masm.addPtr(Imm32(BaselineFrame::Size() + BaselineFrame::FramePointerOffset), valuesSize);
--- a/js/src/jit/x86/Trampoline-x86.cpp
+++ b/js/src/jit/x86/Trampoline-x86.cpp
@@ -186,39 +186,20 @@ JitRuntime::generateEnterJIT(JSContext* 
         masm.push(scratch);
 
         // Push previous frame pointer.
         masm.push(ebp);
 
         // Reserve frame.
         Register framePtr = ebp;
         masm.subPtr(Imm32(BaselineFrame::Size()), esp);
+
+        masm.touchFrameValues(numStackValues, scratch, framePtr);
         masm.mov(esp, framePtr);
 
-#ifdef XP_WIN
-        // Can't push large frames blindly on windows.  Touch frame memory incrementally.
-        masm.mov(numStackValues, scratch);
-        masm.shll(Imm32(3), scratch);
-        masm.subPtr(scratch, framePtr);
-        {
-            masm.movePtr(esp, scratch);
-            masm.subPtr(Imm32(WINDOWS_BIG_FRAME_TOUCH_INCREMENT), scratch);
-
-            Label touchFrameLoop;
-            Label touchFrameLoopEnd;
-            masm.bind(&touchFrameLoop);
-            masm.branchPtr(Assembler::Below, scratch, framePtr, &touchFrameLoopEnd);
-            masm.store32(Imm32(0), Address(scratch, 0));
-            masm.subPtr(Imm32(WINDOWS_BIG_FRAME_TOUCH_INCREMENT), scratch);
-            masm.jump(&touchFrameLoop);
-            masm.bind(&touchFrameLoopEnd);
-        }
-        masm.mov(esp, framePtr);
-#endif
-
         // Reserve space for locals and stack values.
         masm.mov(numStackValues, scratch);
         masm.shll(Imm32(3), scratch);
         masm.subPtr(scratch, esp);
 
         // Enter exit frame.
         masm.addPtr(Imm32(BaselineFrame::Size() + BaselineFrame::FramePointerOffset), scratch);
         masm.makeFrameDescriptor(scratch, FrameType::BaselineJS, ExitFrameLayout::Size());