[pypy-svn] r65264 - in pypy/branch/pyjitpl5/pypy/jit/backend/x86: . test

arigo at codespeak.net arigo at codespeak.net
Thu May 14 19:03:27 CEST 2009


Author: arigo
Date: Thu May 14 19:03:25 2009
New Revision: 65264

Modified:
   pypy/branch/pyjitpl5/pypy/jit/backend/x86/assembler.py
   pypy/branch/pyjitpl5/pypy/jit/backend/x86/gc.py
   pypy/branch/pyjitpl5/pypy/jit/backend/x86/regalloc.py
   pypy/branch/pyjitpl5/pypy/jit/backend/x86/test/test_zrpy_gc.py
Log:
Yay!  GC roots finding seems to work.


Modified: pypy/branch/pyjitpl5/pypy/jit/backend/x86/assembler.py
==============================================================================
--- pypy/branch/pyjitpl5/pypy/jit/backend/x86/assembler.py	(original)
+++ pypy/branch/pyjitpl5/pypy/jit/backend/x86/assembler.py	Thu May 14 19:03:25 2009
@@ -155,6 +155,9 @@
                 self.single_gcref_descr = ConstDescr3(0, WORD, True)
             else:
                 self.gcrefs = None
+            self.gcrootmap = self.cpu.gc_ll_descr.gcrootmap
+            if self.gcrootmap:
+                self.gcrootmap.initialize()
 
     def eventually_log_operations(self, inputargs, operations, memo=None,
                                   myid=0):
@@ -240,8 +243,7 @@
         self.eventually_log_operations(tree.inputargs, tree.operations, None,
                                        compute_unique_id(tree))
         regalloc = RegAlloc(self, tree, self.cpu.translate_support_code)
-        if not we_are_translated():
-            self._regalloc = regalloc # for debugging
+        self._regalloc = regalloc
         regalloc.walk_operations(tree)
         self.sanitize_tree(tree.operations)
         self.mc.done()
@@ -257,6 +259,8 @@
                 tl = op.jump_target
                 self.patch_jump(pos, tl._x86_compiled, tl.arglocs, tl.arglocs,
                                 tree._x86_stack_depth, tl._x86_stack_depth)
+        if we_are_translated():
+            self._regalloc = None   # else keep it around for debugging
 
     def sanitize_tree(self, operations):
         """ Cleans up all attributes attached by regalloc and backend
@@ -270,6 +274,9 @@
     def assemble_bootstrap_code(self, jumpaddr, arglocs, framesize):
         self.make_sure_mc_exists()
         addr = self.mc.tell()
+        if self.gcrootmap:
+            self.mc.PUSH(ebp)
+            self.mc.MOV(ebp, esp)
         self.mc.SUB(esp, imm(framesize * WORD))
         # This uses XCHG to put zeroes in fail_boxes after reading them,
         # just in case they are pointers.
@@ -390,6 +397,7 @@
             assert not isinstance(arg, MODRM)
             self.mc.PUSH(arg)
         self.mc.CALL(rel32(addr))
+        self.mark_gc_roots(len(args))
         self.mc.ADD(esp, imm(len(args) * WORD))
         assert res is eax
 
@@ -814,6 +822,8 @@
         self.mc.ADD(esp, imm32(0))
         guard_index = self.cpu.make_guard_index(op)
         self.mc.MOV(eax, imm(guard_index))
+        if self.gcrootmap:
+            self.mc.POP(ebp)
         self.mc.RET()
 
     def generate_ovf_set(self):
@@ -860,6 +870,7 @@
             if isinstance(x, MODRM):
                 x = stack_pos(x.position + extra_on_stack)
         self.mc.CALL(x)
+        self.mark_gc_roots(extra_on_stack)
         self.mc.ADD(esp, imm(WORD * extra_on_stack))
         if size == 1:
             self.mc.AND(eax, imm(0xff))
@@ -889,6 +900,18 @@
     #    self.gen_call(op, arglocs, resloc)
     #    self.mc.MOVZX(eax, eax)
 
+    def mark_gc_roots(self, extra_on_stack):
+        if self.gcrootmap:
+            gclocs = []
+            regalloc = self._regalloc
+            for v, val in regalloc.stack_bindings.items():
+                if (isinstance(v, BoxPtr) and
+                    regalloc.longevity[v][1] > regalloc.position):
+                    gclocs.append(val)
+            shape = self.gcrootmap.encode_callshape(gclocs)
+            self.gcrootmap.put(rffi.cast(llmemory.Address, self.mc.tell()),
+                               shape)
+
 genop_discard_list = [Assembler386.not_implemented_op_discard] * rop._LAST
 genop_list = [Assembler386.not_implemented_op] * rop._LAST
 genop_guard_list = [Assembler386.not_implemented_op_guard] * rop._LAST

Modified: pypy/branch/pyjitpl5/pypy/jit/backend/x86/gc.py
==============================================================================
--- pypy/branch/pyjitpl5/pypy/jit/backend/x86/gc.py	(original)
+++ pypy/branch/pyjitpl5/pypy/jit/backend/x86/gc.py	Thu May 14 19:03:25 2009
@@ -19,6 +19,7 @@
 
 class GcLLDescr_boehm(GcLLDescription):
     moving_gc = False
+    gcrootmap = None
 
     def __init__(self, gcdescr, mixlevelann):
         # grab a pointer to the Boehm 'malloc' function
@@ -135,16 +136,22 @@
     CALLSHAPE_ARRAY = rffi.CArray(rffi.UCHAR)
 
     def __init__(self):
-        self._gcmap = lltype.malloc(self.GCMAP_ARRAY, 0, flavor='raw')
+        self._gcmap = lltype.nullptr(self.GCMAP_ARRAY)
         self._gcmap_curlength = 0
         self._gcmap_maxlength = 0
 
+    def initialize(self):
+        # hack hack hack.  Remove these lines and see MissingRTypeAttribute
+        # when the rtyper tries to annotate these methods only when GC-ing...
+        self.gcmapstart()
+        self.gcmapend()
+
     def gcmapstart(self):
         return llmemory.cast_ptr_to_adr(self._gcmap)
 
     def gcmapend(self):
         start = self.gcmapstart()
-        return start + llmemory.sizeof(lltype.Signed) * self._gcmap_curlength
+        return start + llmemory.sizeof(llmemory.Address)*self._gcmap_curlength
 
     def put(self, retaddr, callshapeaddr):
         """'retaddr' is the address just after the CALL.
@@ -157,31 +164,31 @@
         self._gcmap_curlength = index + 2
 
     def _enlarge_gcmap(self):
-        newlength = 128 + self._gcmap_maxlength // 4
+        newlength = 128 + self._gcmap_maxlength * 5 // 4
         newgcmap = lltype.malloc(self.GCMAP_ARRAY, newlength, flavor='raw')
         oldgcmap = self._gcmap
         for i in range(self._gcmap_curlength):
             newgcmap[i] = oldgcmap[i]
         self._gcmap = newgcmap
         self._gcmap_maxlength = newlength
-        lltype.free(oldgcmap, flavor='raw')
+        if oldgcmap:
+            lltype.free(oldgcmap, flavor='raw')
 
-    def encode_callshape(self, gclocs, framesize):
+    def encode_callshape(self, gclocs):
         """Encode a callshape from the list of locations containing GC
-        pointers and from the frame size of the current (caller) frame.
-        The framesize gives the offset from %esp to the return address
-        of the current frame."""
-        shape = self._get_callshape(gclocs, framesize)
+        pointers."""
+        shape = self._get_callshape(gclocs)
         return self._compress_callshape(shape)
 
-    def _get_callshape(self, gclocs, framesize):
-        # the four registers %ebx, %esi, %edi, %ebp are not used at all
+    def _get_callshape(self, gclocs):
+        # The return address is always found at 4(%ebp); and
+        # the three registers %ebx, %esi, %edi are not used at all
         # so far, so their value always comes from the caller.
-        shape = [self.LOC_ESP_BASED | framesize,
+        shape = [self.LOC_EBP_BASED | 4,
                  self.LOC_REG | 0,
                  self.LOC_REG | 4,
                  self.LOC_REG | 8,
-                 self.LOC_REG | 12,
+                 self.LOC_EBP_BASED | 0,
                  0]
         for loc in gclocs:
             assert isinstance(loc, MODRM)
@@ -225,15 +232,16 @@
         except KeyError:
             raise NotImplementedError("--gcrootfinder=%s not implemented"
                                       " with the JIT" % (name,))
-        self.gcrootmap = cls()
+        gcrootmap = cls()
+        self.gcrootmap = gcrootmap
 
         # make a TransformerLayoutBuilder and save it on the translator
         # where it can be fished and reused by the FrameworkGCTransformer
         self.layoutbuilder = framework.TransformerLayoutBuilder()
         self.translator._jit2gc = {
             'layoutbuilder': self.layoutbuilder,
-            'gcmapstart': self.gcrootmap.gcmapstart,
-            'gcmapend': self.gcrootmap.gcmapend,
+            'gcmapstart': lambda: gcrootmap.gcmapstart(),
+            'gcmapend': lambda: gcrootmap.gcmapend(),
             }
         GCClass, _ = choose_gc_from_config(gcdescr.config)
         self.moving_gc = GCClass.moving_gc

Modified: pypy/branch/pyjitpl5/pypy/jit/backend/x86/regalloc.py
==============================================================================
--- pypy/branch/pyjitpl5/pypy/jit/backend/x86/regalloc.py	(original)
+++ pypy/branch/pyjitpl5/pypy/jit/backend/x86/regalloc.py	Thu May 14 19:03:25 2009
@@ -951,7 +951,8 @@
             loc = self.make_sure_var_in_reg(v, [v])
             self.sync_var(v)
             if size != 0:
-                # XXX lshift?
+                # XXX lshift? no, better yet, use 'LEA' somehow (it can be
+                # combined with the following INT_ADD)
                 self.Perform(ResOperation(rop.INT_MUL, [], None),
                              [loc, imm(1 << size)], loc)
             self.Perform(ResOperation(rop.INT_ADD, [], None),

Modified: pypy/branch/pyjitpl5/pypy/jit/backend/x86/test/test_zrpy_gc.py
==============================================================================
--- pypy/branch/pyjitpl5/pypy/jit/backend/x86/test/test_zrpy_gc.py	(original)
+++ pypy/branch/pyjitpl5/pypy/jit/backend/x86/test/test_zrpy_gc.py	Thu May 14 19:03:25 2009
@@ -7,7 +7,7 @@
 import weakref, random
 import py
 from pypy.rlib import rgc
-from pypy.rpython.lltypesystem import lltype, llmemory
+from pypy.rpython.lltypesystem import lltype, llmemory, rffi
 from pypy.rpython.lltypesystem.lloperation import llop
 from pypy.rlib.jit import JitDriver
 from pypy.jit.backend.x86.runner import CPU386
@@ -112,17 +112,34 @@
 
 def test_GcRootMap_asmgcc():
     gcrootmap = GcRootMap_asmgcc()
-    shape = gcrootmap._get_callshape([stack_pos(1), stack_pos(55)], 236)
-    assert shape == [236|3, 1, 5, 9, 13, 0, 4|3, 220|3]
+    shape = gcrootmap._get_callshape([stack_pos(1), stack_pos(55)])
+    assert shape == [6, 1, 5, 9, 2, 0, 4|3, 220|3]
     #
-    addr = gcrootmap.encode_callshape([stack_pos(1), stack_pos(55)], 236)
+    shapeaddr = gcrootmap.encode_callshape([stack_pos(1), stack_pos(55)])
     PCALLSHAPE = lltype.Ptr(GcRootMap_asmgcc.CALLSHAPE_ARRAY)
-    p = llmemory.cast_adr_to_ptr(addr, PCALLSHAPE)
-    for i, expected in enumerate([131, 62, 14, 0, 26, 18, 10, 2, 131, 94]):
+    p = llmemory.cast_adr_to_ptr(shapeaddr, PCALLSHAPE)
+    for i, expected in enumerate([131, 62, 14, 0, 4, 18, 10, 2, 12]):
         assert p[i] == expected
+    #
+    retaddr = rffi.cast(llmemory.Address, 1234567890)
+    gcrootmap.put(retaddr, shapeaddr)
+    assert gcrootmap._gcmap[0] == retaddr
+    assert gcrootmap._gcmap[1] == shapeaddr
+    assert gcrootmap.gcmapstart().address[0] == retaddr
+    #
+    # the same as before, but enough times to trigger a few resizes
+    expected_shapeaddr = {}
+    for i in range(1, 600):
+        shapeaddr = gcrootmap.encode_callshape([stack_pos(i)])
+        expected_shapeaddr[i] = shapeaddr
+        retaddr = rffi.cast(llmemory.Address, 123456789 + i)
+        gcrootmap.put(retaddr, shapeaddr)
+    for i in range(1, 600):
+        expected_retaddr = rffi.cast(llmemory.Address, 123456789 + i)
+        assert gcrootmap._gcmap[i*2+0] == expected_retaddr
+        assert gcrootmap._gcmap[i*2+1] == expected_shapeaddr[i]
 
 def test_compile_hybrid_2():
-    py.test.skip("in-progress")
     # a moving GC.  Supports malloc_varsize_nonmovable.  More complex test,
     # requires root stack enumeration but not write_barriers.
     myjitdriver = JitDriver(greens = [], reds = ['n', 'x'])



More information about the Pypy-commit mailing list