Author: Armin Rigo <[email protected]>
Branch:
Changeset: r84862:6aa8ce23a942
Date: 2016-06-01 16:01 +0200
http://bitbucket.org/pypy/pypy/changeset/6aa8ce23a942/
Log: Don't spill registers with pointers around calls that cannot collect
diff --git a/rpython/jit/backend/arm/regalloc.py
b/rpython/jit/backend/arm/regalloc.py
--- a/rpython/jit/backend/arm/regalloc.py
+++ b/rpython/jit/backend/arm/regalloc.py
@@ -397,9 +397,9 @@
else:
self.rm.force_spill_var(var)
- def before_call(self, force_store=[], save_all_regs=False):
- self.rm.before_call(force_store, save_all_regs)
- self.vfprm.before_call(force_store, save_all_regs)
+ def before_call(self, save_all_regs=False):
+ self.rm.before_call(save_all_regs)
+ self.vfprm.before_call(save_all_regs)
def _sync_var(self, v):
if v.type == FLOAT:
@@ -552,8 +552,7 @@
prepare_op_call_f = _prepare_op_call
prepare_op_call_n = _prepare_op_call
- def _prepare_call(self, op, force_store=[], save_all_regs=False,
- first_arg_index=1):
+ def _prepare_call(self, op, save_all_regs=False, first_arg_index=1):
args = [None] * (op.numargs() + 3)
calldescr = op.getdescr()
assert isinstance(calldescr, CallDescr)
@@ -571,17 +570,27 @@
args[1] = imm(size)
args[2] = sign_loc
- args[0] = self._call(op, args, force_store, save_all_regs)
+ effectinfo = calldescr.get_extra_info()
+ if save_all_regs:
+ gc_level = 2
+ elif effectinfo is None or effectinfo.check_can_collect():
+ gc_level = 1
+ else:
+ gc_level = 0
+
+ args[0] = self._call(op, args, gc_level)
return args
- def _call(self, op, arglocs, force_store=[], save_all_regs=False):
- # spill variables that need to be saved around calls
- self.vfprm.before_call(force_store, save_all_regs=save_all_regs)
- if not save_all_regs:
- gcrootmap = self.cpu.gc_ll_descr.gcrootmap
- if gcrootmap and gcrootmap.is_shadow_stack:
- save_all_regs = 2
- self.rm.before_call(force_store, save_all_regs=save_all_regs)
+ def _call(self, op, arglocs, gc_level):
+ # spill variables that need to be saved around calls:
+ # gc_level == 0: callee cannot invoke the GC
+ # gc_level == 1: can invoke GC, save all regs that contain pointers
+ # gc_level == 2: can force, save all regs
+ save_all_regs = gc_level == 2
+ self.vfprm.before_call(save_all_regs=save_all_regs)
+ if gc_level == 1 and self.cpu.gc_ll_descr.gcrootmap:
+ save_all_regs = 2
+ self.rm.before_call(save_all_regs=save_all_regs)
resloc = self.after_call(op)
return resloc
@@ -1068,7 +1077,7 @@
def _prepare_op_call_assembler(self, op, fcond):
locs = self.locs_for_call_assembler(op)
tmploc = self.get_scratch_reg(INT, selected_reg=r.r0)
- resloc = self._call(op, locs + [tmploc], save_all_regs=True)
+ resloc = self._call(op, locs + [tmploc], gc_level=2)
return locs + [resloc, tmploc]
prepare_op_call_assembler_i = _prepare_op_call_assembler
diff --git a/rpython/jit/backend/ppc/regalloc.py
b/rpython/jit/backend/ppc/regalloc.py
--- a/rpython/jit/backend/ppc/regalloc.py
+++ b/rpython/jit/backend/ppc/regalloc.py
@@ -369,9 +369,9 @@
# This operation is used only for testing
self.force_spill_var(op.getarg(0))
- def before_call(self, force_store=[], save_all_regs=False):
- self.rm.before_call(force_store, save_all_regs)
- self.fprm.before_call(force_store, save_all_regs)
+ def before_call(self, save_all_regs=False):
+ self.rm.before_call(save_all_regs)
+ self.fprm.before_call(save_all_regs)
def after_call(self, v):
if v.type == FLOAT:
@@ -756,7 +756,7 @@
src_ofs_loc = self.ensure_reg_or_any_imm(op.getarg(2))
dst_ofs_loc = self.ensure_reg_or_any_imm(op.getarg(3))
length_loc = self.ensure_reg_or_any_imm(op.getarg(4))
- self._spill_before_call(save_all_regs=False)
+ self._spill_before_call(gc_level=0)
return [src_ptr_loc, dst_ptr_loc,
src_ofs_loc, dst_ofs_loc, length_loc]
@@ -789,13 +789,15 @@
prepare_call_f = _prepare_call
prepare_call_n = _prepare_call
- def _spill_before_call(self, save_all_regs=False):
- # spill variables that need to be saved around calls
+ def _spill_before_call(self, gc_level):
+ # spill variables that need to be saved around calls:
+ # gc_level == 0: callee cannot invoke the GC
+ # gc_level == 1: can invoke GC, save all regs that contain pointers
+ # gc_level == 2: can force, save all regs
+ save_all_regs = gc_level == 2
self.fprm.before_call(save_all_regs=save_all_regs)
- if not save_all_regs:
- gcrootmap = self.assembler.cpu.gc_ll_descr.gcrootmap
- if gcrootmap and gcrootmap.is_shadow_stack:
- save_all_regs = 2
+ if gc_level == 1 and self.cpu.gc_ll_descr.gcrootmap:
+ save_all_regs = 2
self.rm.before_call(save_all_regs=save_all_regs)
def _prepare_call(self, op, save_all_regs=False):
@@ -803,7 +805,18 @@
args.append(None)
for i in range(op.numargs()):
args.append(self.loc(op.getarg(i)))
- self._spill_before_call(save_all_regs)
+
+ calldescr = op.getdescr()
+ assert isinstance(calldescr, CallDescr)
+ effectinfo = calldescr.get_extra_info()
+ if save_all_regs:
+ gc_level = 2
+ elif effectinfo is None or effectinfo.check_can_collect():
+ gc_level = 1
+ else:
+ gc_level = 0
+ self._spill_before_call(gc_level=gc_level)
+
if op.type != VOID:
resloc = self.after_call(op)
args[0] = resloc
@@ -932,7 +945,7 @@
def _prepare_call_assembler(self, op):
locs = self.locs_for_call_assembler(op)
- self._spill_before_call(save_all_regs=True)
+ self._spill_before_call(gc_level=2)
if op.type != VOID:
resloc = self.after_call(op)
else:
diff --git a/rpython/jit/backend/x86/regalloc.py
b/rpython/jit/backend/x86/regalloc.py
--- a/rpython/jit/backend/x86/regalloc.py
+++ b/rpython/jit/backend/x86/regalloc.py
@@ -795,22 +795,22 @@
else:
self._consider_call(op)
- def _call(self, op, arglocs, force_store=[], guard_not_forced=False):
+ def _call(self, op, arglocs, gc_level):
# we need to save registers on the stack:
#
# - at least the non-callee-saved registers
#
- # - we assume that any call can collect, and we
- # save also the callee-saved registers that contain GC pointers
+ # - if gc_level > 0, we save also the callee-saved registers that
+ # contain GC pointers
#
- # - for CALL_MAY_FORCE or CALL_ASSEMBLER, we have to save all regs
- # anyway, in case we need to do cpu.force(). The issue is that
- # grab_frame_values() would not be able to locate values in
- # callee-saved registers.
+ # - gc_level == 2 for CALL_MAY_FORCE or CALL_ASSEMBLER. We
+ # have to save all regs anyway, in case we need to do
+ # cpu.force(). The issue is that grab_frame_values() would
+ # not be able to locate values in callee-saved registers.
#
- save_all_regs = guard_not_forced
- self.xrm.before_call(force_store, save_all_regs=save_all_regs)
- if not save_all_regs:
+ save_all_regs = gc_level == 2
+ self.xrm.before_call(save_all_regs=save_all_regs)
+ if gc_level == 1:
gcrootmap = self.assembler.cpu.gc_ll_descr.gcrootmap
# we save all the registers for shadowstack and asmgcc for now
# --- for asmgcc too: we can't say "register x is a gc ref"
@@ -818,7 +818,7 @@
# more for now.
if gcrootmap: # and gcrootmap.is_shadow_stack:
save_all_regs = 2
- self.rm.before_call(force_store, save_all_regs=save_all_regs)
+ self.rm.before_call(save_all_regs=save_all_regs)
if op.type != 'v':
if op.type == FLOAT:
resloc = self.xrm.after_call(op)
@@ -838,9 +838,18 @@
sign_loc = imm1
else:
sign_loc = imm0
+ #
+ effectinfo = calldescr.get_extra_info()
+ if guard_not_forced:
+ gc_level = 2
+ elif effectinfo is None or effectinfo.check_can_collect():
+ gc_level = 1
+ else:
+ gc_level = 0
+ #
self._call(op, [imm(size), sign_loc] +
[self.loc(op.getarg(i)) for i in range(op.numargs())],
- guard_not_forced=guard_not_forced)
+ gc_level=gc_level)
def _consider_real_call(self, op):
effectinfo = op.getdescr().get_extra_info()
@@ -899,7 +908,7 @@
def _consider_call_assembler(self, op):
locs = self.locs_for_call_assembler(op)
- self._call(op, locs, guard_not_forced=True)
+ self._call(op, locs, gc_level=2)
consider_call_assembler_i = _consider_call_assembler
consider_call_assembler_r = _consider_call_assembler
consider_call_assembler_f = _consider_call_assembler
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit