[pypy-svn] r67731 - in pypy/trunk/pypy: jit/backend/llsupport jit/backend/x86 jit/backend/x86/test rpython rpython/lltypesystem rpython/lltypesystem/test rpython/memory/gc rpython/memory/gc/test rpython/memory/gctransform rpython/memory/test translator/c translator/c/test

pedronis at codespeak.net pedronis at codespeak.net
Thu Sep 17 13:54:43 CEST 2009


Author: pedronis
Date: Thu Sep 17 13:54:41 2009
New Revision: 67731

Modified:
   pypy/trunk/pypy/jit/backend/llsupport/llmodel.py
   pypy/trunk/pypy/jit/backend/x86/assembler.py
   pypy/trunk/pypy/jit/backend/x86/runner.py
   pypy/trunk/pypy/jit/backend/x86/test/test_zrpy_gc.py
   pypy/trunk/pypy/rpython/llinterp.py
   pypy/trunk/pypy/rpython/lltypesystem/lloperation.py
   pypy/trunk/pypy/rpython/lltypesystem/test/test_lloperation.py
   pypy/trunk/pypy/rpython/memory/gc/generation.py
   pypy/trunk/pypy/rpython/memory/gc/test/test_direct.py
   pypy/trunk/pypy/rpython/memory/gctransform/framework.py
   pypy/trunk/pypy/rpython/memory/test/test_transformed_gc.py
   pypy/trunk/pypy/translator/c/gc.py
   pypy/trunk/pypy/translator/c/test/test_boehm.py
Log:
(micke, pedronis, armin around a bit yesterday)

fix the issue that the failure code produced by the x86 backend was not marking the array it uses for failure pointer values which is old as pointing potentially to young objects.

this was solved by inventing a new gc operation gc_assume_young_pointers implemented by at least the generation and hybrid gc, and by having the x86 backend produce a call to something that will end up invoking the operation at the end of the failure write backs



Modified: pypy/trunk/pypy/jit/backend/llsupport/llmodel.py
==============================================================================
--- pypy/trunk/pypy/jit/backend/llsupport/llmodel.py	(original)
+++ pypy/trunk/pypy/jit/backend/llsupport/llmodel.py	Thu Sep 17 13:54:41 2009
@@ -44,6 +44,14 @@
         else:
             self._setup_exception_handling_untranslated()
         self.clear_exception()
+        self.setup()
+        if translate_support_code:
+            self._setup_on_leave_jitted_translated()
+        else:
+            self._setup_on_leave_jitted_untranslated()
+
+    def setup(self):
+        pass
 
     def set_class_sizes(self, class_sizes):
         self.class_sizes = class_sizes
@@ -131,10 +139,35 @@
         self.pos_exc_value = pos_exc_value
         self.save_exception = save_exception
 
-    _SAVE_EXCEPTION_FUNC = lltype.Ptr(lltype.FuncType([], lltype.Void))
+    def _setup_on_leave_jitted_untranslated(self):
+        # assume we don't need a backend leave in this case
+        self.on_leave_jitted_save_exc = self.save_exception
+        self.on_leave_jitted_noexc = lambda : None
+
+    def _setup_on_leave_jitted_translated(self):
+        on_leave_jitted_hook = self.get_on_leave_jitted_hook()
+        save_exception = self.save_exception
+
+        def on_leave_jitted_noexc():
+            on_leave_jitted_hook()
+
+        def on_leave_jitted_save_exc():
+            on_leave_jitted_hook()
+            save_exception()
 
-    def get_save_exception_int(self):
-        f = llhelper(self._SAVE_EXCEPTION_FUNC, self.save_exception)
+        self.on_leave_jitted_noexc = on_leave_jitted_noexc
+        self.on_leave_jitted_save_exc = on_leave_jitted_save_exc
+
+    def get_on_leave_jitted_hook(self):
+        return lambda : None
+
+    _ON_JIT_LEAVE_FUNC = lltype.Ptr(lltype.FuncType([], lltype.Void))
+
+    def get_on_leave_jitted_int(self, save_exception):
+        if save_exception:
+            f = llhelper(self._ON_JIT_LEAVE_FUNC, self.on_leave_jitted_save_exc)
+        else:
+            f = llhelper(self._ON_JIT_LEAVE_FUNC, self.on_leave_jitted_noexc)
         return rffi.cast(lltype.Signed, f)
 
     def get_exception(self):

Modified: pypy/trunk/pypy/jit/backend/x86/assembler.py
==============================================================================
--- pypy/trunk/pypy/jit/backend/x86/assembler.py	(original)
+++ pypy/trunk/pypy/jit/backend/x86/assembler.py	Thu Sep 17 13:54:41 2009
@@ -83,6 +83,11 @@
         self.fail_boxes_ptr = lltype.malloc(lltype.GcArray(llmemory.GCREF),
                                             MAX_FAIL_BOXES, zero=True)
 
+    def leave_jitted_hook(self):
+        fail_boxes_ptr = self.fail_boxes_ptr
+        llop.gc_assume_young_pointers(lltype.Void,
+                                      llmemory.cast_ptr_to_adr(fail_boxes_ptr))
+
     def make_sure_mc_exists(self):
         if self.mc is None:
             rffi.cast(lltype.Signed, self.fail_boxes_int)   # workaround
@@ -653,10 +658,15 @@
             mc.MOV(addr_add(imm(self.fail_box_int_addr),
                                  imm(len(locs) * WORD)),
                                  eax)
-        if exc:
-            # note that we don't have to save and restore eax, ecx and edx here
-            addr = self.cpu.get_save_exception_int()
-            mc.CALL(rel32(addr))
+
+        # we call a provided function that will
+        # - call our on_leave_jitted_hook which will mark
+        #   the fail_boxes_ptr array as pointing to young objects to
+        #   avoid unwarranted freeing
+        # - optionally save exception depending on the flag
+        addr = self.cpu.get_on_leave_jitted_int(save_exception=exc)
+        mc.CALL(rel32(addr))
+
         # don't break the following code sequence!
         mc = mc._mc
         mc.LEA(esp, addr_add(imm(0), ebp, (-RET_BP + 2) * WORD))

Modified: pypy/trunk/pypy/jit/backend/x86/runner.py
==============================================================================
--- pypy/trunk/pypy/jit/backend/x86/runner.py	(original)
+++ pypy/trunk/pypy/jit/backend/x86/runner.py	Thu Sep 17 13:54:41 2009
@@ -21,16 +21,17 @@
                  gcdescr=None):
         AbstractLLCPU.__init__(self, rtyper, stats, translate_support_code,
                                gcdescr)
-        TP = lltype.GcArray(llmemory.GCREF)
         self._bootstrap_cache = {}
         self._guard_list = []
-        self.setup()
         if rtyper is not None: # for tests
             self.lltype2vtable = rtyper.lltype_to_vtable_mapping()
 
     def setup(self):
         self.assembler = Assembler386(self, self.translate_support_code)
 
+    def get_on_leave_jitted_hook(self):
+        return self.assembler.leave_jitted_hook
+
     def setup_once(self):
         pass
 

Modified: pypy/trunk/pypy/jit/backend/x86/test/test_zrpy_gc.py
==============================================================================
--- pypy/trunk/pypy/jit/backend/x86/test/test_zrpy_gc.py	(original)
+++ pypy/trunk/pypy/jit/backend/x86/test/test_zrpy_gc.py	Thu Sep 17 13:54:41 2009
@@ -54,7 +54,7 @@
     return entrypoint
 
 
-def compile_and_run(f, gc, **kwds):
+def compile_and_run(f, gc, CPUClass=CPU386, **kwds):
     from pypy.annotation.listdef import s_list_of_strings
     from pypy.translator.translator import TranslationContext
     from pypy.jit.metainterp.warmspot import apply_jit
@@ -68,7 +68,7 @@
     t.buildannotator().build_types(f, [s_list_of_strings])
     t.buildrtyper().specialize()
     if kwds['jit']:
-        apply_jit(t, CPUClass=CPU386, optimizer=OPTIMIZER_SIMPLE)
+        apply_jit(t, CPUClass=CPUClass, optimizer=OPTIMIZER_SIMPLE)
     cbuilder = genc.CStandaloneBuilder(t, f, t.config)
     cbuilder.generate_source()
     cbuilder.compile()
@@ -326,6 +326,14 @@
         check(l[13].x == 122)
         check(l[14].x == 132)
         check(l[15].x == 142)
+
+    class CPU386CollectOnLeave(CPU386):
+
+        def execute_operations(self, loop, verbose=False):
+            op = CPU386.execute_operations(self, loop, verbose)
+            rgc.collect(0)
+            return op            
+        
     res = compile_and_run(get_test(main), "hybrid", gcrootfinder="asmgcc",
-                          jit=True)
+                          CPUClass=CPU386CollectOnLeave, jit=True)
     assert int(res) == 20

Modified: pypy/trunk/pypy/rpython/llinterp.py
==============================================================================
--- pypy/trunk/pypy/rpython/llinterp.py	(original)
+++ pypy/trunk/pypy/rpython/llinterp.py	Thu Sep 17 13:54:41 2009
@@ -821,6 +821,9 @@
     def op_gc__collect(self, *gen):
         self.heap.collect(*gen)
 
+    def op_gc_assume_young_pointers(self, addr):
+        raise NotImplementedError
+
     def op_gc_can_move(self, ptr):
         addr = llmemory.cast_ptr_to_adr(ptr)
         return self.heap.can_move(addr)

Modified: pypy/trunk/pypy/rpython/lltypesystem/lloperation.py
==============================================================================
--- pypy/trunk/pypy/rpython/lltypesystem/lloperation.py	(original)
+++ pypy/trunk/pypy/rpython/lltypesystem/lloperation.py	Thu Sep 17 13:54:41 2009
@@ -100,6 +100,28 @@
         return True
 llop = _LLOP()
 
+class VoidMarker(object):
+    # marker wrapper for void arguments to llops
+    def __init__(self, value):
+        self.value = value
+    def _freeze_(self):
+        return True
+
+def void(value):
+    return VoidMarker(value)
+
+class Entry(ExtRegistryEntry):
+    _about_ = void
+
+    def compute_result_annotation(self, s_value):
+        assert s_value.is_constant()
+        from pypy.annotation.bookkeeper import getbookkeeper
+        bk = getbookkeeper()
+        return bk.immutablevalue(VoidMarker(s_value.const))
+
+    def specialize_call(self, hop):
+        from pypy.rpython.lltypesystem import lltype
+        return hop.inputconst(lltype.Void, None)
 
 def enum_ops_without_sideeffects(raising_is_ok=False):
     """Enumerate operations that have no side-effects
@@ -127,8 +149,16 @@
         return lltype_to_annotation(RESULTTYPE.const)
 
     def specialize_call(self, hop):
+        from pypy.rpython.lltypesystem import lltype
         op = self.instance    # the LLOp object that was called
-        args_v = [hop.inputarg(r, i+1) for i, r in enumerate(hop.args_r[1:])]
+        args_v = []
+        for i, s_arg in enumerate(hop.args_s[1:]):
+            if s_arg.is_constant() and isinstance(s_arg.const, VoidMarker):
+                v_arg = hop.inputconst(lltype.Void, s_arg.const.value)
+            else:
+                v_arg = hop.inputarg(hop.args_r[i+1], i+1)
+            args_v.append(v_arg)
+
         if op.canraise:
             hop.exception_is_here()
         else:
@@ -408,6 +438,7 @@
     'gc_thread_prepare'   : LLOp(canraise=(MemoryError,)),
     'gc_thread_run'       : LLOp(),
     'gc_thread_die'       : LLOp(),
+    'gc_assume_young_pointers': LLOp(),
     # experimental operations in support of thread cloning, only
     # implemented by the Mark&Sweep GC
     'gc_x_swap_pool':       LLOp(canraise=(MemoryError,), canunwindgc=True),

Modified: pypy/trunk/pypy/rpython/lltypesystem/test/test_lloperation.py
==============================================================================
--- pypy/trunk/pypy/rpython/lltypesystem/test/test_lloperation.py	(original)
+++ pypy/trunk/pypy/rpython/lltypesystem/test/test_lloperation.py	Thu Sep 17 13:54:41 2009
@@ -1,5 +1,5 @@
 import py
-from pypy.rpython.lltypesystem.lloperation import LL_OPERATIONS, llop
+from pypy.rpython.lltypesystem.lloperation import LL_OPERATIONS, llop, void
 from pypy.rpython.lltypesystem import lltype, opimpl
 from pypy.rpython.ootypesystem import ootype, ooopimpl
 from pypy.rpython.llinterp import LLFrame
@@ -39,6 +39,19 @@
     res = interpret(llf, [5, 7], policy=LowLevelAnnotatorPolicy())
     assert res == 12
 
+def test_llop_with_voids_interp():
+    from pypy.rpython.annlowlevel import LowLevelAnnotatorPolicy
+    S = lltype.GcStruct('S', ('x', lltype.Signed), ('y', lltype.Signed))
+    name_y = void('y')
+    def llf():
+        s = lltype.malloc(S)
+        llop.bare_setfield(lltype.Void, s, void('x'), 3)
+        llop.bare_setfield(lltype.Void, s, name_y, 2)        
+        return s.x + s.y
+    res = interpret(llf, [], policy=LowLevelAnnotatorPolicy())
+    assert res == 5
+    
+
 # ___________________________________________________________________________
 # This tests that the LLInterpreter and the LL_OPERATIONS tables are in sync.
 

Modified: pypy/trunk/pypy/rpython/memory/gc/generation.py
==============================================================================
--- pypy/trunk/pypy/rpython/memory/gc/generation.py	(original)
+++ pypy/trunk/pypy/rpython/memory/gc/generation.py	Thu Sep 17 13:54:41 2009
@@ -448,6 +448,15 @@
         remember_young_pointer._dont_inline_ = True
         self.remember_young_pointer = remember_young_pointer
 
+    def assume_young_pointers(self, addr_struct):
+        objhdr = self.header(addr_struct)
+        if objhdr.tid & GCFLAG_NO_YOUNG_PTRS:
+            self.old_objects_pointing_to_young.append(addr_struct)
+            objhdr.tid &= ~GCFLAG_NO_YOUNG_PTRS
+        if objhdr.tid & GCFLAG_NO_HEAP_PTRS:
+            objhdr.tid &= ~GCFLAG_NO_HEAP_PTRS
+            self.last_generation_root_objects.append(addr_struct)
+
     def write_into_last_generation_obj(self, addr_struct, addr):
         objhdr = self.header(addr_struct)
         if objhdr.tid & GCFLAG_NO_HEAP_PTRS:

Modified: pypy/trunk/pypy/rpython/memory/gc/test/test_direct.py
==============================================================================
--- pypy/trunk/pypy/rpython/memory/gc/test/test_direct.py	(original)
+++ pypy/trunk/pypy/rpython/memory/gc/test/test_direct.py	Thu Sep 17 13:54:41 2009
@@ -299,7 +299,19 @@
 
         gc.collect(9)
         assert calls == ['semispace_collect']
-        calls = []                
+        calls = []
+
+    def test_assume_young_pointers(self):
+        s0 = lltype.malloc(S, immortal=True)
+        self.consider_constant(s0)
+        s = self.malloc(S)
+        s.x = 1
+        s0.next = s
+        self.gc.assume_young_pointers(llmemory.cast_ptr_to_adr(s0))
+
+        self.gc.collect(0)
+
+        assert s0.next.x == 1
 
 
 class TestHybridGC(TestGenerationGC):

Modified: pypy/trunk/pypy/rpython/memory/gctransform/framework.py
==============================================================================
--- pypy/trunk/pypy/rpython/memory/gctransform/framework.py	(original)
+++ pypy/trunk/pypy/rpython/memory/gctransform/framework.py	Thu Sep 17 13:54:41 2009
@@ -242,6 +242,13 @@
                                   [s_gc, annmodel.SomeAddress()],
                                   annmodel.SomeBool())
 
+        if hasattr(GCClass, 'assume_young_pointers'):
+            # xxx should really be a noop for gcs without generations
+            self.assume_young_pointers_ptr = getfn(
+                GCClass.assume_young_pointers.im_func,
+                [s_gc, annmodel.SomeAddress()],
+                annmodel.s_None)
+
         # in some GCs we can inline the common case of
         # malloc_fixedsize(typeid, size, True, False, False)
         if getattr(GCClass, 'inline_simple_malloc', False):
@@ -574,6 +581,12 @@
         hop.genop("direct_call", [self.can_move_ptr, self.c_const_gc, v_addr],
                   resultvar=op.result)
 
+    def gct_gc_assume_young_pointers(self, hop):
+        op = hop.spaceop
+        v_addr = op.args[0]
+        hop.genop("direct_call", [self.assume_young_pointers_ptr,
+                                  self.c_const_gc, v_addr])
+
     def _can_realloc(self):
         return self.gcdata.gc.can_realloc
 

Modified: pypy/trunk/pypy/rpython/memory/test/test_transformed_gc.py
==============================================================================
--- pypy/trunk/pypy/rpython/memory/test/test_transformed_gc.py	(original)
+++ pypy/trunk/pypy/rpython/memory/test/test_transformed_gc.py	Thu Sep 17 13:54:41 2009
@@ -5,7 +5,7 @@
 from pypy.annotation import model as annmodel
 from pypy.rpython.lltypesystem import lltype, llmemory
 from pypy.rpython.memory.gctransform import framework
-from pypy.rpython.lltypesystem.lloperation import llop
+from pypy.rpython.lltypesystem.lloperation import llop, void
 from pypy.rpython.memory.gc.marksweep import X_CLONE, X_POOL, X_POOL_PTR
 from pypy.rlib.objectmodel import compute_unique_id, we_are_translated
 from pypy.rlib.debug import ll_assert
@@ -1110,5 +1110,26 @@
         res = run([100, 100])
         assert res == 200
 
+    def test_assume_young_pointers(self):
+        from pypy.rlib import rgc
+        S = lltype.GcForwardReference()
+        S.become(lltype.GcStruct('S',
+                                 ('x', lltype.Signed),
+                                 ('prev', lltype.Ptr(S)),
+                                 ('next', lltype.Ptr(S))))
+        s0 = lltype.malloc(S, immortal=True)
+        def f():
+            s = lltype.malloc(S)
+            s.x = 42
+            llop.bare_setfield(lltype.Void, s0, void('next'), s)
+            llop.gc_assume_young_pointers(lltype.Void,
+                                          llmemory.cast_ptr_to_adr(s0))
+            rgc.collect(0)
+            return s0.next.x
+
+        run = self.runner(f, nbargs=0)
+        res = run([])
+        assert res == 42
+
     def test_malloc_nonmovable_fixsize(self):
         py.test.skip("not supported")

Modified: pypy/trunk/pypy/translator/c/gc.py
==============================================================================
--- pypy/trunk/pypy/translator/c/gc.py	(original)
+++ pypy/trunk/pypy/translator/c/gc.py	Thu Sep 17 13:54:41 2009
@@ -83,6 +83,9 @@
     def OP_GC_THREAD_DIE(self, funcgen, op):
         return ''
 
+    def OP_GC_ASSUME_YOUNG_POINTERS(self, funcgen, op):
+        return ''
+
 
 class RefcountingInfo:
     static_deallocator = None

Modified: pypy/trunk/pypy/translator/c/test/test_boehm.py
==============================================================================
--- pypy/trunk/pypy/translator/c/test/test_boehm.py	(original)
+++ pypy/trunk/pypy/translator/c/test/test_boehm.py	Thu Sep 17 13:54:41 2009
@@ -1,6 +1,7 @@
 import py
 from pypy.translator.translator import TranslationContext
-from pypy.rpython.lltypesystem import lltype
+from pypy.rpython.lltypesystem import lltype, llmemory
+from pypy.rpython.lltypesystem.lloperation import llop
 from pypy.rpython.memory.test import snippet
 from pypy.rpython.tool.rffi_platform import check_boehm
 from pypy.translator.c.genc import CExtModuleBuilder
@@ -411,6 +412,17 @@
         run = self.getcompiled(f)
         assert run() == True
 
+    def test_assume_young_pointers_nop(self):
+        S = lltype.GcStruct('S', ('x', lltype.Signed))
+        s = lltype.malloc(S)
+        s.x = 0
+        def f():
+            llop.gc_assume_young_pointers(lltype.Void,
+                                          llmemory.cast_ptr_to_adr(s))
+            return True
+        run = self.getcompiled(f)
+        assert run() == True        
+
     # reusing some tests from pypy.rpython.memory.test.snippet
     large_tests_ok = True
 



More information about the Pypy-commit mailing list