[pypy-svn] r23173 - in pypy/dist/pypy/rpython/memory: . test

mwh at codespeak.net mwh at codespeak.net
Thu Feb 9 14:25:22 CET 2006


Author: mwh
Date: Thu Feb  9 14:25:19 2006
New Revision: 23173

Modified:
   pypy/dist/pypy/rpython/memory/gctransform.py
   pypy/dist/pypy/rpython/memory/test/test_gctransform.py
Log:
first implementation of BoehmGCTransformer.


Modified: pypy/dist/pypy/rpython/memory/gctransform.py
==============================================================================
--- pypy/dist/pypy/rpython/memory/gctransform.py	(original)
+++ pypy/dist/pypy/rpython/memory/gctransform.py	Thu Feb  9 14:25:19 2006
@@ -198,6 +198,27 @@
 
     # ----------------------------------------------------------------
 
+def _static_deallocator_body_for_type(v, TYPE, depth=1):
+    if isinstance(TYPE, lltype.Array):
+        inner = list(_static_deallocator_body_for_type('v_%i'%depth, TYPE.OF, depth+1))
+        if inner:
+            yield '    '*depth + 'i_%d = 0'%(depth,)
+            yield '    '*depth + 'l_%d = len(%s)'%(depth, v)
+            yield '    '*depth + 'while i_%d < l_%d:'%(depth, depth)
+            yield '    '*depth + '    v_%d = %s[i_%d]'%(depth, v, depth)
+            for line in inner:
+                yield line
+            yield '    '*depth + '    i_%d += 1'%(depth,)
+    elif isinstance(TYPE, lltype.Struct):
+        for name in TYPE._names:
+            inner = list(_static_deallocator_body_for_type(
+                v + '_' + name, TYPE._flds[name], depth))
+            if inner:
+                yield '    '*depth + v + '_' + name + ' = ' + v + '.' + name
+                for line in inner:
+                    yield line
+    elif isinstance(TYPE, lltype.Ptr):
+        yield '    '*depth + 'pop_alive(%s)'%v
 
 class RefcountingGCTransformer(GCTransformer):
 
@@ -269,29 +290,6 @@
                 pass
         return None
 
-    def _static_deallocator_body_for_type(self, v, TYPE, depth=1):
-        if isinstance(TYPE, lltype.Array):
-            
-            inner = list(self._static_deallocator_body_for_type('v_%i'%depth, TYPE.OF, depth+1))
-            if inner:
-                yield '    '*depth + 'i_%d = 0'%(depth,)
-                yield '    '*depth + 'l_%d = len(%s)'%(depth, v)
-                yield '    '*depth + 'while i_%d < l_%d:'%(depth, depth)
-                yield '    '*depth + '    v_%d = %s[i_%d]'%(depth, v, depth)
-                for line in inner:
-                    yield line
-                yield '    '*depth + '    i_%d += 1'%(depth,)
-        elif isinstance(TYPE, lltype.Struct):
-            for name in TYPE._names:
-                inner = list(self._static_deallocator_body_for_type(
-                    v + '_' + name, TYPE._flds[name], depth))
-                if inner:
-                    yield '    '*depth + v + '_' + name + ' = ' + v + '.' + name
-                    for line in inner:
-                        yield line
-        elif isinstance(TYPE, lltype.Ptr):
-            yield '    '*depth + 'pop_alive(%s)'%v
-
     def static_deallocation_graph_for_type(self, TYPE):
         if TYPE in self.static_deallocator_graphs:
             return self.static_deallocator_graphs[TYPE]
@@ -320,7 +318,7 @@
             DESTR_ARG = None
 
         if destrptr is not None:
-            body = '\n'.join(self._static_deallocator_body_for_type('v', TYPE, 2))
+            body = '\n'.join(_static_deallocator_body_for_type('v', TYPE, 2))
             src = """
 def deallocator(addr):
     v = cast_adr_to_ptr(addr, PTR_TYPE)
@@ -340,7 +338,7 @@
 """ % (body, )
         else:
             call_del = None
-            body = '\n'.join(self._static_deallocator_body_for_type('v', TYPE))
+            body = '\n'.join(_static_deallocator_body_for_type('v', TYPE))
             src = ('def deallocator(addr):\n    v = cast_adr_to_ptr(addr, PTR_TYPE)\n' +
                    body + '\n    destroy(v)\n')
         d = {'pop_alive': pop_alive,
@@ -466,3 +464,91 @@
         return [TYPE]
     else:
         return []
+
+def type_contains_pyobjs(TYPE):
+    if isinstance(TYPE, lltype.Array):
+        return type_contains_pyobjs(TYPE.OF)
+    elif isinstance(TYPE, lltype.Struct):
+        result = []
+        for name in TYPE._names:
+            if type_contains_pyobjs(TYPE._flds[name]):
+                return True
+        return False
+    elif isinstance(TYPE, lltype.Ptr) and TYPE.TO == lltype.PyObject:
+        return True
+    else:
+        return False
+
+
+class BoehmGCTransformer(GCTransformer):
+    gc_header_offset = gc.GCHeaderOffset(lltype.Void)
+
+    def __init__(self, translator):
+        super(BoehmGCTransformer, self).__init__(translator)
+        self.finalizer_graphs = {}
+
+    def push_alive_nopyobj(self, var):
+        return []
+
+    def pop_alive_nopyobj(self, var):
+        return []
+
+    def get_rtti(self, TYPE):
+        if isinstance(TYPE, lltype.GcStruct):
+            try:
+                return lltype.getRuntimeTypeInfo(TYPE)
+            except ValueError:
+                pass
+        return None
+
+    def finalizer_graph_for_type(self, TYPE):
+        if TYPE in self.finalizer_graphs:
+            return self.finalizer_graphs[TYPE]
+        
+        def compute_pop_alive_ll_ops(hop):
+            hop.llops.extend(self.pop_alive(hop.args_v[1]))
+            return hop.inputconst(hop.r_result.lowleveltype, hop.s_result.const)
+        def pop_alive(var):
+            pass
+        pop_alive.compute_ll_ops = compute_pop_alive_ll_ops
+        pop_alive.llresult = lltype.Void
+        
+        rtti = self.get_rtti(TYPE)
+        if rtti is not None and hasattr(rtti._obj, 'destructor_funcptr'):
+            destrptr = rtti._obj.destructor_funcptr
+            DESTR_ARG = lltype.typeOf(destrptr).TO.ARGS[0]
+        else:
+            destrptr = None
+            DESTR_ARG = None
+
+        if type_contains_pyobjs(TYPE):
+            if destrptr:
+                raise Exception("can't mix PyObjects and __del__ with Boehm")
+
+            static_body = '\n'.join(_static_deallocator_body_for_type('v', TYPE))
+            d = {'pop_alive':pop_alive,
+                 'PTR_TYPE':lltype.Ptr(TYPE),
+                 'cast_adr_to_ptr':objectmodel.cast_adr_to_ptr}
+            src = ("def finalizer(addr):\n"
+                   "    v = cast_adr_to_ptr(addr, PTR_TYPE)\n"
+                   "%s\n")%(static_body,)
+            exec src in d
+            g = self.translator.rtyper.annotate_helper(d['finalizer'], [llmemory.Address])
+        elif destrptr:
+            d = {'PTR_TYPE':DESTR_ARG,
+                 'cast_adr_to_ptr':objectmodel.cast_adr_to_ptr,
+                 'destrptr':destrptr}
+            src = ("def finalizer(addr):\n"
+                   "    v = cast_adr_to_ptr(addr, PTR_TYPE)\n"
+                   "    destrptr(v)\n")
+            exec src in d
+            g = self.translator.rtyper.annotate_helper(
+                d['finalizer'], [llmemory.Address])
+        else:
+            g = None
+
+        if g:
+            self.seen_graphs[g] = True
+        self.finalizer_graphs[TYPE] = g
+        return g
+        

Modified: pypy/dist/pypy/rpython/memory/test/test_gctransform.py
==============================================================================
--- pypy/dist/pypy/rpython/memory/test/test_gctransform.py	(original)
+++ pypy/dist/pypy/rpython/memory/test/test_gctransform.py	Thu Feb  9 14:25:19 2006
@@ -264,6 +264,22 @@
     ops = getops(graphof(t, f))
     assert len(ops['direct_call']) == 4
 
+
+def test_boehm_simple():
+    class C:
+        pass
+    def f():
+        c = C()
+        c.x = 1
+        return c.x
+    t, transformer = rtype_and_transform(
+        f, [], gctransform.BoehmGCTransformer, check=False)
+    ops = getops(graphof(t, f))
+    assert 'direct_call' not in ops
+    gcs = [k for k in ops if k.startswith('gc')]
+    assert len(gcs) == 0
+
+
   
 # ______________________________________________________________________
 # test write barrier placement
@@ -308,19 +324,25 @@
 # ----------------------------------------------------------------------
 # test deallocators
 
-def make_deallocator(TYPE, attr="static_deallocation_graph_for_type"):
+def make_deallocator(TYPE,
+                     attr="static_deallocation_graph_for_type",
+                     cls=gctransform.RefcountingGCTransformer):
     def f():
         pass
     t = TranslationContext()
     t.buildannotator().build_types(f, [])
     t.buildrtyper().specialize(t)
-    transformer = gctransform.RefcountingGCTransformer(t)
+    transformer = cls(t)
     graph = getattr(transformer, attr)(TYPE)
     t.rtyper.specialize_more_blocks()
     if conftest.option.view:
         t.view()
     return graph, t
 
+def make_boehm_finalizer(TYPE):
+    return make_deallocator(TYPE, attr="finalizer_graph_for_type",
+                            cls=gctransform.BoehmGCTransformer)
+
 def test_deallocator_simple():
     S = lltype.GcStruct("S", ('x', lltype.Signed))
     dgraph, t = make_deallocator(S)
@@ -425,3 +447,49 @@
         s2 = lltype.malloc(S)
         s1.x = s2
     t, transformer = rtype_and_transform(f, [], gctransform.RefcountingGCTransformer, check=False)
+
+def test_boehm_finalizer_simple():
+    S = lltype.GcStruct("S", ('x', lltype.Signed))
+    f, t = make_boehm_finalizer(S)
+    assert f is None
+
+def test_boehm_finalizer_pyobj():
+    S = lltype.GcStruct("S", ('x', lltype.Ptr(lltype.PyObject)))
+    f, t = make_boehm_finalizer(S)
+    assert f is not None
+
+def test_boehm_finalizer___del__():
+    S = lltype.GcStruct("S", ('x', lltype.Signed))
+    def f(s):
+        s.x = 1
+    def type_info_S(p):
+        return lltype.getRuntimeTypeInfo(S)
+    qp = lltype.functionptr(lltype.FuncType([lltype.Ptr(S)],
+                                            lltype.Ptr(lltype.RuntimeTypeInfo)),
+                            "type_info_S", 
+                            _callable=type_info_S)
+    dp = lltype.functionptr(lltype.FuncType([lltype.Ptr(S)],
+                                            lltype.Void), 
+                            "destructor_funcptr", 
+                            _callable=f)
+    pinf = lltype.attachRuntimeTypeInfo(S, qp, destrptr=dp)
+    f, t = make_boehm_finalizer(S)
+    assert f is not None
+
+def test_boehm_finalizer_nomix___del___and_pyobj():
+    S = lltype.GcStruct("S", ('x', lltype.Signed), ('y', lltype.Ptr(lltype.PyObject)))
+    def f(s):
+        s.x = 1
+    def type_info_S(p):
+        return lltype.getRuntimeTypeInfo(S)
+    qp = lltype.functionptr(lltype.FuncType([lltype.Ptr(S)],
+                                            lltype.Ptr(lltype.RuntimeTypeInfo)),
+                            "type_info_S", 
+                            _callable=type_info_S)
+    dp = lltype.functionptr(lltype.FuncType([lltype.Ptr(S)],
+                                            lltype.Void), 
+                            "destructor_funcptr", 
+                            _callable=f)
+    pinf = lltype.attachRuntimeTypeInfo(S, qp, destrptr=dp)
+    py.test.raises(Exception, "make_boehm_finalizer(S)")
+



More information about the Pypy-commit mailing list