[pypy-svn] r24024 - in pypy/dist/pypy: rpython/memory translator/c translator/c/test

mwh at codespeak.net mwh at codespeak.net
Mon Mar 6 16:51:10 CET 2006


Author: mwh
Date: Mon Mar  6 16:51:08 2006
New Revision: 24024

Modified:
   pypy/dist/pypy/rpython/memory/gctransform.py
   pypy/dist/pypy/translator/c/gc.py
   pypy/dist/pypy/translator/c/test/test_newgc.py
Log:
Make the first gc framework using test run.  Woohoo!

Bits I remember:
 - fixed a bug in StackRootIterator
 - make sure FrameworkGCTransformer.gcdata.type_info_table doesn't get
   annotated as a constant
 - replace FrameworkGCTransformer.gcdata.type_info_table at the
   llpython, not the rpython level
 - make sure all types in the graph get typeids
 - pass the gc object to malloc
 - make genc emit the fields that the gc needs

Open issues:
 - it's rather hard-coded to MarkSweepGC
 - some general ugliness
 - there's no way to be sure that the test actually triggered a
   collection yet!


Modified: pypy/dist/pypy/rpython/memory/gctransform.py
==============================================================================
--- pypy/dist/pypy/rpython/memory/gctransform.py	(original)
+++ pypy/dist/pypy/rpython/memory/gctransform.py	Mon Mar  6 16:51:08 2006
@@ -688,9 +688,8 @@
             def pop(self):
                 while self.current != gcdata.root_stack_base:
                     self.current -= sizeofaddr
-                    result = self.current.address[0]
-                    if result != NULL:
-                        return result
+                    if self.current.address[0] != NULL:
+                        return self.current
                 return NULL
 
         def frameworkgc_setup():
@@ -719,6 +718,15 @@
             gcdata.root_stack_top = top
             return result
 
+        bk = self.translator.annotator.bookkeeper
+
+        # the point of this little dance is to not annotate
+        # self.gcdata.type_info_table as a constant.
+        data_classdef = bk.getuniqueclassdef(GCData)
+        data_classdef.generalize_attr(
+            'type_info_table',
+            annmodel.SomePtr(lltype.Ptr(GCData.TYPE_INFO_TABLE)))
+        
         annhelper = annlowlevel.MixLevelHelperAnnotator(self.translator.rtyper)
         frameworkgc_setup_graph = annhelper.getgraph(frameworkgc_setup, [],
                                                      annmodel.s_None)
@@ -727,7 +735,7 @@
                                              annmodel.s_None)
         pop_root_graph = annhelper.getgraph(pop_root, [],
                                             annmodel.SomeAddress())
-        bk = self.translator.annotator.bookkeeper
+
         classdef = bk.getuniqueclassdef(GCData.GCClass)
         s_gcdata = annmodel.SomeInstance(classdef)
         malloc_graph = annhelper.getgraph(GCData.GCClass.malloc.im_func,
@@ -740,7 +748,7 @@
                                                         attach_empty_cleanup=True)
         self.push_root_ptr = self.graph2funcptr(push_root_graph)
         self.pop_root_ptr  = self.graph2funcptr(pop_root_graph)
-        self.malloc_ptr    = self.graph2funcptr(malloc_graph)
+        self.malloc_ptr    = self.graph2funcptr(malloc_graph, True)
 
     def graph2funcptr(self, graph, attach_empty_cleanup=False):
         self.seen_graphs[graph] = True
@@ -796,6 +804,18 @@
     def finish(self):
         newgcdependencies = super(FrameworkGCTransformer, self).finish()
         if self.type_info_list is not None:
+            # XXX this is a kind of sledgehammer-wallnut approach to make sure
+            # all types get an ID.
+            for graph in self.translator.graphs:
+                for block in graph.iterblocks():
+                    for v in block.getvariables() + block.getconstants():
+                        t = getattr(v, 'concretetype', None)
+                        if t is None:
+                            continue
+                        if isinstance(t, lltype.Ptr) and t.TO != lltype.PyObject and \
+                               t._needsgc():
+                            self.get_type_id(v.concretetype.TO)
+
             table = lltype.malloc(self.gcdata.TYPE_INFO_TABLE,
                                   len(self.type_info_list), immortal=True)
             for tableentry, newcontent in zip(table, self.type_info_list):
@@ -803,12 +823,24 @@
                     setattr(tableentry, key, value)
             self.type_info_list = None
             self.offsettable_cache = None
+            
             # replace the type_info_table pointer in gcdata -- at this point,
             # the database is in principle complete, so it has already seen
             # the old (empty) array.  We need to force it to consider the new
             # array now.  It's a bit hackish as the old empty array will also
             # be generated in the C source, but that's a rather minor problem.
-            self.gcdata.type_info_table = table
+            
+            # XXX because we call inputconst already in replace_malloc, we can't
+            # modify the instance, we have to modify the 'rtyped instance'
+            # instead.  horrors.  is there a better way?
+            
+            s_gcdata = self.translator.annotator.bookkeeper.immutablevalue(
+                self.gcdata)
+            r_gcdata = self.translator.rtyper.getrepr(s_gcdata)
+            ll_instance = rmodel.inputconst(r_gcdata, self.gcdata).value
+            ll_instance.inst_type_info_table = table
+            #self.gcdata.type_info_table = table
+            
             newgcdependencies = newgcdependencies or []
             newgcdependencies.append(table)
         return newgcdependencies
@@ -834,10 +866,22 @@
             v_length = rmodel.inputconst(lltype.Signed, 0)
         else:
             v_length = op.args[1]
+
+        # surely there's a better way of doing this?
+        s_gcdata = self.translator.annotator.bookkeeper.immutablevalue(self.gcdata)
+        r_gcdata = self.translator.rtyper.getrepr(s_gcdata)
+        s_gc = self.translator.annotator.bookkeeper.valueoftype(self.gcdata.GCClass)
+        r_gc = self.translator.rtyper.getrepr(s_gc)
+        
+        newop0 = SpaceOperation(
+            "getfield",
+            [rmodel.inputconst(r_gcdata, self.gcdata), Constant("inst_gc")],
+            varoftype(r_gc.lowleveltype))
         newop = SpaceOperation("direct_call",
-                               [self.malloc_ptr, c_type_id, v_length],
+                               [self.malloc_ptr, newop0.result, c_type_id, v_length],
                                v)
         ops, finally_ops = self.protect_roots(newop, livevars)
+        ops.insert(0, newop0)
         ops.append(SpaceOperation("cast_adr_to_ptr", [v], op.result))
         return ops, finally_ops, 1
 

Modified: pypy/dist/pypy/translator/c/gc.py
==============================================================================
--- pypy/dist/pypy/translator/c/gc.py	(original)
+++ pypy/dist/pypy/translator/c/gc.py	Mon Mar  6 16:51:08 2006
@@ -283,3 +283,10 @@
     def OP_GC_RELOAD_POSSIBLY_MOVED(self, funcgen, op, err):
         args = [funcgen.expr(v) for v in op.args]
         return '%s = %s; /* for moving GCs */' % (args[1], args[0])
+
+    def common_gcheader_definition(self, defnode):
+        return [('flags', lltype.Signed), ('typeid', lltype.Signed)]
+
+    def common_gcheader_initdata(self, defnode):
+        # this more or less assumes mark-and-sweep gc
+        return [0, defnode.db.gctransformer.id_of_type[defnode.T]]

Modified: pypy/dist/pypy/translator/c/test/test_newgc.py
==============================================================================
--- pypy/dist/pypy/translator/c/test/test_newgc.py	(original)
+++ pypy/dist/pypy/translator/c/test/test_newgc.py	Mon Mar  6 16:51:08 2006
@@ -194,7 +194,6 @@
     from pypy.translator.c.gc import FrameworkGcPolicy as gcpolicy
 
     def test_framework_simple(self):
-        py.test.skip("in progress, getting there :-)")
         def g(x):
             return x + 1
         class A(object):
@@ -202,6 +201,10 @@
         def f():
             a = A()
             a.b = g(1)
+            # this should trigger a couple of collections
+            # XXX make sure it triggers at least one somehow!
+            for i in range(100000):
+                [A()] * 1000
             return a.b
         fn = self.getcompiled(f)
         res = fn()



More information about the Pypy-commit mailing list