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

Reply via email to