[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