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

arigo at codespeak.net arigo at codespeak.net
Tue May 23 16:41:22 CEST 2006


Author: arigo
Date: Tue May 23 16:41:19 2006
New Revision: 27622

Modified:
   pypy/dist/pypy/rpython/annlowlevel.py
   pypy/dist/pypy/rpython/lltypesystem/lltype.py
   pypy/dist/pypy/rpython/memory/gc.py
   pypy/dist/pypy/rpython/memory/gctransform.py
   pypy/dist/pypy/rpython/memory/test/test_transformed_gc.py
   pypy/dist/pypy/translator/c/database.py
   pypy/dist/pypy/translator/c/funcgen.py
   pypy/dist/pypy/translator/c/gc.py
   pypy/dist/pypy/translator/c/node.py
Log:
Trying to sort out the dependencies in order between the stackless and
the gc transforms.  The isgchelper flag was getting in the way because
gc helpers must almost all be stackless transformed too (e.g. to allow
UnwindException to pass through a call to a destructor).

Some obscure hacks now allow cooperation between the mixlevelannotator
and the genc database about delayed functions.  It is now ok to get()
delayed function pointers.  It forces the unique pypy_g_* name of the
function to be computed, but the FuncNode is not built.  Instead, the
complete() method periodically checks if these delayed pointers have
been resolved (e.g. by a finish()).

The finish() of the gc transformer is now in two parts: finish_helpers()
finishes the mixlevelannotator; then finish_tables() computes the
final GC tables.

Documented in complete() the precise order in which these finish() are
called and why.


Modified: pypy/dist/pypy/rpython/annlowlevel.py
==============================================================================
--- pypy/dist/pypy/rpython/annlowlevel.py	(original)
+++ pypy/dist/pypy/rpython/annlowlevel.py	Tue May 23 16:41:19 2006
@@ -161,7 +161,11 @@
 
     def graph2delayed(self, graph):
         FUNCTYPE = lltype.ForwardReference()
-        delayedptr = lltype._ptr(lltype.Ptr(FUNCTYPE), "delayed!", solid=True)
+        # obscure hack: embed the name of the function in the string, so
+        # that the genc database can get it even before the delayedptr
+        # is really computed
+        name = "delayed!%s" % (graph.name,)
+        delayedptr = lltype._ptr(lltype.Ptr(FUNCTYPE), name, solid=True)
         self.delayedfuncs.append((delayedptr, graph))
         return delayedptr
 

Modified: pypy/dist/pypy/rpython/lltypesystem/lltype.py
==============================================================================
--- pypy/dist/pypy/rpython/lltypesystem/lltype.py	(original)
+++ pypy/dist/pypy/rpython/lltypesystem/lltype.py	Tue May 23 16:41:19 2006
@@ -790,6 +790,8 @@
         p = _ptr(Ptr(typeOf(container)), container, p._solid)
     return p
 
+class DelayedPointer(Exception):
+    pass
 
 class _ptr(object):
     __slots__ = ('_TYPE', '_T', 
@@ -843,7 +845,10 @@
         raise TypeError("pointer objects are not hashable")
 
     def __nonzero__(self):
-        return self._obj is not None
+        try:
+            return self._obj is not None
+        except DelayedPointer:
+            return True    # assume it's not a delayed null
 
     # _setobj, _getobj and _obj0 are really _internal_ implementations details of _ptr,
     # use _obj if necessary instead !
@@ -866,8 +871,10 @@
                 if obj is None:
                     raise RuntimeError("accessing already garbage collected %r"
                                    % (self._T,))
-            if not isinstance(obj, int):
+            if isinstance(obj, _container):
                 obj._check()
+            elif isinstance(obj, str) and obj.startswith("delayed!"):
+                raise DelayedPointer
         return obj
     _obj = property(_getobj)
 
@@ -968,6 +975,8 @@
             return '* %s' % (self._obj, )
         except RuntimeError:
             return '* DEAD %s' % self._T
+        except DelayedPointer:
+            return '* %s' % (self._obj0,)
 
     def __call__(self, *args):
         if isinstance(self._T, FuncType):

Modified: pypy/dist/pypy/rpython/memory/gc.py
==============================================================================
--- pypy/dist/pypy/rpython/memory/gc.py	(original)
+++ pypy/dist/pypy/rpython/memory/gc.py	Tue May 23 16:41:19 2006
@@ -218,10 +218,6 @@
         #    call __del__, move the object to the list of object-without-del
         import time
         from pypy.rpython.lltypesystem.lloperation import llop
-        # XXX the following two lines should not be there, but without them
-        # there is a strange crash in decodestate when using stackless :-(
-        if self.collect_in_progress:
-            return
         if DEBUG_PRINT:
             llop.debug_print(lltype.Void, 'collecting...')
         start_time = time.time()
@@ -383,6 +379,8 @@
                 #llop.debug_view(lltype.Void, self.malloced_objects, self.malloced_objects_with_finalizer, size_gc_header)
                 finalizer(obj)
                 if not self.collect_in_progress: # another collection was caused?
+                    llop.debug_print(lltype.Void, "outer collect interrupted "
+                                                  "by recursive collect")
                     return
                 if not last:
                     if self.malloced_objects_with_finalizer == next:

Modified: pypy/dist/pypy/rpython/memory/gctransform.py
==============================================================================
--- pypy/dist/pypy/rpython/memory/gctransform.py	(original)
+++ pypy/dist/pypy/rpython/memory/gctransform.py	Tue May 23 16:41:19 2006
@@ -32,7 +32,7 @@
     
 
 class GCTransformer(object):
-    finished = False
+    finished_helpers = False
 
     def __init__(self, translator, inline=False):
         self.translator = translator
@@ -265,28 +265,32 @@
         return [SpaceOperation("direct_call", op.args, op.result)]
 
     def annotate_helper(self, ll_helper, ll_args, ll_result):
-        assert not self.finished
+        assert not self.finished_helpers
         args_s = map(annmodel.lltype_to_annotation, ll_args)
         s_result = annmodel.lltype_to_annotation(ll_result)
-        g = self.mixlevelannotator.getgraph(ll_helper, args_s, s_result)
-        FUNC = lltype.FuncType(ll_args, ll_result)
-        ptr = rmodel.inputconst(
-            lltype.Ptr(FUNC),
-            lltype.functionptr(FUNC, g.name, graph=g, isgchelper=True))
-        return g, ptr.value
+        graph = self.mixlevelannotator.getgraph(ll_helper, args_s, s_result)
+        # the produced graphs does not need to be fully transformed
+        self.need_minimal_transform(graph)
+        return self.mixlevelannotator.graph2delayed(graph)
 
     def inittime_helper(self, ll_helper, ll_args, ll_result):
-        graph, ptr = self.annotate_helper(ll_helper, ll_args, ll_result)
-        self.need_minimal_transform(graph)
-        return Constant(ptr, lltype.Ptr(lltype.FuncType(ll_args, ll_result)))
+        ptr = self.annotate_helper(ll_helper, ll_args, ll_result)
+        return Constant(ptr, lltype.typeOf(ptr))
 
-    def finish(self):
+    def finish_helpers(self):
         if self.translator is not None:
             self.mixlevelannotator.finish_annotate()
-        self.finished = True
+        self.finished_helpers = True
         if self.translator is not None:
             self.mixlevelannotator.finish_rtype()
 
+    def finish_tables(self):
+        pass
+
+    def finish(self):
+        self.finish_helpers()
+        self.finish_tables()
+
 class MinimalGCTransformer(GCTransformer):
     def __init__(self, parenttransformer):
         GCTransformer.__init__(self, parenttransformer.translator)
@@ -450,7 +454,7 @@
 
         dealloc_fptr = self.dynamic_deallocation_funcptr_for_type(PTRTYPE.TO)
         cdealloc_fptr = rmodel.inputconst(
-            lltype.Ptr(ADDRESS_VOID_FUNC), dealloc_fptr)
+            lltype.typeOf(dealloc_fptr), dealloc_fptr)
              
         result.append(SpaceOperation("direct_call",
                                      [self.decref_ptr, adr1, cdealloc_fptr],
@@ -493,9 +497,6 @@
         result.extend(self.pop_alive(oldval))
         return result
 
-    def finish(self):
-        super(RefcountingGCTransformer, self).finish()
-
 ##    -- maybe add this for tests and for consistency --
 ##    def consider_constant(self, TYPE, value):
 ##        p = value._as_ptr()
@@ -565,9 +566,7 @@
              'll_call_destructor': ll_call_destructor}
         exec src in d
         this = d['ll_deallocator']
-        g, fptr = self.annotate_helper(this, [llmemory.Address], lltype.Void)
-        # the produced deallocator graph does not need to be transformed
-        self.need_minimal_transform(g)
+        fptr = self.annotate_helper(this, [llmemory.Address], lltype.Void)
         self.static_deallocator_funcptrs[TYPE] = fptr
         for p in find_gc_ptrs_in_type(TYPE):
             self.static_deallocation_funcptr_for_type(p.TO)
@@ -599,9 +598,7 @@
             rtti = queryptr(v)
             gcheader.signed[0] = 0
             llop.gc_call_rtti_destructor(lltype.Void, rtti, addr)
-        g, fptr = self.annotate_helper(ll_dealloc, [llmemory.Address], lltype.Void)
-        self.need_minimal_transform(g)
-        
+        fptr = self.annotate_helper(ll_dealloc, [llmemory.Address], lltype.Void)
         self.dynamic_deallocator_funcptrs[TYPE] = fptr
         self.queryptr2dynamic_deallocator_funcptr[queryptr._obj] = fptr
         return fptr
@@ -663,9 +660,6 @@
         """ for boehm it is enough to do nothing"""
         return [SpaceOperation("same_as", [Constant(None, lltype.Void)], op.result)]
 
-    def finish(self):
-        super(BoehmGCTransformer, self).finish()
-
     def finalizer_funcptr_for_type(self, TYPE):
         if TYPE in self.finalizer_funcptrs:
             return self.finalizer_funcptrs[TYPE]
@@ -690,7 +684,7 @@
                    "    v = cast_adr_to_ptr(addr, PTR_TYPE)\n"
                    "%s\n")%(static_body,)
             exec src in d
-            g, fptr = self.annotate_helper(d['ll_finalizer'], [llmemory.Address], lltype.Void)
+            fptr = self.annotate_helper(d['ll_finalizer'], [llmemory.Address], lltype.Void)
         elif destrptr:
             EXC_INSTANCE_TYPE = self.translator.rtyper.exceptiondata.lltype_of_exception_value
             def ll_finalizer(addr):
@@ -698,12 +692,10 @@
                 v = llmemory.cast_adr_to_ptr(addr, DESTR_ARG)
                 ll_call_destructor(destrptr, v)
                 llop.gc_restore_exception(lltype.Void, exc_instance)
-            g, fptr = self.annotate_helper(ll_finalizer, [llmemory.Address], lltype.Void)
+            fptr = self.annotate_helper(ll_finalizer, [llmemory.Address], lltype.Void)
         else:
-            g = fptr = None
+            fptr = None
 
-        if g:
-            self.need_minimal_transform(g)
         self.finalizer_funcptrs[TYPE] = fptr
         return fptr
 
@@ -735,6 +727,7 @@
 class FrameworkGCTransformer(GCTransformer):
     use_stackless = False
     extra_static_slots = 0
+    finished_tables = False
 
     from pypy.rpython.memory.gc import MarkSweepGC as GCClass
     GC_PARAMS = {'start_heap_size': 8*1024*1024 # XXX adjust
@@ -975,7 +968,7 @@
         try:
             return self.id_of_type[TYPE]
         except KeyError:
-            assert not self.finished
+            assert not self.finished_tables
             assert isinstance(TYPE, (lltype.GcStruct, lltype.GcArray))
             # Record the new type_id description as a small dict for now.
             # It will be turned into a Struct("type_info") in finish()
@@ -1037,11 +1030,10 @@
             def ll_finalizer(addr):
                 v = llmemory.cast_adr_to_ptr(addr, DESTR_ARG)
                 ll_call_destructor(destrptr, v)
-            g, fptr = self.annotate_helper(ll_finalizer, [llmemory.Address], lltype.Void)
+            fptr = self.annotate_helper(ll_finalizer, [llmemory.Address], lltype.Void)
         else:
-            g = fptr = lltype.nullptr(ADDRESS_VOID_FUNC)
-        if g:
-            self.need_minimal_transform(g)
+            fptr = lltype.nullptr(ADDRESS_VOID_FUNC)
+
         self.finalizer_funcptrs[TYPE] = fptr
         return fptr
 
@@ -1085,56 +1077,53 @@
             self.offsettable_cache[TYPE] = cachedarray
             return cachedarray
 
-    def finish(self):
-        finished = self.finished
-        newgcdependencies = super(FrameworkGCTransformer, self).finish()
-        if not finished:
-
-            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):
-                for key, value in newcontent.items():
-                    setattr(tableentry, key, value)
-            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.
-            
-            # 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
-
-            ll_static_roots = lltype.malloc(lltype.Array(llmemory.Address),
-                                            len(self.static_gc_roots) +
-                                                self.extra_static_slots,
-                                            immortal=True)
-            for i in range(len(self.static_gc_roots)):
-                adr = self.static_gc_roots[i]
-                ll_static_roots[i] = adr
-            ll_instance.inst_static_roots = ll_static_roots
-
-            ll_static_roots_inside = lltype.malloc(lltype.Array(llmemory.Address),
-                                                   len(self.addresses_of_static_ptrs_in_nongc),
-                                                   immortal=True)
-            for i in range(len(self.addresses_of_static_ptrs_in_nongc)):
-                ll_static_roots_inside[i] = self.addresses_of_static_ptrs_in_nongc[i]
-            ll_instance.inst_static_root_start = llmemory.cast_ptr_to_adr(ll_static_roots_inside) + llmemory.ArrayItemsOffset(lltype.Array(llmemory.Address))
-            ll_instance.inst_static_root_end = ll_instance.inst_static_root_start + llmemory.sizeof(llmemory.Address) * len(ll_static_roots_inside)
-            
-            newgcdependencies = newgcdependencies or []
-            newgcdependencies.append(table)
-            newgcdependencies.append(ll_static_roots)
-            newgcdependencies.append(ll_static_roots_inside)
+    def finish_tables(self):
+        self.finished_tables = True
+        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):
+            for key, value in newcontent.items():
+                setattr(tableentry, key, value)
+        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.
+
+        # 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
+
+        ll_static_roots = lltype.malloc(lltype.Array(llmemory.Address),
+                                        len(self.static_gc_roots) +
+                                            self.extra_static_slots,
+                                        immortal=True)
+        for i in range(len(self.static_gc_roots)):
+            adr = self.static_gc_roots[i]
+            ll_static_roots[i] = adr
+        ll_instance.inst_static_roots = ll_static_roots
+
+        ll_static_roots_inside = lltype.malloc(lltype.Array(llmemory.Address),
+                                               len(self.addresses_of_static_ptrs_in_nongc),
+                                               immortal=True)
+        for i in range(len(self.addresses_of_static_ptrs_in_nongc)):
+            ll_static_roots_inside[i] = self.addresses_of_static_ptrs_in_nongc[i]
+        ll_instance.inst_static_root_start = llmemory.cast_ptr_to_adr(ll_static_roots_inside) + llmemory.ArrayItemsOffset(lltype.Array(llmemory.Address))
+        ll_instance.inst_static_root_end = ll_instance.inst_static_root_start + llmemory.sizeof(llmemory.Address) * len(ll_static_roots_inside)
+
+        newgcdependencies = []
+        newgcdependencies.append(table)
+        newgcdependencies.append(ll_static_roots)
+        newgcdependencies.append(ll_static_roots_inside)
         return newgcdependencies
 
     def protect_roots(self, op, livevars, block, index=-1):

Modified: pypy/dist/pypy/rpython/memory/test/test_transformed_gc.py
==============================================================================
--- pypy/dist/pypy/rpython/memory/test/test_transformed_gc.py	(original)
+++ pypy/dist/pypy/rpython/memory/test/test_transformed_gc.py	Tue May 23 16:41:19 2006
@@ -389,10 +389,10 @@
                 self.id = b.nextid
                 b.nextid += 1
             def __del__(self):
+                llop.gc__collect(lltype.Void)
                 b.num_deleted += 1
                 C()
                 C()
-                llop.gc__collect(lltype.Void)
         class C(A):
             def __del__(self):
                 b.num_deleted += 1

Modified: pypy/dist/pypy/translator/c/database.py
==============================================================================
--- pypy/dist/pypy/translator/c/database.py	(original)
+++ pypy/dist/pypy/translator/c/database.py	Tue May 23 16:41:19 2006
@@ -30,7 +30,8 @@
         self.pendingsetupnodes = []
         self.containernodes = {}
         self.containerlist = []
-        self.latercontainerlist = []
+        self.delayedfunctionnames = {}
+        self.delayedfunctionptrs = []
         self.completedcontainers = 0
         self.containerstats = {}
         self.externalfuncs = {}
@@ -138,7 +139,7 @@
         else:
             raise Exception("don't know about type %r" % (T,))
 
-    def getcontainernode(self, container):
+    def getcontainernode(self, container, **buildkwds):
         try:
             node = self.containernodes[container]
         except KeyError:
@@ -148,12 +149,9 @@
                 if hasattr(self.gctransformer, 'consider_constant'):
                     self.gctransformer.consider_constant(T, container)
             nodefactory = ContainerNodeFactory[T.__class__]
-            node = nodefactory(self, T, container)
+            node = nodefactory(self, T, container, **buildkwds)
             self.containernodes[container] = node
-            if node.is_later_container:
-                self.latercontainerlist.append(node)
-            else:
-                self.containerlist.append(node)
+            self.containerlist.append(node)
             kind = getattr(node, 'nodekind', '?')
             self.containerstats[kind] = self.containerstats.get(kind, 0) + 1
         return node
@@ -173,11 +171,40 @@
                 return PrimitiveName[T](obj, self)
             elif isinstance(T, Ptr):
                 if obj:   # test if the ptr is non-NULL
-                    if isinstance(obj._obj, int):
+                    try:
+                        container = obj._obj
+                    except lltype.DelayedPointer:
+                        # hack hack hack
+                        name = obj._obj0
+                        assert name.startswith('delayed!')
+                        n = len('delayed!')
+                        if len(name) == n:
+                            raise
+                        if id(obj) in self.delayedfunctionnames:
+                            return self.delayedfunctionnames[id(obj)][0]
+                        funcname = name[n:]
+                        funcname = self.namespace.uniquename('g_' + funcname)
+                        self.delayedfunctionnames[id(obj)] = funcname, obj
+                        self.delayedfunctionptrs.append(obj)
+                        return funcname
+                        # /hack hack hack
+                    else:
+                        # hack hack hack
+                        if id(obj) in self.delayedfunctionnames:
+                            # this used to be a delayed function,
+                            # make sure we use the same name
+                            forcename = self.delayedfunctionnames[id(obj)][0]
+                            node = self.getcontainernode(container,
+                                                         forcename=forcename)
+                            assert node.ptrname == forcename
+                            return forcename
+                        # /hack hack hack
+
+                    if isinstance(container, int):
                         # special case for tagged odd-valued pointers
                         return '((%s) %d)' % (cdecl(self.gettype(T), ''),
                                               obj._obj)
-                    node = self.getcontainernode(obj._obj)
+                    node = self.getcontainernode(container)
                     return node.ptrname
                 else:
                     return '((%s) NULL)' % (cdecl(self.gettype(T), ''), )
@@ -198,10 +225,52 @@
             show_i = (i//1000 + 1) * 1000
         else:
             show_i = -1
-        work_to_do = True
-        transformations_to_finish = [self.gctransformer]
+
+        # The order of database completion is fragile with stackless and
+        # gc transformers.  Here is what occurs:
+        #
+        # 1. follow dependencies recursively from the entry point: data
+        #    structures pointing to other structures or functions, and
+        #    constants in functions pointing to other structures or functions.
+        #    Because of the mixlevelannotator, this might find delayed
+        #    (not-annotated-and-rtyped-yet) function pointers.  They are
+        #    not followed at this point.  User finalizers (__del__) on the
+        #    other hand are followed during this step too.
+        #
+        # 2. gctransformer.finish_helpers() - after this, all functions in
+        #    the program have been rtyped.
+        #
+        # 3. follow new dependencies.  All previously delayed functions
+        #    should have been resolved by 2 - they are gc helpers, like
+        #    ll_finalize().  New FuncNodes are built for them.  No more
+        #    FuncNodes can show up after this step.
+        #
+        # 4. stacklesstransform.finish() - freeze the stackless resume point
+        #    table.
+        #
+        # 5. follow new dependencies (this should be only the new frozen
+        #    table, which contains only numbers and already-seen function
+        #    pointers).
+        #
+        # 6. gctransformer.finish_tables() - freeze the gc types table.
+        #
+        # 7. follow new dependencies (this should be only the gc type table,
+        #    which contains only numbers and pointers to ll_finalizer
+        #    functions seen in step 3).
+        #
+        # I think that there is no reason left at this point that force
+        # step 4 to be done before step 6, nor to have a follow-new-
+        # dependencies step inbetween.  It is important though to have step 3
+        # before steps 4 and 6.
+        #
+        # This is implemented by interleaving the follow-new-dependencies
+        # steps with calls to the next 'finish' function from the following
+        # list:
+        finish_callbacks = []
+        finish_callbacks.append(self.gctransformer.finish_helpers)
         if self.stacklesstransformer:
-            transformations_to_finish.insert(0, self.stacklesstransformer)
+            finish_callbacks.append(self.stacklesstransformer.finish)
+        finish_callbacks.append(self.gctransformer.finish_tables)
 
         def add_dependencies(newdependencies):
             for value in newdependencies:
@@ -210,7 +279,7 @@
                 else:
                     self.get(value)
         
-        while work_to_do:
+        while True:
             while True:
                 if hasattr(self, 'pyobjmaker'):
                     self.pyobjmaker.collect_initcode()
@@ -228,22 +297,32 @@
                 if i == show_i:
                     dump()
                     show_i += 1000
-            work_to_do = False
 
-            while transformations_to_finish:
-                transformation = transformations_to_finish.pop(0)
-                newdependencies = transformation.finish()
+            if self.delayedfunctionptrs:
+                lst = self.delayedfunctionptrs
+                self.delayedfunctionptrs = []
+                progress = False
+                for fnptr in lst:
+                    try:
+                        fnptr._obj
+                    except lltype.DelayedPointer:   # still not resolved
+                        self.delayedfunctionptrs.append(fnptr)
+                    else:
+                        self.get(fnptr)
+                        progress = True
+                if progress:
+                    continue   # progress - follow all dependencies again
+
+            if finish_callbacks:
+                finish = finish_callbacks.pop(0)
+                newdependencies = finish()
                 if newdependencies:
                     add_dependencies(newdependencies)
-                    work_to_do = True
-                    break
-            else:
-                if self.latercontainerlist:
-                    work_to_do = True
-                    for node in self.latercontainerlist:
-                        node.make_funcgens()
-                        self.containerlist.append(node)
-                    self.latercontainerlist = []
+                continue       # progress - follow all dependencies again
+
+            break     # database is now complete
+
+        assert not self.delayedfunctionptrs
         self.completed = True
         if show_progress:
             dump()

Modified: pypy/dist/pypy/translator/c/funcgen.py
==============================================================================
--- pypy/dist/pypy/translator/c/funcgen.py	(original)
+++ pypy/dist/pypy/translator/c/funcgen.py	Tue May 23 16:41:19 2006
@@ -10,6 +10,7 @@
 from pypy.rpython.lltypesystem.lltype import UnsignedLongLong, Char, UniChar
 from pypy.rpython.lltypesystem.lltype import pyobjectptr, ContainerType
 from pypy.rpython.lltypesystem.lltype import Struct, Array, FixedSizeArray
+from pypy.rpython.lltypesystem.lltype import ForwardReference
 from pypy.translator.backendopt.ssa import SSI_to_SSA
 
 PyObjPtr = Ptr(PyObject)
@@ -34,15 +35,14 @@
                        blocknum
                        oldgraph""".split()
 
-    def __init__(self, graph, db, cpython_exc=False, functionname=None,
-                 do_stackless=True):
+    def __init__(self, graph, db, cpython_exc=False, functionname=None):
         self.graph = graph
         self.db = db
         self.gcpolicy = db.gcpolicy
         self.cpython_exc = cpython_exc
         self.functionname = functionname
         # apply the stackless transformation
-        if db.stacklesstransformer and do_stackless:
+        if db.stacklesstransformer:
             db.stacklesstransformer.transform_graph(graph)
         # apply the exception transformation
         if self.db.exctransformer:
@@ -54,6 +54,10 @@
 
         for v in self.vars:
             T = getattr(v, 'concretetype', PyObjPtr)
+            # obscure: skip forward references and hope for the best
+            # (needed for delayed function pointers)
+            if isinstance(T, Ptr) and T.TO.__class__ == ForwardReference:
+                continue
             db.gettype(T)  # force the type to be considered by the database
        
         self.lltypes = None

Modified: pypy/dist/pypy/translator/c/gc.py
==============================================================================
--- pypy/dist/pypy/translator/c/gc.py	(original)
+++ pypy/dist/pypy/translator/c/gc.py	Tue May 23 16:41:19 2006
@@ -355,7 +355,7 @@
         if rtti is not None and hasattr(rtti._obj, 'destructor_funcptr'):
             destrptr = rtti._obj.destructor_funcptr
             # make sure this is seen by the database early, i.e. before
-            # finish() on the gctransformer
+            # finish_helpers() on the gctransformer
             self.db.get(destrptr)
 
     def array_setup(self, arraydefnode):

Modified: pypy/dist/pypy/translator/c/node.py
==============================================================================
--- pypy/dist/pypy/translator/c/node.py	(original)
+++ pypy/dist/pypy/translator/c/node.py	Tue May 23 16:41:19 2006
@@ -335,7 +335,6 @@
 
 
 class ContainerNode(object):
-    is_later_container = False
     if USESLOTS:
         __slots__ = """db T obj 
                        typename implementationtypename
@@ -544,20 +543,18 @@
     # there not so many node of this kind, slots should not
     # be necessary
 
-    def __init__(self, db, T, obj):
+    def __init__(self, db, T, obj, forcename=None):
         self.globalcontainer = True
         self.db = db
         self.T = T
         self.obj = obj
         if hasattr(obj, 'includes'):
             self.includes = obj.includes
-            self.name = self.basename()
-        else:
-            self.name = db.namespace.uniquename('g_' + self.basename())
-        if not getattr(obj, 'isgchelper', False):
-            self.make_funcgens()
+            self.name = forcename or self.basename()
         else:
-            self.is_later_container = True
+            self.name = (forcename or
+                         db.namespace.uniquename('g_' + self.basename()))
+        self.make_funcgens()
         #self.dependencies = {}
         self.typename = db.gettype(T)  #, who_asks=self)
         self.ptrname = self.name
@@ -656,8 +653,7 @@
                 from pypy.translator.c.stackless import SlpFunctionCodeGenerator
                 return [SlpFunctionCodeGenerator(fnobj.graph, db, cpython_exc, functionname)]
         else:
-            return [FunctionCodeGenerator(fnobj.graph, db, cpython_exc, functionname,
-                       do_stackless = not getattr(fnobj, 'isgchelper', False))]
+            return [FunctionCodeGenerator(fnobj.graph, db, cpython_exc, functionname)]
     elif getattr(fnobj, 'external', None) == 'C':
         # deprecated case
         if hasattr(fnobj, 'includes'):



More information about the Pypy-commit mailing list