[pypy-svn] pypy jitypes2: Implement closing and reopening the stack.

arigo commits-noreply at bitbucket.org
Mon Mar 28 15:58:48 CEST 2011


Author: Armin Rigo <arigo at tunes.org>
Branch: jitypes2
Changeset: r42996:58a292fcefa5
Date: 2011-03-28 15:57 +0200
http://bitbucket.org/pypy/pypy/changeset/58a292fcefa5/

Log:	Implement closing and reopening the stack.

diff --git a/pypy/jit/backend/llsupport/regalloc.py b/pypy/jit/backend/llsupport/regalloc.py
--- a/pypy/jit/backend/llsupport/regalloc.py
+++ b/pypy/jit/backend/llsupport/regalloc.py
@@ -37,6 +37,11 @@
         self.frame_depth += size
         return newloc
 
+    def reserve_location_in_frame(self, size):
+        frame_depth = self.frame_depth
+        self.frame_depth += size
+        return frame_depth
+
     # abstract methods that need to be overwritten for specific assemblers
     @staticmethod
     def frame_pos(loc, type):

diff --git a/pypy/jit/backend/llsupport/gc.py b/pypy/jit/backend/llsupport/gc.py
--- a/pypy/jit/backend/llsupport/gc.py
+++ b/pypy/jit/backend/llsupport/gc.py
@@ -15,7 +15,6 @@
 from pypy.jit.backend.llsupport.descr import GcCache, get_field_descr
 from pypy.jit.backend.llsupport.descr import GcPtrFieldDescr
 from pypy.jit.backend.llsupport.descr import get_call_descr
-from pypy.rpython.memory.gctransform import asmgcroot
 
 # ____________________________________________________________
 
@@ -309,6 +308,7 @@
 
     @rgc.no_collect
     def freeing_block(self, start, stop):
+        from pypy.rpython.memory.gctransform import asmgcroot
         # if [start:stop] is a raw block of assembler, then look up the
         # corresponding gcroot markers, and mark them as freed now in
         # self._gcmap by setting the 2nd address of every entry to NULL.

diff --git a/pypy/jit/backend/x86/regalloc.py b/pypy/jit/backend/x86/regalloc.py
--- a/pypy/jit/backend/x86/regalloc.py
+++ b/pypy/jit/backend/x86/regalloc.py
@@ -126,6 +126,7 @@
         self.translate_support_code = translate_support_code
         # to be read/used by the assembler too
         self.jump_target_descr = None
+        self.close_stack_struct = 0
 
     def _prepare(self, inputargs, operations):
         self.fm = X86FrameManager()
@@ -801,6 +802,11 @@
         self._consider_call(op, guard_op)
 
     def consider_call_release_gil(self, op, guard_op):
+        # first force the registers like eax into the stack, because of
+        # the initial call to _close_stack()
+        self.rm.before_call()
+        self.xrm.before_call()
+        #
         assert guard_op is not None
         self._consider_call(op, guard_op)
 

diff --git a/pypy/jit/backend/x86/runner.py b/pypy/jit/backend/x86/runner.py
--- a/pypy/jit/backend/x86/runner.py
+++ b/pypy/jit/backend/x86/runner.py
@@ -113,10 +113,11 @@
                 LLInterpreter.current_interpreter = prev_interpreter
         return res
 
-    @staticmethod
     def cast_ptr_to_int(x):
         adr = llmemory.cast_ptr_to_adr(x)
         return CPU386.cast_adr_to_int(adr)
+    cast_ptr_to_int._annspecialcase_ = 'specialize:arglltype(0)'
+    cast_ptr_to_int = staticmethod(cast_ptr_to_int)
 
     all_null_registers = lltype.malloc(rffi.LONGP.TO, 24,
                                        flavor='raw', zero=True,

diff --git a/pypy/jit/backend/x86/rx86.py b/pypy/jit/backend/x86/rx86.py
--- a/pypy/jit/backend/x86/rx86.py
+++ b/pypy/jit/backend/x86/rx86.py
@@ -505,6 +505,7 @@
     POP_b = insn(rex_nw, '\x8F', orbyte(0<<3), stack_bp(1))
 
     LEA_rb = insn(rex_w, '\x8D', register(1,8), stack_bp(2))
+    LEA_rs = insn(rex_w, '\x8D', register(1,8), stack_sp(2))
     LEA32_rb = insn(rex_w, '\x8D', register(1,8),stack_bp(2,force_32bits=True))
     LEA_ra = insn(rex_w, '\x8D', register(1, 8), mem_reg_plus_scaled_reg_plus_const(2))
     LEA_rm = insn(rex_w, '\x8D', register(1, 8), mem_reg_plus_const(2))

diff --git a/pypy/jit/backend/x86/assembler.py b/pypy/jit/backend/x86/assembler.py
--- a/pypy/jit/backend/x86/assembler.py
+++ b/pypy/jit/backend/x86/assembler.py
@@ -127,6 +127,8 @@
         if hasattr(gc_ll_descr, 'get_malloc_fixedsize_slowpath_addr'):
             self._build_malloc_fixedsize_slowpath()
         self._build_stack_check_slowpath()
+        if gc_ll_descr.gcrootmap:
+            self._build_close_stack()
         debug_start('jit-backend-counts')
         self.set_debug(have_debug_prints())
         debug_stop('jit-backend-counts')
@@ -274,6 +276,40 @@
         rawstart = mc.materialize(self.cpu.asmmemmgr, [])
         self.stack_check_slowpath = rawstart
 
+    @staticmethod
+    def _close_stack(css):
+        # similar to trackgcroot.py:pypy_asm_stackwalk, first part
+        from pypy.rpython.memory.gctransform import asmgcroot
+        new = rffi.cast(asmgcroot.ASM_FRAMEDATA_HEAD_PTR, css)
+        next = asmgcroot.gcrootanchor.next
+        new.next = next
+        new.prev = asmgcroot.gcrootanchor
+        asmgcroot.gcrootanchor.next = new
+        next.prev = new
+        # XXX and now release the GIL
+
+    @staticmethod
+    def _reopen_stack(css):
+        # similar to trackgcroot.py:pypy_asm_stackwalk, second part
+        from pypy.rpython.memory.gctransform import asmgcroot
+        # XXX first reacquire the GIL
+        old = rffi.cast(asmgcroot.ASM_FRAMEDATA_HEAD_PTR, css)
+        prev = old.prev
+        next = old.next
+        prev.next = next
+        next.prev = prev
+
+    _CLOSESTACK_FUNC = lltype.Ptr(lltype.FuncType([rffi.LONGP],
+                                                  lltype.Void))
+
+    def _build_close_stack(self):
+        closestack_func = llhelper(self._CLOSESTACK_FUNC,
+                                   self._close_stack)
+        reopenstack_func = llhelper(self._CLOSESTACK_FUNC,
+                                    self._reopen_stack)
+        self.closestack_addr  = self.cpu.cast_ptr_to_int(closestack_func)
+        self.reopenstack_addr = self.cpu.cast_ptr_to_int(reopenstack_func)
+
     def assemble_loop(self, inputargs, operations, looptoken, log):
         '''adds the following attributes to looptoken:
                _x86_loop_code       (an integer giving an address)
@@ -1832,7 +1868,75 @@
         self.mc.CMP_bi(FORCE_INDEX_OFS, 0)
         self.implement_guard(guard_token, 'L')
 
-    genop_guard_call_release_gil = genop_guard_call_may_force
+    def genop_guard_call_release_gil(self, op, guard_op, guard_token,
+                                     arglocs, result_loc):
+        # first, close the stack in the sense of the asmgcc GC root tracker
+        gcrootmap = self.cpu.gc_ll_descr.gcrootmap
+        if gcrootmap:
+            # note that regalloc.py used save_all_regs=True to save all
+            # registers, so we don't have to care about saving them (other
+            # than ebp) in the close_stack_struct
+            self.call_close_stack()
+        # do the call
+        faildescr = guard_op.getdescr()
+        fail_index = self.cpu.get_fail_descr_number(faildescr)
+        self.mc.MOV_bi(FORCE_INDEX_OFS, fail_index)
+        self.genop_call(op, arglocs, result_loc)
+        # then reopen the stack
+        if gcrootmap:
+            self.call_reopen_stack(result_loc)
+        # finally, the guard_not_forced
+        self.mc.CMP_bi(FORCE_INDEX_OFS, 0)
+        self.implement_guard(guard_token, 'L')
+
+    def call_close_stack(self):
+        from pypy.rpython.memory.gctransform import asmgcroot
+        css = self._regalloc.close_stack_struct
+        if css == 0:
+            use_words = (2 + max(asmgcroot.INDEX_OF_EBP,
+                                 asmgcroot.FRAME_PTR) + 1)
+            pos = self._regalloc.fm.reserve_location_in_frame(use_words)
+            css = get_ebp_ofs(pos + use_words - 1)
+            self._regalloc.close_stack_struct = css
+        # The location where the future CALL will put its return address
+        # will be [ESP-WORD], so save that as the next frame's top address
+        self.mc.LEA_rs(eax.value, -WORD)        # LEA EAX, [ESP-4]
+        frame_ptr = css + WORD * (2+asmgcroot.FRAME_PTR)
+        self.mc.MOV_br(frame_ptr, eax.value)    # MOV [css.frame], EAX
+        # Save ebp
+        index_of_ebp = css + WORD * (2+asmgcroot.INDEX_OF_EBP)
+        self.mc.MOV_br(index_of_ebp, ebp.value) # MOV [css.ebp], EBP
+        # Call the closestack() function (also releasing the GIL)
+        if IS_X86_32:
+            reg = eax
+        elif IS_X86_64:
+            reg = edi
+        self.mc.LEA_rb(reg.value, css)
+        self._emit_call(imm(self.closestack_addr), [reg])
+
+    def call_reopen_stack(self, save_loc):
+        # save the previous result (eax/xmm0) into the stack temporarily
+        if isinstance(save_loc, RegLoc):
+            self._regalloc.reserve_param(save_loc.width//WORD)
+            if save_loc.is_xmm:
+                self.mc.MOVSD_sx(0, save_loc.value)
+            else:
+                self.mc.MOV_sr(0, save_loc.value)
+        # call the reopenstack() function (also reacquiring the GIL)
+        css = self._regalloc.close_stack_struct
+        assert css != 0
+        if IS_X86_32:
+            reg = eax
+        elif IS_X86_64:
+            reg = edi
+        self.mc.LEA_rb(reg.value, css)
+        self._emit_call(imm(self.reopenstack_addr), [reg])
+        # restore the result from the stack
+        if isinstance(save_loc, RegLoc):
+            if save_loc.is_xmm:
+                self.mc.MOVSD_xs(save_loc.value, 0)
+            else:
+                self.mc.MOV_rs(save_loc.value, 0)
 
     def genop_guard_call_assembler(self, op, guard_op, guard_token,
                                    arglocs, result_loc):
@@ -2042,7 +2146,7 @@
         # on 64-bits, 'tid' is a value that fits in 31 bits
         self.mc.MOV_mi((eax.value, 0), tid)
         self.mc.MOV(heap(nursery_free_adr), edx)
-        
+
 genop_discard_list = [Assembler386.not_implemented_op_discard] * rop._LAST
 genop_list = [Assembler386.not_implemented_op] * rop._LAST
 genop_llong_list = {}


More information about the Pypy-commit mailing list