[pypy-commit] pypy emit-call-arm: work on calls that release and reaquire the gil

bivab noreply at buildbot.pypy.org
Fri May 24 09:49:43 CEST 2013


Author: David Schneider <david.schneider at picle.org>
Branch: emit-call-arm
Changeset: r64521:f3faf8d05904
Date: 2013-05-22 10:56 -0500
http://bitbucket.org/pypy/pypy/changeset/f3faf8d05904/

Log:	work on calls that release and reaquire the gil

diff --git a/rpython/jit/backend/arm/callbuilder.py b/rpython/jit/backend/arm/callbuilder.py
--- a/rpython/jit/backend/arm/callbuilder.py
+++ b/rpython/jit/backend/arm/callbuilder.py
@@ -6,6 +6,7 @@
 from rpython.jit.backend.arm.jump import remap_frame_layout
 from rpython.jit.backend.llsupport.callbuilder import AbstractCallBuilder
 from rpython.jit.backend.arm.helper.assembler import count_reg_args
+from rpython.jit.backend.arm.helper.assembler import saved_registers
 from rpython.jit.backend.arm.helper.regalloc import check_imm_arg
 
 
@@ -26,7 +27,6 @@
         self.asm.push_gcmap(self.mc, gcmap, store=True)
 
     def pop_gcmap(self):
-        assert not self.is_call_release_gil
         self.asm._reload_frame_if_necessary(self.mc)
         self.asm.pop_gcmap(self.mc)
 
@@ -69,19 +69,59 @@
             self.mc.gen_load_int(r.ip.value, n, cond=fcond)
             self.mc.ADD_rr(r.sp.value, r.sp.value, r.ip.value, cond=fcond)
 
+    def select_call_release_gil_mode(self):
+        AbstractCallBuilder.select_call_release_gil_mode(self)
+
+    def call_releasegil_addr_and_move_real_arguments(self):
+        assert not self.asm._is_asmgcc()
+        from rpython.jit.backend.arm.regalloc import CoreRegisterManager
+        with saved_registers(self.mc, CoreRegisterManager.save_around_call_regs):
+            self.mc.BL(self.asm.releasegil_addr)
+        #
+        if not we_are_translated():                     # for testing: we should not access
+            self.mc.ADD_ri(r.fp.value, r.fp.value, 1)   # fp any more
+        #
+
+    def move_real_result_and_call_reacqgil_addr(self):
+        # save the result we just got
+        assert not self.asm._is_asmgcc()
+        gpr_to_save, vfp_to_save = self.get_result_locs()
+        with saved_registers(self.mc, gpr_to_save, vfp_to_save):
+            self.mc.BL(self.asm.reacqgil_addr)
+        #
+        if not we_are_translated():                    # for testing: now we can accesss
+            self.mc.SUB_ri(r.fp.value, r.fp.value, 1)  # fp again
+        #
+        #   for shadowstack, done for us by _reload_frame_if_necessary()
+
+    def get_result_locs(self):
+        raise NotImplementedError
+
 
 class SoftFloatCallBuilder(ARMCallbuilder):
 
+    def get_result_locs(self):
+        if self.resloc is None:
+            return [], []
+        if self.resloc.is_vfp_reg():
+            return [r.r0, r.r1], []
+        assert self.resloc.is_reg()
+        return [r.r0], []
+
     def load_result(self):
+        # ensure the result is wellformed and stored in the correct location
         resloc = self.resloc
-        # ensure the result is wellformed and stored in the correct location
-        if resloc is not None:
-            if resloc.is_vfp_reg():
-                # move result to the allocated register
-                self.asm.mov_to_vfp_loc(r.r0, r.r1, resloc)
-            elif resloc.is_reg():
-                self.asm._ensure_result_bit_extension(resloc,
-                                                  self.ressize, self.ressigned)
+        if resloc is None:
+            return
+        if resloc.is_vfp_reg():
+            # move result to the allocated register
+            self.asm.mov_to_vfp_loc(r.r0, r.r1, resloc)
+        elif resloc.is_reg():
+            # move result to the allocated register
+            if resloc is not r.r0:
+                self.asm.mov_loc_loc(r.r0, resloc)
+            self.asm._ensure_result_bit_extension(resloc,
+                                              self.ressize, self.ressign)
 
 
     def _collect_stack_args(self, arglocs):
@@ -140,10 +180,11 @@
                 num += 1
                 count += 1
         # Check that the address of the function we want to call is not
-        # currently stored in one of the registers used to pass the arguments.
+        # currently stored in one of the registers used to pass the arguments
+        # or on the stack, which we can not access later
         # If this happens to be the case we remap the register to r4 and use r4
         # to call the function
-        if self.fnloc in non_float_regs:
+        if self.fnloc in non_float_regs or self.fnloc.is_stack():
             non_float_locs.append(self.fnloc)
             non_float_regs.append(r.r4)
             self.fnloc = r.r4
@@ -195,10 +236,11 @@
             on_stack += 1
         self._push_stack_args(stack_args, on_stack*WORD)
         # Check that the address of the function we want to call is not
-        # currently stored in one of the registers used to pass the arguments.
+        # currently stored in one of the registers used to pass the arguments
+        # or on the stack, which we can not access later
         # If this happens to be the case we remap the register to r4 and use r4
         # to call the function
-        if self.fnloc in non_float_regs:
+        if self.fnloc in non_float_regs or self.fnloc.is_stack():
             non_float_locs.append(self.fnloc)
             non_float_regs.append(r.r4)
             self.fnloc = r.r4
@@ -212,8 +254,15 @@
         # ensure the result is wellformed and stored in the correct location
         if resloc is not None and resloc.is_reg():
             self.asm._ensure_result_bit_extension(resloc,
-                                                  self.ressize, self.ressigned)
+                                                  self.ressize, self.ressign)
 
+    def get_result_locs(self):
+        if self.resloc is None:
+            return [], []
+        if self.resloc.is_vfp_reg():
+            return [], [r.d0]
+        assert self.resloc.is_reg()
+        return [r.r0], []
 
 
 def get_callbuilder(cpu, assembler, fnloc, arglocs,
diff --git a/rpython/jit/backend/arm/opassembler.py b/rpython/jit/backend/arm/opassembler.py
--- a/rpython/jit/backend/arm/opassembler.py
+++ b/rpython/jit/backend/arm/opassembler.py
@@ -1032,10 +1032,10 @@
         assert 0, 'xxx revisit this'
         #
         self._emit_call(op, callargs, fcond)
-        self._emit_guard_may_force(guard_op, arglocs[1 + numargs:], numargs)
+        self._emit_guard_may_force(guard_op, arglocs[1 + numargs:])
         return fcond
 
-    def _emit_guard_may_force(self, guard_op, arglocs, numargs):
+    def _emit_guard_may_force(self, guard_op, arglocs):
         ofs = self.cpu.get_ofs_of_frame_field('jf_descr')
         self.mc.LDR_ri(r.ip.value, r.fp.value, imm=ofs)
         self.mc.CMP_ri(r.ip.value, 0)
@@ -1044,68 +1044,13 @@
 
     def emit_guard_call_release_gil(self, op, guard_op, arglocs, regalloc,
                                                                     fcond):
-
+        numargs = op.numargs()
+        callargs = arglocs[:numargs + 3]      # extract the arguments to the call
+        guardargs = arglocs[len(callargs):]  # extrat the arguments for the guard
         self._store_force_index(guard_op)
-        self._emit_call(op, arglocs, result_loc, is_call_release_gil=True)
-        self._emit_guard_may_force(guard_op, arglocs[numargs+1:], numargs)
+        self._emit_call(op, arglocs, is_call_release_gil=True)
+        self._emit_guard_may_force(guard_op, guardargs)
         return fcond
-        # first, close the stack in the sense of the asmgcc GC root tracker
-        #gcrootmap = self.cpu.gc_ll_descr.gcrootmap
-        #numargs = op.numargs()
-        #callargs = arglocs[2:numargs + 1]  # extract the arguments to the call
-        #adr = arglocs[1]
-        #resloc = arglocs[0]
-
-        #if gcrootmap:
-        #    # we put the gcmap now into the frame before releasing the GIL,
-        #    # and pop it below after reacquiring the GIL.  The assumption
-        #    # is that this gcmap describes correctly the situation at any
-        #    # point in-between: all values containing GC pointers should
-        #    # be safely saved out of registers by now, and will not be
-        #    # manipulated by any of the following CALLs.
-        #    gcmap = self._regalloc.get_gcmap(noregs=True)
-        #    self.push_gcmap(self.mc, gcmap, store=True)
-        #    self.call_release_gil(gcrootmap, arglocs, regalloc, fcond)
-        ## do the call
-        #descr = op.getdescr()
-        #size = descr.get_result_size()
-        #signed = descr.is_result_signed()
-        ##
-        #self._emit_call(adr, callargs, fcond,
-        #                            resloc, (size, signed),
-        #                            is_call_release_gil=True)
-        ## then reopen the stack
-        #if gcrootmap:
-        #    self.call_reacquire_gil(gcrootmap, resloc, regalloc, fcond)
-        #    self.pop_gcmap(self.mc)     # remove the gcmap saved above
-
-
-    def call_release_gil(self, gcrootmap, save_registers, regalloc, fcond):
-        # Save caller saved registers and do the call
-        # NOTE: We assume that  the floating point registers won't be modified.
-        assert gcrootmap.is_shadow_stack
-        with saved_registers(self.mc, regalloc.rm.save_around_call_regs):
-            self._emit_call(imm(self.releasegil_addr), [],
-                                        fcond, is_call_release_gil=True)
-
-    def call_reacquire_gil(self, gcrootmap, save_loc, regalloc, fcond):
-        # save the previous result into the stack temporarily, in case it is in
-        # a caller saved register.
-        # NOTE: like with call_release_gil(), we assume that we don't need to
-        # save vfp regs in this case. Besides the result location
-        regs_to_save = []
-        vfp_regs_to_save = []
-        if save_loc and save_loc in regalloc.rm.save_around_call_regs:
-            regs_to_save.append(save_loc)
-            regs_to_save.append(r.ip)  # for alingment
-        elif save_loc and save_loc in regalloc.vfprm.save_around_call_regs:
-            vfp_regs_to_save.append(save_loc)
-        assert gcrootmap.is_shadow_stack
-        # call the reopenstack() function (also reacquiring the GIL)
-        with saved_registers(self.mc, regs_to_save, vfp_regs_to_save):
-            self._emit_call(imm(self.reacqgil_addr), [], fcond,
-                    is_call_release_gil=True)
-        self._reload_frame_if_necessary(self.mc)
 
     def _store_force_index(self, guard_op):
         faildescr = guard_op.getdescr()
diff --git a/rpython/jit/backend/llsupport/assembler.py b/rpython/jit/backend/llsupport/assembler.py
--- a/rpython/jit/backend/llsupport/assembler.py
+++ b/rpython/jit/backend/llsupport/assembler.py
@@ -372,6 +372,9 @@
         self.releasegil_addr  = self.cpu.cast_ptr_to_int(releasegil_func)
         self.reacqgil_addr = self.cpu.cast_ptr_to_int(reacqgil_func)
 
+    def _is_asmgcc(self):
+        gcrootmap = self.cpu.gc_ll_descr.gcrootmap
+        return bool(gcrootmap) and not gcrootmap.is_shadow_stack
 
 
 def debug_bridge(descr_number, rawstart, codeendpos):
diff --git a/rpython/jit/backend/llsupport/callbuilder.py b/rpython/jit/backend/llsupport/callbuilder.py
--- a/rpython/jit/backend/llsupport/callbuilder.py
+++ b/rpython/jit/backend/llsupport/callbuilder.py
@@ -8,12 +8,13 @@
     # is it for the main CALL of a call_release_gil?
     is_call_release_gil = False
 
-    # set by save_result_value()
-    tmpresloc = None
+    # this can be set to guide more complex calls: gives the detailed
+    # type of the arguments
+    argtypes = ""
+    ressign = False
+
 
     def __init__(self, assembler, fnloc, arglocs, resloc, restype, ressize):
-        # Avoid tons of issues with a non-immediate fnloc by sticking it
-        # as an extra argument if needed
         self.fnloc = fnloc
         self.arglocs = arglocs
         self.asm = assembler
@@ -21,7 +22,6 @@
         self.resloc = resloc
         self.restype = restype
         self.ressize = ressize
-        self.ressigned = False
 
     def emit_no_collect(self):
         """Emit a call that cannot collect."""
@@ -52,6 +52,12 @@
         self.pop_gcmap()
         self.load_result()
 
+    def call_releasegil_addr_and_move_real_arguments(self):
+        raise NotImplementedError
+
+    def move_real_result_and_call_reacqgil_addr(self):
+        raise NotImplementedError
+
     def select_call_release_gil_mode(self):
         """Overridden in CallBuilder64"""
         self.is_call_release_gil = True
@@ -62,6 +68,17 @@
     def push_gcmap(self):
         raise NotImplementedError
 
+    def push_gcmap_for_call_release_gil(self):
+        assert self.is_call_release_gil
+        # we put the gcmap now into the frame before releasing the GIL,
+        # and pop it after reacquiring the GIL.  The assumption
+        # is that this gcmap describes correctly the situation at any
+        # point in-between: all values containing GC pointers should
+        # be safely saved out of registers by now, and will not be
+        # manipulated by any of the following CALLs.
+        gcmap = self.asm._regalloc.get_gcmap(noregs=True)
+        self.asm.push_gcmap(self.mc, gcmap, store=True)
+
     def pop_gcmap(self):
         raise NotImplementedError
 
diff --git a/rpython/jit/backend/x86/assembler.py b/rpython/jit/backend/x86/assembler.py
--- a/rpython/jit/backend/x86/assembler.py
+++ b/rpython/jit/backend/x86/assembler.py
@@ -999,10 +999,6 @@
                     self.implement_guard(guard_token, checkfalsecond)
         return genop_cmp_guard_float
 
-    def _is_asmgcc(self):
-        gcrootmap = self.cpu.gc_ll_descr.gcrootmap
-        return bool(gcrootmap) and not gcrootmap.is_shadow_stack
-
     def simple_call(self, fnloc, arglocs, result_loc=eax):
         if result_loc is xmm0:
             result_type = FLOAT
diff --git a/rpython/jit/backend/x86/callbuilder.py b/rpython/jit/backend/x86/callbuilder.py
--- a/rpython/jit/backend/x86/callbuilder.py
+++ b/rpython/jit/backend/x86/callbuilder.py
@@ -19,23 +19,21 @@
     return (words + CALL_ALIGN - 1) & ~(CALL_ALIGN-1)
 
 
-
-
 class CallBuilderX86(AbstractCallBuilder):
 
     # max number of words we have room in esp; if we need more for
     # arguments, we need to decrease esp temporarily
     stack_max = PASS_ON_MY_FRAME
 
-    # this can be set to guide more complex calls: gives the detailed
-    # type of the arguments
-    argtypes = ""
-    ressign = False
+    # set by save_result_value()
+    tmpresloc = None
 
     def __init__(self, assembler, fnloc, arglocs,
                  resloc=eax, restype=INT, ressize=WORD):
         AbstractCallBuilder.__init__(self, assembler, fnloc, arglocs,
                                      resloc, restype, ressize)
+        # Avoid tons of issues with a non-immediate fnloc by sticking it
+        # as an extra argument if needed
         self.fnloc_is_immediate = isinstance(fnloc, ImmedLoc)
         if not self.fnloc_is_immediate:
             self.fnloc = None
@@ -96,17 +94,6 @@
         gcmap = self.asm._regalloc.get_gcmap([eax], noregs=noregs)
         self.asm.push_gcmap(self.mc, gcmap, store=True)
 
-    def push_gcmap_for_call_release_gil(self):
-        assert self.is_call_release_gil
-        # we put the gcmap now into the frame before releasing the GIL,
-        # and pop it after reacquiring the GIL.  The assumption
-        # is that this gcmap describes correctly the situation at any
-        # point in-between: all values containing GC pointers should
-        # be safely saved out of registers by now, and will not be
-        # manipulated by any of the following CALLs.
-        gcmap = self.asm._regalloc.get_gcmap(noregs=True)
-        self.asm.push_gcmap(self.mc, gcmap, store=True)
-
     def pop_gcmap(self):
         self.asm._reload_frame_if_necessary(self.mc)
         if self.change_extra_stack_depth:


More information about the pypy-commit mailing list