Author: Maciej Fijalkowski <[email protected]>
Branch: jitframe-on-heap
Changeset: r60134:68788e589b96
Date: 2013-01-17 17:48 +0200
http://bitbucket.org/pypy/pypy/changeset/68788e589b96/
Log: fight fight fight. freelists on the frame manager, so we get more
compact frames (and we can respect GC-vs-non-GC)
diff --git a/pypy/jit/backend/llsupport/jitframe.py
b/pypy/jit/backend/llsupport/jitframe.py
--- a/pypy/jit/backend/llsupport/jitframe.py
+++ b/pypy/jit/backend/llsupport/jitframe.py
@@ -4,18 +4,37 @@
# compiled loop token (in fact we could use this as a compiled loop token
# XXX do this
+GCMAP = lltype.GcArray(lltype.Signed)
+NULLGCMAP = lltype.nullptr(GCMAP)
+# XXX make it SHORT not Signed
+
JITFRAMEINFO = lltype.GcStruct(
'JITFRAMEINFO',
# the depth of frame
('jfi_frame_depth', lltype.Signed),
# gcindexlist is a list of indexes of GC ptrs
# in the actual array jf_frame of JITFRAME
- ('jfi_gcindexlist', lltype.Ptr(lltype.GcArray(lltype.Signed))),
- )
+ ('jfi_gcmap', lltype.Ptr(GCMAP)),
+)
+
+NULLFRAMEINFO = lltype.nullptr(JITFRAMEINFO)
# the JITFRAME that's stored on the heap. See backend/<backend>/arch.py for
# detailed explanation how it is on your architecture
+def jitframe_allocate(frame_info):
+ frame = lltype.malloc(JITFRAME, frame_info.jfi_frame_depth, zero=True)
+ frame.jf_gcmap = frame_info.jfi_gcmap
+ frame.jf_frame_info = frame_info
+ return frame
+
+def jitframe_copy(frame):
+ frame_info = frame.jf_frame_info
+ new_frame = lltype.malloc(JITFRAME, frame_info.jfi_frame_depth, zero=True)
+ new_frame.jf_gcmap = frame_info.jfi_gcmap
+ new_frame.jf_frame_info = frame_info
+ return new_frame
+
JITFRAME = lltype.GcStruct(
'JITFRAME',
('jf_frame_info', lltype.Ptr(JITFRAMEINFO)),
@@ -29,6 +48,8 @@
# a bitmask of where are GCREFS in the top of the frame (saved registers)
# used for calls and failures
('jf_gcpattern', lltype.Signed),
+ # a copy of gcmap from frameinfo
+ ('jf_gcmap', lltype.Ptr(GCMAP)),
# For the front-end: a GCREF for the savedata
('jf_savedata', llmemory.GCREF),
# For GUARD_(NO)_EXCEPTION and GUARD_NOT_FORCED: the exception we
@@ -37,8 +58,13 @@
# exception is not stored there, but is simply kept as a variable there)
('jf_guard_exc', llmemory.GCREF),
# the actual frame
- ('jf_frame', lltype.Array(lltype.Signed))
- # it should be: , hints={'nolength': True})), but ll2ctypes is complaining
+ ('jf_frame', lltype.Array(lltype.Signed)),
+ # note that we keep length field, because it's crucial to have the data
+ # about GCrefs here and not in frame info which might change
+ adtmeths = {
+ 'allocate': jitframe_allocate,
+ 'copy': jitframe_copy,
+ }
)
JITFRAMEPTR = lltype.Ptr(JITFRAME)
diff --git a/pypy/jit/backend/llsupport/llmodel.py
b/pypy/jit/backend/llsupport/llmodel.py
--- a/pypy/jit/backend/llsupport/llmodel.py
+++ b/pypy/jit/backend/llsupport/llmodel.py
@@ -57,10 +57,8 @@
def realloc_frame(frame):
frame = lltype.cast_opaque_ptr(jitframe.JITFRAMEPTR, frame)
- frame_info = frame.jf_frame_info
- new_frame = lltype.malloc(jitframe.JITFRAME,
- frame_info.jfi_frame_depth)
- new_frame.jf_frame_info = frame_info
+ new_frame = frame.copy()
+ # XXX now we know, rewrite this
# we need to do this, because we're not sure what things
# are GC pointers and which ones are not
llop.gc_writebarrier_before_copy(lltype.Bool, frame, new_frame,
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
@@ -23,8 +23,9 @@
# assume the list is sorted
if lst is not None:
node = None
- for item in range(len(lst) - 1, -1, -1):
- node = Node(fm.get_loc_index(item), node)
+ for i in range(len(lst) - 1, -1, -1):
+ item = lst[i]
+ node = Node(item, node)
self.master_node = node
else:
self.master_node = None
@@ -111,6 +112,37 @@
node = node.next
return 'LinkedList(%s)' % '->'.join(l)
+def frame_manager_from_gcmap(FmClass, gcmap, depth, frame_bindings):
+ if not gcmap:
+ return FmClass()
+ rev_bindings = [False] * depth
+ for arg, loc in frame_bindings.iteritems():
+ size = FmClass.frame_size(arg.type)
+ if size == 2:
+ rev_bindings[FmClass.get_loc_index(loc) + 1] = True
+ assert size == 1
+ rev_bindings[FmClass.get_loc_index(loc)] = True
+ if not gcmap:
+ return FmClass()
+ gcrefs = []
+ others = []
+ c = 0
+ for i in range(len(gcmap)):
+ item = gcmap[i]
+ while c < item:
+ if not rev_bindings[c]:
+ others.append(c)
+ c += 1
+ if not rev_bindings[item]:
+ gcrefs.append(item)
+ c += 1
+ for i in range(c, depth):
+ others.append(i)
+ fm = FmClass(depth, gcrefs, others)
+ for arg, loc in frame_bindings.iteritems():
+ fm.bindings[arg] = loc
+ return fm
+
class FrameManager(object):
""" Manage frame positions
@@ -605,6 +637,7 @@
""" Platform specific - Allocates a temporary register """
raise NotImplementedError("Abstract")
+
def compute_vars_longevity(inputargs, operations):
# compute a dictionary that maps variables to index in
# operations that is a "last-time-seen"
diff --git a/pypy/jit/backend/llsupport/test/test_regalloc.py
b/pypy/jit/backend/llsupport/test/test_regalloc.py
--- a/pypy/jit/backend/llsupport/test/test_regalloc.py
+++ b/pypy/jit/backend/llsupport/test/test_regalloc.py
@@ -1,10 +1,9 @@
import py
from pypy.jit.metainterp.history import BoxInt, ConstInt, BoxFloat, INT,
FLOAT,\
BoxPtr
-from pypy.jit.backend.llsupport.regalloc import FrameManager, LinkedList
+from pypy.jit.backend.llsupport.regalloc import FrameManager, LinkedList,\
+ frame_manager_from_gcmap
from pypy.jit.backend.llsupport.regalloc import RegisterManager as BaseRegMan
-from pypy.jit.tool.oparser import parse
-from pypy.jit.backend.detect_cpu import getcpuclass
def newboxes(*values):
return [BoxInt(v) for v in values]
@@ -591,3 +590,25 @@
for box in fm.bindings.keys():
fm.mark_as_free(box)
assert fm.get_gc_map() == [7, 8]
+
+ def test_fm_from_gcmap(self):
+ class Loc(object):
+ def __init__(self, l):
+ self.l = l
+
+ class Fm(FrameManager):
+ @staticmethod
+ def get_loc_index(l):
+ return l.l
+
+ b0 = BoxInt()
+ b1 = BoxInt()
+ l0 = Loc(5)
+ l1 = Loc(2)
+ bindings = {b0: l0, b1: l1}
+ fm = frame_manager_from_gcmap(Fm, [1, 5, 6, 8], 13,
+ bindings)
+ assert repr(fm.freelist_gcrefs) == "LinkedList(1->6->8)"
+ assert repr(fm.freelist_others) ==
"LinkedList(0->3->4->7->9->10->11->12)"
+ assert fm.current_frame_depth == 13
+ assert fm.bindings == bindings
diff --git a/pypy/jit/backend/test/runner_test.py
b/pypy/jit/backend/test/runner_test.py
--- a/pypy/jit/backend/test/runner_test.py
+++ b/pypy/jit/backend/test/runner_test.py
@@ -430,7 +430,7 @@
def test_int_operations(self):
from pypy.jit.metainterp.test.test_executor import get_int_tests
for opnum, boxargs, retvalue in get_int_tests():
- print "X"
+ print opnum
res = self.execute_operation(opnum, boxargs, 'int')
assert res.value == retvalue
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
@@ -534,8 +534,9 @@
looptoken, clt.allgcrefs)
looppos = self.mc.get_relative_pos()
looptoken._x86_loop_code = looppos
- frame_depth = self._assemble(regalloc, operations)
+ frame_depth = self._assemble(regalloc, inputargs, operations)
clt.frame_info.jfi_frame_depth = frame_depth + JITFRAME_FIXED_SIZE
+ self._update_gcmap(clt.frame_info, regalloc)
#
size_excluding_failure_stuff = self.mc.get_relative_pos()
self.write_pending_failure_recoveries()
@@ -586,9 +587,10 @@
startpos = self.mc.get_relative_pos()
operations = regalloc.prepare_bridge(inputargs, arglocs,
operations,
- self.current_clt.allgcrefs)
+ self.current_clt.allgcrefs,
+ self.current_clt.frame_info)
stack_check_patch_ofs = self._check_frame_depth()
- frame_depth = self._assemble(regalloc, operations)
+ frame_depth = self._assemble(regalloc, inputargs, operations)
codeendpos = self.mc.get_relative_pos()
self.write_pending_failure_recoveries()
fullsize = self.mc.get_relative_pos()
@@ -610,6 +612,7 @@
self._patch_stackadjust(stack_check_patch_ofs + rawstart, frame_depth)
self.fixup_target_tokens(rawstart)
self.current_clt.frame_info.jfi_frame_depth = frame_depth
+ self._update_gcmap(self.current_clt.frame_info, regalloc)
self.teardown()
# oprofile support
if self.cpu.profile_agent is not None:
@@ -688,6 +691,13 @@
mc = codebuf.MachineCodeBlockWrapper()
mc.writeimm32(allocated_depth)
mc.copy_to_raw_memory(adr)
+
+ def _update_gcmap(self, frame_info, regalloc):
+ gcmap = regalloc.get_gc_map()
+ frame_info.jfi_gcmap = lltype.malloc(jitframe.GCMAP,
+ len(gcmap))
+ for i in range(len(gcmap)):
+ frame_info.jfi_gcmap[i] = gcmap[i]
def get_asmmemmgr_blocks(self, looptoken):
clt = looptoken.compiled_loop_token
@@ -777,16 +787,17 @@
operations = newoperations
return operations
- def _assemble(self, regalloc, operations):
+ def _assemble(self, regalloc, inputargs, operations):
self._regalloc = regalloc
regalloc.compute_hint_frame_locations(operations)
- regalloc.walk_operations(operations)
+ regalloc.walk_operations(inputargs, operations)
if we_are_translated() or self.cpu.dont_keepalive_stuff:
self._regalloc = None # else keep it around for debugging
frame_depth = regalloc.get_final_frame_depth()
jump_target_descr = regalloc.jump_target_descr
if jump_target_descr is not None:
- target_frame_depth =
jump_target_descr._x86_clt.frame_info.jfi_frame_depth
+ tgt_depth = jump_target_descr._x86_clt.frame_info.jfi_frame_depth
+ target_frame_depth = tgt_depth - JITFRAME_FIXED_SIZE
frame_depth = max(frame_depth, target_frame_depth)
return frame_depth
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
@@ -17,13 +17,15 @@
from pypy.jit.codewriter import longlong
from pypy.jit.codewriter.effectinfo import EffectInfo
from pypy.jit.metainterp.resoperation import rop
+from pypy.jit.backend.llsupport.jitframe import NULLGCMAP
from pypy.jit.backend.llsupport.descr import ArrayDescr
from pypy.jit.backend.llsupport.descr import CallDescr
from pypy.jit.backend.llsupport.descr import unpack_arraydescr
from pypy.jit.backend.llsupport.descr import unpack_fielddescr
from pypy.jit.backend.llsupport.descr import unpack_interiorfielddescr
from pypy.jit.backend.llsupport.regalloc import FrameManager, RegisterManager,\
- TempBox, compute_vars_longevity, is_comparison_or_ovf_op
+ TempBox, compute_vars_longevity, is_comparison_or_ovf_op,\
+ frame_manager_from_gcmap
from pypy.jit.backend.x86.arch import WORD, JITFRAME_FIXED_SIZE
from pypy.jit.backend.x86.arch import IS_X86_32, IS_X86_64
from pypy.jit.backend.x86 import rx86
@@ -171,9 +173,11 @@
self.close_stack_struct = 0
self.final_jump_op = None
- def _prepare(self, inputargs, operations, allgcrefs):
- self.fm = X86FrameManager()
- self.min_frame_depth = 0
+ def _prepare(self, inputargs, operations, allgcrefs, gcmap=NULLGCMAP,
+ parent_frame_depth=0, frame_bindings=None):
+ self.fm = frame_manager_from_gcmap(X86FrameManager, gcmap,
+ parent_frame_depth,
+ frame_bindings)
cpu = self.assembler.cpu
operations = cpu.gc_ll_descr.rewrite_assembler(cpu, operations,
allgcrefs)
@@ -201,9 +205,16 @@
self.min_bytes_before_label = 13
return operations
- def prepare_bridge(self, inputargs, arglocs, operations, allgcrefs):
- operations = self._prepare(inputargs, operations,
- allgcrefs)
+ def get_gc_map(self):
+ return self.fm.get_gc_map()
+
+ def prepare_bridge(self, inputargs, arglocs, operations, allgcrefs,
+ frame_info):
+ frame_bindings = self._frame_bindings(arglocs, inputargs)
+ operations = self._prepare(inputargs, operations, allgcrefs,
+ frame_info.jfi_gcmap,
+ frame_info.jfi_frame_depth,
+ frame_bindings)
self._update_bindings(arglocs, inputargs)
self.min_bytes_before_label = 0
return operations
@@ -213,70 +224,12 @@
at_least_position)
def get_final_frame_depth(self):
- min_frame_depth = self.fm.get_frame_depth()
- if min_frame_depth > self.min_frame_depth:
- self.min_frame_depth = min_frame_depth
- return self.min_frame_depth
+ return self.fm.get_frame_depth()
def _set_initial_bindings(self, inputargs):
for box in inputargs:
assert isinstance(box, Box)
self.fm.get_new_loc(box)
- #loc = self.fm.frame_pos(cur_frame_pos, box.type)
- #self.fm.set_binding(box, loc)
-
- # if IS_X86_64:
- # inputargs = self._set_initial_bindings_regs_64(inputargs)
- # # ...
- # # stack layout: arg2
- # # arg1
- # # arg0
- # # return address
- # # saved ebp <-- ebp points here
- # # ...
- # XXX # adjust the address to count for the fact that we're passing
- # # jitframe as a first arg
- # cur_frame_pos = - 1 - FRAME_FIXED_SIZE
- # assert get_ebp_ofs(cur_frame_pos-1) == 2*WORD
- # assert get_ebp_ofs(cur_frame_pos-2) == 3*WORD
- # #
- # for box in inputargs:
- # assert isinstance(box, Box)
- # #
- # if IS_X86_32 and box.type == FLOAT:
- # cur_frame_pos -= 2
- # else:
- # cur_frame_pos -= 1
- # loc = self.fm.frame_pos(cur_frame_pos, box.type)
- # self.fm.set_binding(box, loc)
-
- # def _set_initial_bindings_regs_64(self, inputargs):
- # # In reverse order for use with pop()
- # unused_gpr = [r9, r8, ecx, edx, esi] # jitframe comes in edi. don't
use
- # # it for parameter parsing
- # unused_xmm = [xmm7, xmm6, xmm5, xmm4, xmm3, xmm2, xmm1, xmm0]
- # #
- # pass_on_stack = []
- # #
- # for box in inputargs:
- # assert isinstance(box, Box)
- # #
- # if box.type == FLOAT:
- # if len(unused_xmm) > 0:
- # ask = unused_xmm.pop()
- # got = self.xrm.try_allocate_reg(box, selected_reg=ask)
- # assert ask == got
- # else:
- # pass_on_stack.append(box)
- # else:
- # if len(unused_gpr) > 0:
- # ask = unused_gpr.pop()
- # got = self.rm.try_allocate_reg(box, selected_reg=ask)
- # assert ask == got
- # else:
- # pass_on_stack.append(box)
- # #
- # return pass_on_stack
def possibly_free_var(self, var):
if var.type == FLOAT:
@@ -329,9 +282,20 @@
else:
return self.xrm.make_sure_var_in_reg(var, forbidden_vars)
+ def _frame_bindings(self, locs, inputargs):
+ bindings = {}
+ i = 0
+ for loc in locs:
+ if loc is None:
+ continue
+ arg = inputargs[i]
+ i += 1
+ if not isinstance(loc, RegLoc):
+ bindings[arg] = loc
+ return bindings
+
def _update_bindings(self, locs, inputargs):
# XXX this should probably go to llsupport/regalloc.py
- xxx
used = {}
i = 0
for loc in locs:
@@ -339,21 +303,16 @@
continue
arg = inputargs[i]
i += 1
- if arg.type == FLOAT:
- if isinstance(loc, RegLoc):
+ if isinstance(loc, RegLoc):
+ if arg.type == FLOAT:
self.xrm.reg_bindings[arg] = loc
used[loc] = None
else:
- self.fm.set_binding(arg, loc)
- else:
- if isinstance(loc, RegLoc):
if loc is ebp:
self.rm.bindings_to_frame_reg[arg] = None
else:
self.rm.reg_bindings[arg] = loc
used[loc] = None
- else:
- self.fm.set_binding(arg, loc)
self.rm.free_regs = []
for reg in self.rm.all_regs:
if reg not in used:
@@ -362,8 +321,6 @@
for reg in self.xrm.all_regs:
if reg not in used:
self.xrm.free_regs.append(reg)
- # note: we need to make a copy of inputargs because possibly_free_vars
- # is also used on op args, which is a non-resizable list
self.possibly_free_vars(list(inputargs))
self.rm._check_invariants()
self.xrm._check_invariants()
@@ -437,7 +394,7 @@
return False
return True
- def walk_operations(self, operations):
+ def walk_operations(self, inputargs, operations):
i = 0
#self.operations = operations
while i < len(operations):
@@ -465,6 +422,8 @@
assert not self.xrm.reg_bindings
self.flush_loop()
self.assembler.mc.mark_op(None) # end of the loop
+ for arg in inputargs:
+ self.possibly_free_var(arg)
def flush_loop(self):
# rare case: if the loop is too short, or if we are just after
@@ -921,6 +880,7 @@
if oopspecindex == EffectInfo.OS_MATH_SQRT:
return self._consider_math_sqrt(op)
self._consider_call(op)
+ self.possibly_free_vars(op.getarglist())
def consider_call_may_force(self, op, guard_op):
assert guard_op is not None
@@ -943,6 +903,7 @@
xxx
self._call(op, [frame_loc, self.loc(op.getarg(0))],
guard_not_forced_op=guard_op)
+ self.possibly_free_var(op.getarg(0))
def consider_cond_call_gc_wb(self, op):
assert op.result is None
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
@@ -115,9 +115,7 @@
func = rffi.cast(FUNCPTR, addr)
#llop.debug_print(lltype.Void, ">>>> Entering", addr)
frame_info = clt.frame_info
- frame = lltype.malloc(jitframe.JITFRAME,
frame_info.jfi_frame_depth,
- zero=True)
- frame.jf_frame_info = frame_info
+ frame = jitframe.JITFRAME.allocate(frame_info)
ll_frame = lltype.cast_opaque_ptr(llmemory.GCREF, frame)
prev_interpreter = None # help flow space
if not self.translate_support_code:
_______________________________________________
pypy-commit mailing list
[email protected]
http://mail.python.org/mailman/listinfo/pypy-commit