[pypy-svn] r27153 - in pypy/dist/pypy: annotation rpython rpython/lltypesystem rpython/memory rpython/module translator translator/c translator/c/test translator/js translator/llvm translator/pyrex translator/stackless

arigo at codespeak.net arigo at codespeak.net
Fri May 12 20:13:10 CEST 2006


Author: arigo
Date: Fri May 12 20:13:02 2006
New Revision: 27153

Added:
   pypy/dist/pypy/translator/stackless/frame.py   (contents, props changed)
Modified:
   pypy/dist/pypy/annotation/description.py
   pypy/dist/pypy/rpython/extfunctable.py
   pypy/dist/pypy/rpython/lltypesystem/rclass.py
   pypy/dist/pypy/rpython/memory/gcwrapper.py
   pypy/dist/pypy/rpython/module/ll_stackless.py
   pypy/dist/pypy/rpython/rstack.py
   pypy/dist/pypy/translator/c/database.py
   pypy/dist/pypy/translator/c/genc.py
   pypy/dist/pypy/translator/c/pyobj.py
   pypy/dist/pypy/translator/c/test/test_database.py
   pypy/dist/pypy/translator/c/wrapper.py
   pypy/dist/pypy/translator/driver.py
   pypy/dist/pypy/translator/js/js.py
   pypy/dist/pypy/translator/llvm/genllvm.py
   pypy/dist/pypy/translator/pyrex/genpyrex.py
   pypy/dist/pypy/translator/stackless/code.py
   pypy/dist/pypy/translator/stackless/transform.py
Log:
* Clean-up of stackless transform; split code.py in two files;
  build compressed tables instead of having multiple fields in each
  frame header; use -1 instead of 0 as the non-resuming case so that
  the table entries computation can be 0-based

* Added a .clone method() on the RPython frame types, not implemented 
  yet.

* Replaced all abuses of "bookkeeper.getdesc(func).cachedgraph(None)"
  in the PyPy sources with a new method .getuniquegraph(), which asserts
  that there is exactly one graph and returns it, no matter under what
  key.  Indeed, cachedgraph() could also build and return a fresh graph,
  with was utterly confusing the later stages of the translation 
  process.


Modified: pypy/dist/pypy/annotation/description.py
==============================================================================
--- pypy/dist/pypy/annotation/description.py	(original)
+++ pypy/dist/pypy/annotation/description.py	Fri May 12 20:13:02 2006
@@ -191,6 +191,10 @@
             graph.name = alt_name
         return graph
 
+    def getuniquegraph(self):
+        assert len(self._cache) == 1
+        return self._cache.values()[0]
+
     def cachedgraph(self, key, alt_name=None, builder=None):
         try:
             return self._cache[key]

Modified: pypy/dist/pypy/rpython/extfunctable.py
==============================================================================
--- pypy/dist/pypy/rpython/extfunctable.py	(original)
+++ pypy/dist/pypy/rpython/extfunctable.py	Fri May 12 20:13:02 2006
@@ -253,7 +253,9 @@
 declare(rstack.stack_unwind, noneannotation, 'll_stack/unwind')
 frametop_type_info = declaregcptrtype(rstack.frame_stack_top,'frame_stack_top',
                                         switch = (rstack.frame_stack_top,
-                                                  'll_stackless/switch'))
+                                                  'll_stackless/switch'),
+                                        clone  = (rstack.frame_stack_top,
+                                                  'll_stackless/clone'))
 
 # ___________________________________________________________
 # javascript

Modified: pypy/dist/pypy/rpython/lltypesystem/rclass.py
==============================================================================
--- pypy/dist/pypy/rpython/lltypesystem/rclass.py	(original)
+++ pypy/dist/pypy/rpython/lltypesystem/rclass.py	Fri May 12 20:13:02 2006
@@ -364,7 +364,7 @@
                 source_repr = getinstancerepr(self.rtyper, source_classdef)
                 assert len(s_func.descriptions) == 1
                 funcdesc = s_func.descriptions.keys()[0]
-                graph = funcdesc.cachedgraph(None)
+                graph = funcdesc.getuniquegraph()
                 FUNCTYPE = FuncType([Ptr(source_repr.object_type)], Void)
                 destrptr = functionptr(FUNCTYPE, graph.name,
                                        graph=graph,

Modified: pypy/dist/pypy/rpython/memory/gcwrapper.py
==============================================================================
--- pypy/dist/pypy/rpython/memory/gcwrapper.py	(original)
+++ pypy/dist/pypy/rpython/memory/gcwrapper.py	Fri May 12 20:13:02 2006
@@ -163,7 +163,7 @@
     
 def getfunctionptr(annotator, graphfunc):
     """Make a functionptr from the given Python function."""
-    graph = annotator.bookkeeper.getdesc(graphfunc).cachedgraph(None)
+    graph = annotator.bookkeeper.getdesc(graphfunc).getuniquegraph()
     llinputs = [v.concretetype for v in graph.getargs()]
     lloutput = graph.getreturnvar().concretetype
     FT = lltype.FuncType(llinputs, lloutput)
@@ -293,12 +293,12 @@
         # convert constants
         fgcc = FlowGraphConstantConverter(a.translator.graphs)
         fgcc.convert()
-        self.malloc_graph = a.bookkeeper.getdesc(self.gc.malloc.im_func).cachedgraph(None)
-        self.write_barrier_graph = a.bookkeeper.getdesc(self.gc.write_barrier.im_func).cachedgraph(None)
+        self.malloc_graph = a.bookkeeper.getdesc(self.gc.malloc.im_func).getuniquegraph()
+        self.write_barrier_graph = a.bookkeeper.getdesc(self.gc.write_barrier.im_func).getuniquegraph()
 
         # create a gc via invoking instantiate_gc
         self.gcptr = self.llinterp.eval_graph(
-            a.bookkeeper.getdesc(instantiate_gc).cachedgraph(None))
+            a.bookkeeper.getdesc(instantiate_gc).getuniquegraph())
         GETROOTS_FUNCTYPE = lltype.typeOf(
             getfunctionptr(a, dummy_get_roots1)).TO
         setattr(self.gcptr, "inst_get_roots",

Modified: pypy/dist/pypy/rpython/module/ll_stackless.py
==============================================================================
--- pypy/dist/pypy/rpython/module/ll_stackless.py	(original)
+++ pypy/dist/pypy/rpython/module/ll_stackless.py	Fri May 12 20:13:02 2006
@@ -18,3 +18,10 @@
     else:
         return to_opaque_object(newframetop)
 ll_stackless_switch.suggested_primitive = True
+
+
+def ll_stackless_clone(opaqueframetop):
+    frametop = from_opaque_object(opaqueframetop)
+    newframetop = frametop.clone()
+    return to_opaque_object(newframetop)
+ll_stackless_clone.suggested_primitive = True

Modified: pypy/dist/pypy/rpython/rstack.py
==============================================================================
--- pypy/dist/pypy/rpython/rstack.py	(original)
+++ pypy/dist/pypy/rpython/rstack.py	Fri May 12 20:13:02 2006
@@ -29,3 +29,5 @@
 class frame_stack_top(object):
     def switch(self):
         raise NotImplementedError("only works in translated versions")
+    def clone(self):
+        raise NotImplementedError("only works in translated versions")

Modified: pypy/dist/pypy/translator/c/database.py
==============================================================================
--- pypy/dist/pypy/translator/c/database.py	(original)
+++ pypy/dist/pypy/translator/c/database.py	Fri May 12 20:13:02 2006
@@ -223,10 +223,13 @@
                     show_i += 1000
             work_to_do = False
             if not is_later_yet:
-                newgcdependencies = self.gctransformer.finish()
-                if newgcdependencies:
+                newdependencies = self.gctransformer.finish() or []
+                if self.stacklesstransformer:
+                    newdependencies2 = self.stacklesstransformer.finish() or []
+                    newdependencies.extend(newdependencies2)
+                if newdependencies:
                     work_to_do = True
-                    for value in newgcdependencies:
+                    for value in newdependencies:
                         if isinstance(typeOf(value), ContainerType):
                             self.getcontainernode(value)
                         else:

Modified: pypy/dist/pypy/translator/c/genc.py
==============================================================================
--- pypy/dist/pypy/translator/c/genc.py	(original)
+++ pypy/dist/pypy/translator/c/genc.py	Fri May 12 20:13:02 2006
@@ -182,7 +182,7 @@
         # XXX check that the entrypoint has the correct
         # signature:  list-of-strings -> int
         bk = self.translator.annotator.bookkeeper
-        return getfunctionptr(bk.getdesc(self.entrypoint).cachedgraph(None))
+        return getfunctionptr(bk.getdesc(self.entrypoint).getuniquegraph())
 
     def getccompiler(self, extra_includes):
         # XXX for now, we always include Python.h

Modified: pypy/dist/pypy/translator/c/pyobj.py
==============================================================================
--- pypy/dist/pypy/translator/c/pyobj.py	(original)
+++ pypy/dist/pypy/translator/c/pyobj.py	Fri May 12 20:13:02 2006
@@ -573,7 +573,7 @@
                         # this is the context where we create the instance.
                         ann = self.translator.annotator
                         clsdef = ann.bookkeeper.getuniqueclassdef(cls)
-                        graph = ann.bookkeeper.getdesc(func).cachedgraph(None)
+                        graph = ann.bookkeeper.getdesc(func).getuniquegraph()
                         if ann.binding(graph.getargs()[0]).classdef is not clsdef:
                             value = new_method_graph(graph, clsdef, fname, self.translator)
                     self.name_for_meth[value] = fname

Modified: pypy/dist/pypy/translator/c/test/test_database.py
==============================================================================
--- pypy/dist/pypy/translator/c/test/test_database.py	(original)
+++ pypy/dist/pypy/translator/c/test/test_database.py	Fri May 12 20:13:02 2006
@@ -176,7 +176,7 @@
     t.buildannotator().build_types(func, [int])
     t.buildrtyper().specialize()
     bk = t.annotator.bookkeeper
-    graph = bk.getdesc(func).cachedgraph(None)
+    graph = bk.getdesc(func).getuniquegraph()
     return t, graph
 
 def test_function_call():

Modified: pypy/dist/pypy/translator/c/wrapper.py
==============================================================================
--- pypy/dist/pypy/translator/c/wrapper.py	(original)
+++ pypy/dist/pypy/translator/c/wrapper.py	Fri May 12 20:13:02 2006
@@ -40,7 +40,7 @@
             do_inline = True
         else:
             bk = translator.annotator.bookkeeper
-            graph = bk.getdesc(func).cachedgraph(None)
+            graph = bk.getdesc(func).getuniquegraph()
 
     f = getfunctionptr(graph)
     FUNCTYPE = typeOf(f).TO

Modified: pypy/dist/pypy/translator/driver.py
==============================================================================
--- pypy/dist/pypy/translator/driver.py	(original)
+++ pypy/dist/pypy/translator/driver.py	Fri May 12 20:13:02 2006
@@ -318,7 +318,7 @@
         translator = self.translator
         interp = LLInterpreter(translator.rtyper)
         bk = translator.annotator.bookkeeper
-        graph = bk.getdesc(self.entry_point).cachedgraph(None)
+        graph = bk.getdesc(self.entry_point).getuniquegraph()
         v = interp.eval_graph(graph,
                               self.extra.get('get_llinterp_args',
                                              lambda: [])())

Modified: pypy/dist/pypy/translator/js/js.py
==============================================================================
--- pypy/dist/pypy/translator/js/js.py	(original)
+++ pypy/dist/pypy/translator/js/js.py	Fri May 12 20:13:02 2006
@@ -39,7 +39,7 @@
         self.graph = []
         for  func in self.functions:
             bk   = self.db.translator.annotator.bookkeeper
-            ptr  = getfunctionptr(bk.getdesc(func).cachedgraph(None))
+            ptr  = getfunctionptr(bk.getdesc(func).getuniquegraph())
             c    = inputconst(lltype.typeOf(ptr), ptr)
             self.db.prepare_arg(c)
             self.graph.append( self.db.obj2node[c.value._obj].graph )

Modified: pypy/dist/pypy/translator/llvm/genllvm.py
==============================================================================
--- pypy/dist/pypy/translator/llvm/genllvm.py	(original)
+++ pypy/dist/pypy/translator/llvm/genllvm.py	Fri May 12 20:13:02 2006
@@ -179,7 +179,7 @@
         self.entrypoint = func
 
         bk = self.translator.annotator.bookkeeper
-        ptr = getfunctionptr(bk.getdesc(func).cachedgraph(None))
+        ptr = getfunctionptr(bk.getdesc(func).getuniquegraph())
         c = inputconst(lltype.typeOf(ptr), ptr)
         self.db.prepare_arg_value(c)
         self.entry_func_name = func.func_name

Modified: pypy/dist/pypy/translator/pyrex/genpyrex.py
==============================================================================
--- pypy/dist/pypy/translator/pyrex/genpyrex.py	(original)
+++ pypy/dist/pypy/translator/pyrex/genpyrex.py	Fri May 12 20:13:02 2006
@@ -451,7 +451,7 @@
                 list_methods=delay_methods.get(cls,[])
                 for methdesc in list_methods:
                     # XXX!
-                    graph = methdesc.funcdesc.cachedgraph(None)
+                    graph = methdesc.funcdesc.getuniquegraph()
                     hackedargs = ', '.join([var.name for var in graph.getargs()])
                     name = graph.name.split('.')[-1]
                     self.putline("def %s(%s):" % (name, hackedargs))

Modified: pypy/dist/pypy/translator/stackless/code.py
==============================================================================
--- pypy/dist/pypy/translator/stackless/code.py	(original)
+++ pypy/dist/pypy/translator/stackless/code.py	Fri May 12 20:13:02 2006
@@ -1,51 +1,33 @@
 from pypy.rpython.lltypesystem import lltype, llmemory, lloperation
 from pypy.rpython import rarithmetic
 from pypy.rpython import extfunctable
-
-SAVED_REFERENCE = lltype.Ptr(lltype.GcOpaqueType('stackless.saved_ref'))
-null_saved_ref = lltype.nullptr(SAVED_REFERENCE.TO)
-
-STORAGE_TYPES = [lltype.Void, SAVED_REFERENCE, llmemory.Address,
-                 lltype.Signed, lltype.Float, lltype.SignedLongLong]
-
-STORAGE_FIELDS = {SAVED_REFERENCE: 'ref',
-                  llmemory.Address: 'addr',
-                  lltype.Signed: 'long',
-                  lltype.Float: 'float',
-                  lltype.SignedLongLong: 'longlong',
-                  }
-
-RETVAL_VOID = 0
-for _key, _value in STORAGE_FIELDS.items():
-    globals()['RETVAL_' + _value.upper()] = STORAGE_TYPES.index(_key)
+from pypy.translator.stackless import frame
+from pypy.translator.stackless.frame import STATE_HEADER, SAVED_REFERENCE
 
 # ____________________________________________________________
 
+SWITCH_STATE = frame.make_state_header_type('switch_state',
+                                            ('c', SAVED_REFERENCE))
+
 def ll_frame_switch(targetstate):
-    if global_state.restart_substate == 0:
+    if global_state.restart_substate == -1:
         # normal entry point for a call to state.switch()
         # first unwind the stack
         u = UnwindException()
         s = lltype.malloc(SWITCH_STATE)
-        s.header.restartstate = 1
-        # the next three lines are pure rtyper-pleasing hacks
-        f = ll_frame_switch
-        if global_state.restart_substate:
-            f = None
+        s.header.f_restart = INDEX_SWITCH
         s.c = lltype.cast_opaque_ptr(SAVED_REFERENCE, targetstate)
-        s.header.function = llmemory.cast_ptr_to_adr(f)
-        s.header.retval_type = RETVAL_REF
         add_frame_state(u, s.header)
         raise u
-    elif global_state.restart_substate == 1:
-        # STATE 1: we didn't do anything so far, but the stack is unwound
-        global_state.restart_substate = 0
+    elif global_state.restart_substate == 0:
+        # STATE 0: we didn't do anything so far, but the stack is unwound
+        global_state.restart_substate = -1
         # grab the frame corresponding to ourself, and prepare it for
-        # the future switch() back, which will go to STATE 2 below
+        # the future switch() back, which will go to STATE 1 below
         sourcestate = global_state.top
-        sourcestate.restartstate = 2
+        sourcestate.f_restart = INDEX_SWITCH + 1
         # the 'targetstate' local is garbage here, it must be read back from
-        # 's.c' where we saved it by STATE 0 above
+        # 's.c' where we saved it by the normal entry point above
         s = lltype.cast_pointer(lltype.Ptr(SWITCH_STATE), sourcestate)
         targetstate = lltype.cast_opaque_ptr(lltype.Ptr(STATE_HEADER), s.c)
         global_state.top = targetstate
@@ -53,118 +35,86 @@
                                                          sourcestate)
         raise UnwindException()   # this jumps to targetstate
     else:
-        # STATE 2: switching back into a tasklet suspended by
+        # STATE 1: switching back into a tasklet suspended by
         # a call to switch()
-        global_state.top = null_state
-        global_state.restart_substate = 0
-        origin_state = lltype.cast_opaque_ptr(OPAQUE_STATE_HEADER_PTR,
+        global_state.top = frame.null_state
+        global_state.restart_substate = -1
+        origin_state = lltype.cast_opaque_ptr(frame.OPAQUE_STATE_HEADER_PTR,
                                               fetch_retval_ref())
         return origin_state    # a normal return into the current tasklet,
                                # with the source state as return value
 ll_frame_switch.stackless_explicit = True
 
-STATE_HEADER = lltype.GcStruct('state_header',
-                               ('f_back',       lltype.Ptr(lltype.GcForwardReference())),
-                               ('restartstate', lltype.Signed),
-                               ('function',     llmemory.Address),
-                               ('retval_type',  lltype.Signed),
-                               adtmeths={'switch': ll_frame_switch})
-STATE_HEADER.f_back.TO.become(STATE_HEADER)
-
-null_state = lltype.nullptr(STATE_HEADER)
-
-OPAQUE_STATE_HEADER_PTR = lltype.Ptr(
-    extfunctable.frametop_type_info.get_lltype())
-
-##def decode_state(currentframe): 
-##    return (currentframe.function,
-##            currentframe.retval_type,
-##            currentframe.restartstate)
-##decode_state.stackless_explicit = True
-
-SWITCH_STATE = lltype.GcStruct('state_switch',
-                               ('header', STATE_HEADER),
-                               ('c', SAVED_REFERENCE))
+INDEX_SWITCH = frame.RestartInfo.add_prebuilt(ll_frame_switch, 2)
+
+# ____________________________________________________________
 
 def yield_current_frame_to_caller():
-    if global_state.restart_substate == 0:
+    if global_state.restart_substate == -1:
         # normal entry point for yield_current_frame_to_caller()
         # first unwind the stack
         u = UnwindException()
         s = lltype.malloc(STATE_HEADER)
-        s.restartstate = 1
-        # the next three lines are pure rtyper-pleasing hacks
-        f = yield_current_frame_to_caller
-        if global_state.restart_substate:
-            f = None
-        s.function = llmemory.cast_ptr_to_adr(f)
-        s.retval_type = RETVAL_REF
+        s.f_restart = INDEX_YCFTC
         add_frame_state(u, s)
-        raise u   # this goes to 'STATE 1' below
+        raise u   # this goes to 'STATE 0' below
 
-    elif global_state.restart_substate == 1:
-        # STATE 1: we didn't do anything so far, but the stack is unwound
-        global_state.restart_substate = 0
+    elif global_state.restart_substate == 0:
+        # STATE 0: we didn't do anything so far, but the stack is unwound
+        global_state.restart_substate = -1
         ycftc_state = global_state.top
         our_caller_state = ycftc_state.f_back
         caller_state = our_caller_state.f_back
-        # the next three lines are pure rtyper-pleasing hacks
-        f = yield_current_frame_to_caller
-        if global_state.restart_substate:
-            f = None
         # when our immediate caller finishes (which is later, when the
-        # tasklet finishes), then we will jump to 'STATE 2' below
+        # tasklet finishes), then we will jump to 'STATE 1' below
         endstate = lltype.malloc(STATE_HEADER)
-        endstate.restartstate = 2
-        endstate.function = llmemory.cast_ptr_to_adr(f)
+        endstate.f_restart = INDEX_YCFTC + 1
         our_caller_state.f_back = endstate
         global_state.top = caller_state
         global_state.retval_ref = lltype.cast_opaque_ptr(SAVED_REFERENCE,
                                                          our_caller_state)
         raise UnwindException()  # this goes to the caller's caller
 
-    elif global_state.restart_substate == 2:
-        # STATE 2: this is a slight abuse of yield_current_frame_to_caller(),
+    elif global_state.restart_substate == 1:
+        # STATE 1: this is a slight abuse of yield_current_frame_to_caller(),
         # as we return here when our immediate caller returns (and thus the
         # new tasklet finishes).
-        global_state.restart_substate = 0
+        global_state.restart_substate = -1
         next_state = lltype.cast_opaque_ptr(lltype.Ptr(STATE_HEADER),
                                             fetch_retval_ref())
         # return a NULL state pointer to the target of the implicit switch
         global_state.top = next_state
-        global_state.retval_ref = null_saved_ref
+        global_state.retval_ref = frame.null_saved_ref
         raise UnwindException()  # this goes to the switch target given by
                                  # the 'return' at the end of our caller
 
     else:
-        # STATE 3: this is never reached!  But the annotator doesn't know it,
+        # this is never reached!  But the annotator doesn't know it,
         # so it makes the whole function be annotated as returning a random
         # non-constant STATE_HEADER pointer.
-        return lltype.cast_opaque_ptr(OPAQUE_STATE_HEADER_PTR,
+        return lltype.cast_opaque_ptr(frame.OPAQUE_STATE_HEADER_PTR,
                                       global_state.top)
 
 yield_current_frame_to_caller.stackless_explicit = True
 
+INDEX_YCFTC = frame.RestartInfo.add_prebuilt(yield_current_frame_to_caller, 2)
+
+# ____________________________________________________________
+
 def stack_frames_depth():
-    if not global_state.restart_substate:
+    if global_state.restart_substate == -1:
         # normal entry point for stack_frames_depth()
         # first unwind the stack
         u = UnwindException()
         s = lltype.malloc(STATE_HEADER)
-        s.restartstate = 1
-        # the next three lines are pure rtyper-pleasing hacks
-        f = stack_frames_depth
-        if global_state.restart_substate:
-            f = None
-        s.function = llmemory.cast_ptr_to_adr(f)
-        s.retval_type = RETVAL_LONG
+        s.f_restart = INDEX_DEPTH
         add_frame_state(u, s)
-        raise u    # goes to STATE 1 below
+        raise u    # goes to STATE 0 below
     else:
-        # STATE 1: now the stack is unwound, and we can count the frames
+        # STATE 0: now the stack is unwound, and we can count the frames
         # in the heap
         cur = global_state.top
-        global_state.restart_substate = 0
+        global_state.restart_substate = -1
         depth = 0
         while cur:
             depth += 1
@@ -172,56 +122,60 @@
         return depth
 stack_frames_depth.stackless_explicit = True
 
+INDEX_DEPTH = frame.RestartInfo.add_prebuilt(stack_frames_depth, 1)
+
+# ____________________________________________________________
+
 def ll_stack_unwind():
-    if not global_state.restart_substate:
+    if global_state.restart_substate == -1:
         # normal entry point for stack_frames_depth()
         # first unwind the stack in the usual way
         u = UnwindException()
         s = lltype.malloc(STATE_HEADER)
-        s.restartstate = 1
-        # the next three lines are pure rtyper-pleasing hacks
-        f = ll_stack_unwind
-        if global_state.restart_substate:
-            f = None
-        s.function = llmemory.cast_ptr_to_adr(f)
-        s.retval_type = RETVAL_VOID
+        s.f_restart = INDEX_UNWIND
         add_frame_state(u, s)
-        raise u    # goes to STATE 1 below
+        raise u    # goes to STATE 0 below
     else:
-        # STATE 1: now the stack is unwound.  That was the goal.
+        # STATE 0: now the stack is unwound.  That was the goal.
         # Return to caller.
-        global_state.restart_substate = 0
+        global_state.restart_substate = -1
 ll_stack_unwind.stackless_explicit = True
 
+INDEX_UNWIND = frame.RestartInfo.add_prebuilt(ll_stack_unwind, 1)
+
+# ____________________________________________________________
+
 class StacklessData:
     def __init__(self):
-        self.top = null_state
-        self.restart_substate = 0
+        self.top = frame.null_state
+        self.restart_substate = -1
         self.retval_long = 0
         self.retval_longlong = rarithmetic.r_longlong(0)
         self.retval_float = 0.0
         self.retval_addr = llmemory.NULL
-        self.retval_ref = null_saved_ref
+        self.retval_ref = frame.null_saved_ref
         self.exception = None
+        self.masterarray = lltype.malloc(frame.FRAME_INFO_ARRAY, 0,
+                                         immortal=True)
 
 global_state = StacklessData()
 
 def call_function(fn, retval_code):
-    if retval_code == RETVAL_VOID:
+    if retval_code == frame.RETVAL_VOID:
         lloperation.llop.unsafe_call(lltype.Void, fn)
-    elif retval_code == RETVAL_REF:
+    elif retval_code == frame.RETVAL_REF:
         global_state.retval_ref = lloperation.llop.unsafe_call(
             SAVED_REFERENCE, fn)
-    elif retval_code == RETVAL_ADDR:
+    elif retval_code == frame.RETVAL_ADDR:
         global_state.retval_addr = lloperation.llop.unsafe_call(
             llmemory.Address, fn)
-    elif retval_code == RETVAL_LONG:
+    elif retval_code == frame.RETVAL_LONG:
         global_state.retval_long = lloperation.llop.unsafe_call(
             lltype.Signed, fn)
-    elif retval_code == RETVAL_FLOAT:
+    elif retval_code == frame.RETVAL_FLOAT:
         global_state.retval_float = lloperation.llop.unsafe_call(
             lltype.Float, fn)
-    elif retval_code == RETVAL_LONGLONG:
+    elif retval_code == frame.RETVAL_LONGLONG:
         global_state.retval_longlong = lloperation.llop.unsafe_call(
             lltype.SignedLongLong, fn)
 call_function.stackless_explicit = True
@@ -235,7 +189,8 @@
         # To switch manually to a different frame, code issues a regular
         # UnwindException first, to empty the C stack, and then issues a
         # (XXX complete this comment)
-        self.frame_bottom = null_state
+        self.frame_bottom = frame.null_state
+    __init__.stackless_explicit = True
 
 def slp_main_loop():
     """
@@ -244,12 +199,12 @@
     pending = global_state.top
     
     while True:
-        back                          = pending.f_back
-        fn                            = pending.function
-        signature                     = pending.retval_type
-        global_state.restart_substate = pending.restartstate
+        back = pending.f_back
+        decoded = frame.decodestate(global_state.masterarray,
+                                    pending.f_restart)
+        (fn, global_state.restart_substate, retval_type) = decoded
         try:
-            call_function(fn, signature)
+            call_function(fn, retval_type)
         except UnwindException, u:   #XXX annotation support needed
             if u.frame_bottom:
                 u.frame_bottom.f_back = back
@@ -274,22 +229,6 @@
         u.frame_bottom = frame_state
 add_frame_state.stackless_explicit = True
 
-def resume_state():
-    """Return and zero the 'restart_substate', the index of the resume
-    point to jump to or zero for the not resuming case."""
-    x = global_state.restart_substate
-    global_state.restart_substate = 0
-    return x 
-resume_state.stackless_explicit = True
-
-# XXX would like to be able to say
-#def resume_header():
-#    x = global_state.restart_substate
-#    if x:
-#        top = global_state.top
-#        global_state.top = None
-# XXX and then insert the rtyped graph of this into functions
-        
 def fetch_retval_void():
     e = global_state.exception
     if e:
@@ -342,6 +281,6 @@
         raise e
     else:
         res = global_state.retval_ref
-        global_state.retval_ref = null_saved_ref
+        global_state.retval_ref = frame.null_saved_ref
         return res
 fetch_retval_ref.stackless_explicit = True

Added: pypy/dist/pypy/translator/stackless/frame.py
==============================================================================
--- (empty file)
+++ pypy/dist/pypy/translator/stackless/frame.py	Fri May 12 20:13:02 2006
@@ -0,0 +1,144 @@
+from pypy.rpython.lltypesystem import lltype, llmemory
+from pypy.rpython import extfunctable
+from pypy.rpython.typesystem import getfunctionptr
+from pypy.objspace.flow.model import FunctionGraph
+
+# ____________________________________________________________
+# generic data types
+
+SAVED_REFERENCE = lltype.Ptr(lltype.GcOpaqueType('stackless.saved_ref'))
+null_saved_ref = lltype.nullptr(SAVED_REFERENCE.TO)
+
+STORAGE_TYPES = [lltype.Void, SAVED_REFERENCE, llmemory.Address,
+                 lltype.Signed, lltype.Float, lltype.SignedLongLong]
+
+STORAGE_FIELDS = {SAVED_REFERENCE: 'ref',
+                  llmemory.Address: 'addr',
+                  lltype.Signed: 'long',
+                  lltype.Float: 'float',
+                  lltype.SignedLongLong: 'longlong',
+                  }
+
+RETVAL_VOID = 0
+for _key, _value in STORAGE_FIELDS.items():
+    globals()['RETVAL_' + _value.upper()] = STORAGE_TYPES.index(_key)
+
+def storage_type(T):
+    """Return the 'erased' storage type corresponding to T.
+    """
+    if T is lltype.Void:
+        return lltype.Void
+    elif isinstance(T, lltype.Ptr):
+        if T._needsgc():
+            return SAVED_REFERENCE
+        else:
+            return llmemory.Address
+    elif T is lltype.Float:
+        return lltype.Float
+    elif T in [lltype.SignedLongLong, lltype.UnsignedLongLong]:
+        return lltype.SignedLongLong
+    elif T is llmemory.Address:
+        return llmemory.Address
+    elif isinstance(T, lltype.Primitive):
+        return lltype.Signed
+    else:
+        raise Exception("don't know about %r" % (T,))
+
+# ____________________________________________________________
+# structures for saved frame states
+
+STATE_HEADER = lltype.GcStruct('state_header',
+                           ('f_back', lltype.Ptr(lltype.GcForwardReference())),
+                           ('f_restart', lltype.Signed))
+STATE_HEADER.f_back.TO.become(STATE_HEADER)
+
+null_state = lltype.nullptr(STATE_HEADER)
+
+OPAQUE_STATE_HEADER_PTR = lltype.Ptr(
+    extfunctable.frametop_type_info.get_lltype())
+
+
+def make_state_header_type(name, *fields):
+##    source = ['def ll_reccopy_%s(frame):' % name,
+##              '    if frame.f_back:'
+##              '        prev = frame.f_back.XXX',
+##              '    newframe = lltype.malloc(lltype.typeOf(FRAME))',
+##              '    newframe.']
+    
+##    copynames = [name for (name, _) in fields]
+##    copynames.append('header.restartstate')
+##    copynames.append('header.function')
+##    copynames.append('header.retval_type')
+##    for name in copynames:
+##        source.append('    newframe.%s = frame.%s' % (name, name))
+##    source.append('    return newframe')
+##    source.append('')
+##    miniglobals = {'lltype': lltype}
+##    exec compile2('\n'.join(source)) in miniglobals
+##    extras = {
+##        'adtmeths': {'reccopy': miniglobals['ll_frame_reccopy']}
+##        }
+    return lltype.GcStruct(name,
+                           ('header', STATE_HEADER),
+                           *fields)
+
+# ____________________________________________________________
+# master array giving information about the restart points
+# (STATE_HEADER.frameinfo is an index into this array)
+
+FRAME_INFO = lltype.Struct('frame_info',
+                           ('fnaddr', llmemory.Address),
+                           ('info',   lltype.Signed))
+FRAME_INFO_ARRAY = lltype.Array(FRAME_INFO)
+
+def decodestate(masterarray, index):
+    finfo = masterarray[index]
+    if finfo.fnaddr:
+        restartstate = 0
+    else:
+        restartstate = finfo.info
+        finfo = masterarray[index - restartstate]
+    return (finfo.fnaddr,  # function ptr
+            restartstate,  # restart state within function
+            finfo.info)    # retval_type
+decodestate.stackless_explicit = True
+
+
+class RestartInfo(object):
+    __slots__ = ['func_or_graph',
+                 'first_index',
+                 'nb_restart_states']
+
+    def __init__(self, func_or_graph, first_index, nb_restart_states):
+        self.func_or_graph = func_or_graph
+        self.first_index = first_index
+        self.nb_restart_states = nb_restart_states
+
+    def compress(self, rtyper, masterarray):
+        if self.nb_restart_states > 0:
+            graph = self.func_or_graph
+            if not isinstance(graph, FunctionGraph):
+                bk = rtyper.annotator.bookkeeper
+                graph = bk.getdesc(graph).getuniquegraph()
+            funcptr = getfunctionptr(graph)
+            rettype = lltype.typeOf(funcptr).TO.RESULT
+            retval_type = STORAGE_TYPES.index(storage_type(rettype))
+
+            finfo = masterarray[self.first_index]
+            finfo.fnaddr = llmemory.cast_ptr_to_adr(funcptr)
+            finfo.info = retval_type
+            for i in range(1, self.nb_restart_states):
+                finfo = masterarray[self.first_index+i]
+                finfo.info = i
+
+    prebuilt = []
+    prebuiltindex = 0
+
+    def add_prebuilt(cls, func, nb_restart_states):
+        assert func.stackless_explicit    # did you forget this flag?
+        n = cls.prebuiltindex
+        restart = cls(func, n, nb_restart_states)
+        cls.prebuilt.append(restart)
+        cls.prebuiltindex += restart.nb_restart_states
+        return n
+    add_prebuilt = classmethod(add_prebuilt)

Modified: pypy/dist/pypy/translator/stackless/transform.py
==============================================================================
--- pypy/dist/pypy/translator/stackless/transform.py	(original)
+++ pypy/dist/pypy/translator/stackless/transform.py	Fri May 12 20:13:02 2006
@@ -6,37 +6,17 @@
 from pypy.translator import unsimplify
 from pypy.annotation import model as annmodel
 from pypy.rpython.annlowlevel import MixLevelHelperAnnotator
-from pypy.translator.stackless import code
-from pypy.translator.stackless.code import SAVED_REFERENCE, STORAGE_TYPES
-from pypy.translator.stackless.code import STORAGE_FIELDS
+from pypy.translator.stackless import code, frame
 from pypy.rpython.rclass import getinstancerepr
 from pypy.rpython.rbuiltin import gen_cast
 from pypy.rpython.rtyper import LowLevelOpList
 from pypy.rpython.module import ll_stackless, ll_stack
 from pypy.translator.backendopt import graphanalyze
 
-from pypy.translator.stackless.code import STATE_HEADER, null_state
-
-def storage_type(T):
-    """Return the 'erased' storage type corresponding to T.
-    """
-    if T is lltype.Void:
-        return lltype.Void
-    elif isinstance(T, lltype.Ptr):
-        if T._needsgc():
-            return SAVED_REFERENCE
-        else:
-            return llmemory.Address
-    elif T is lltype.Float:
-        return lltype.Float
-    elif T in [lltype.SignedLongLong, lltype.UnsignedLongLong]:
-        return lltype.SignedLongLong
-    elif T is llmemory.Address:
-        return llmemory.Address
-    elif isinstance(T, lltype.Primitive):
-        return lltype.Signed
-    else:
-        raise Exception("don't know about %r" % (T,))
+from pypy.translator.stackless.frame import SAVED_REFERENCE, STORAGE_TYPES
+from pypy.translator.stackless.frame import STORAGE_FIELDS
+from pypy.translator.stackless.frame import STATE_HEADER, null_state
+from pypy.translator.stackless.frame import storage_type
 
 # a simple example of what the stackless transform does
 #
@@ -44,29 +24,31 @@
 #     return g() + x + 1
 #
 # STATE_func_0 = lltype.Struct('STATE_func_0',
-#                              ('header', code.STATE_HEADER),
+#                              ('header', STATE_HEADER),
 #                              ('saved_long_0', Signed))
 #
 # def func(x):
 #     state = global_state.restart_substate
-#     global_state.restart_substate = 0
-#     if state == 0:   # normal case
+#     if state == -1:   # normal case
 #         try:
 #             retval = g(x)
 #         except code.UnwindException, u:
 #             state = lltype.malloc(STATE_func_0)
-#             state.header.restartstate = 1
-#             state.header.function = llmemory.cast_ptr_to_adr(func)
-#             state.header.retval_type = code.RETVAL_LONG
+#             state.header.f_restart = <index in array of frame.FRAMEINFO>
 #             state.saved_long_0 = x
 #             code.add_frame_state(u, state.header)
 #             raise
-#     elif state == 1:
+#     elif state == 0:
+#         global_state.restart_substate = -1
 #         state = lltype.cast_pointer(lltype.Ptr(STATE_func_0),
 #                                     global_state.top)
 #         global_state.top = null_state
 #         x = state.saved_long_0
 #         retval = code.fetch_retval_long() # can raise an exception
+#     elif state == 1:
+#         ...
+#     elif state == 2:
+#         ...
 #     else:
 #         abort()
 #     return retval + x + 1
@@ -104,9 +86,7 @@
             for t in STORAGE_TYPES:
                 for j in range(counts.get(t, 0)):
                     fields.append(('state_%s_%d' % (STORAGE_FIELDS[t], j), t))
-            T = lltype.GcStruct("FrameState",
-                                ('header', STATE_HEADER),
-                                *fields)
+            T = frame.make_state_header_type("FrameState", *fields)
             self.frametypes[key] = T
         return T, fieldnames
 
@@ -140,6 +120,8 @@
         self.translator = translator
 
         self.frametyper = FrameTyper()
+        self.restartinfos = frame.RestartInfo.prebuilt[:]
+        self.restartinfoindex = frame.RestartInfo.prebuiltindex
         self.curr_graph = None
         
         bk = translator.annotator.bookkeeper
@@ -150,6 +132,13 @@
         self.analyzer = StacklessAnalyzer(translator,
                                           self.unwind_exception_type)
 
+        # the point of this little dance is to not annotate
+        # code.global_state.masterarray as a constant.
+        data_classdef = bk.getuniqueclassdef(code.StacklessData)
+        data_classdef.generalize_attr(
+            'masterarray',
+            annmodel.SomePtr(lltype.Ptr(frame.FRAME_INFO_ARRAY)))
+
         mixlevelannotator = MixLevelHelperAnnotator(translator.rtyper)
         l2a = annmodel.lltype_to_annotation
 
@@ -163,7 +152,7 @@
         slp_entry_point.stackless_explicit = True
 
         self.slp_entry_point = slp_entry_point
-        oldgraph = bk.getdesc(entrypoint).cachedgraph(None)
+        oldgraph = bk.getdesc(entrypoint).getuniquegraph()
         s_argv = translator.annotator.binding(oldgraph.getargs()[0])
         self.slp_entry_point_ptr = mixlevelannotator.constfunc(
             slp_entry_point, [s_argv], annmodel.SomeInteger())
@@ -175,9 +164,6 @@
              annmodel.SomePtr(lltype.Ptr(STATE_HEADER))],
             l2a(lltype.Void))
 
-        self.resume_state_ptr = mixlevelannotator.constfunc(
-            code.resume_state, [], annmodel.SomeInteger())
-
         self.fetch_retvals = {
             lltype.Void: mixlevelannotator.constfunc(
                 code.fetch_retval_void, [], annmodel.s_None),
@@ -193,7 +179,7 @@
                 code.fetch_retval_ref, [], annmodel.SomePtr(SAVED_REFERENCE)),
             }
 
-        s_StatePtr = annmodel.SomePtr(code.OPAQUE_STATE_HEADER_PTR)
+        s_StatePtr = annmodel.SomePtr(frame.OPAQUE_STATE_HEADER_PTR)
         self.suggested_primitives = {
             ll_stackless.ll_stackless_stack_frames_depth:
                 mixlevelannotator.constfunc(
@@ -217,9 +203,19 @@
             r_global_state.lowleveltype)
         self.seen_blocks = set()
 
+        # some prebuilt constants to save memory
+        self.c_restart_substate_name = model.Constant("inst_restart_substate",
+                                                      lltype.Void)
+        self.c_inst_top_name = model.Constant("inst_top", lltype.Void)
+        self.c_f_restart_name = model.Constant("f_restart", lltype.Void)
+        self.c_minus_one = model.Constant(-1, lltype.Signed)
+        self.c_null_state = model.Constant(null_state,
+                                           lltype.typeOf(null_state))
+
     def transform_all(self):
         for graph in self.translator.graphs:
             self.transform_graph(graph)
+        self.finish()
         
     def transform_graph(self, graph):
         self.resume_points = []
@@ -241,6 +237,7 @@
 
         if self.resume_points:
             self.insert_resume_handling(graph)
+            self.generate_restart_infos(graph)
 
         model.checkgraph(graph)
 
@@ -274,23 +271,28 @@
         new_start_block = model.Block(newinputargs)
         var_resume_state = varoftype(lltype.Signed)
         new_start_block.operations.append(
-            model.SpaceOperation("direct_call",
-                                 [self.resume_state_ptr],
+            model.SpaceOperation("getfield",
+                                 [self.ll_global_state,
+                                  self.c_restart_substate_name],
                                  var_resume_state))
-        not_resuming_link = model.Link(newinputargs, old_start_block, 0)
-        not_resuming_link.llexitcase = 0
+        not_resuming_link = model.Link(newinputargs, old_start_block, -1)
+        not_resuming_link.llexitcase = -1
         resuming_links = []
         for resume_point_index, resume_point in enumerate(self.resume_points):
             newblock = model.Block([])
             newargs = []
             llops = LowLevelOpList()
+            llops.genop("setfield",
+                        [self.ll_global_state,
+                         self.c_restart_substate_name,
+                         self.c_minus_one])
             frame_state_type = resume_point.frame_state_type
             frame_top = varoftype(lltype.Ptr(frame_state_type))
             llops.extend(self.ops_read_global_state_field(frame_top, "top"))
             llops.genop("setfield",
                        [self.ll_global_state,
-                        model.Constant("inst_top", lltype.Void),
-                        model.Constant(null_state, lltype.typeOf(null_state))])
+                        self.c_inst_top_name,
+                        self.c_null_state])
             varmap = {}
             for i, arg in enumerate(resume_point.args):
                 assert arg is not resume_point.var_result
@@ -351,8 +353,8 @@
                 # end ouch!
             
             resuming_links.append(
-                model.Link([], newblock, resume_point_index+1))
-            resuming_links[-1].llexitcase = resume_point_index+1
+                model.Link([], newblock, resume_point_index))
+            resuming_links[-1].llexitcase = resume_point_index
         new_start_block.exitswitch = var_resume_state
         new_start_block.closeblock(not_resuming_link, *resuming_links)
 
@@ -499,24 +501,11 @@
             [self.add_frame_state_ptr, var_exc, var_header],
             varoftype(lltype.Void)))
 
+        f_restart = self.restartinfoindex + len(self.resume_points)
         saveops.append(model.SpaceOperation(
             "setfield",
-            [var_header, model.Constant("restartstate", lltype.Void), 
-             model.Constant(len(self.resume_points)+1, lltype.Signed)],
-            varoftype(lltype.Void)))
-
-        funcptr = rtyper.type_system.getcallable(self.curr_graph)
-        saveops.append(model.SpaceOperation(
-            "setfield",
-            [var_header, model.Constant("function", lltype.Void), 
-             model.Constant(llmemory.fakeaddress(funcptr), llmemory.Address)],
-            varoftype(lltype.Void)))
-        rettype = lltype.typeOf(funcptr).TO.RESULT
-        retval_type = STORAGE_TYPES.index(storage_type(rettype))
-
-        saveops.append(model.SpaceOperation(
-            "setfield", [var_header, model.Constant("retval_type", lltype.Void), 
-                         model.Constant(retval_type, lltype.Signed)],
+            [var_header, self.c_f_restart_name,
+             model.Constant(f_restart, lltype.Signed)],
             varoftype(lltype.Void)))
 
         type_repr = rclass.get_type_repr(rtyper)
@@ -544,3 +533,23 @@
             v_typeerased = gen_cast(llops, t, var)
             llops.genop('setfield', [frame_state_var, fname, v_typeerased])
         return llops
+
+    def generate_restart_infos(self, graph):
+        restartinfo = frame.RestartInfo(graph, self.restartinfoindex,
+                                        len(self.resume_points))
+        self.restartinfos.append(restartinfo)
+        self.restartinfoindex += len(self.resume_points)
+
+    def finish(self):
+        # compute the final masterarray
+        masterarray = lltype.malloc(frame.FRAME_INFO_ARRAY,
+                                    self.restartinfoindex,
+                                    immortal=True)
+        rtyper = self.translator.rtyper
+        for restartinfo in self.restartinfos:
+            restartinfo.compress(rtyper, masterarray)
+        # horrors in the same spirit as in rpython.memory.gctransform
+        # (shorter, though)
+        ll_global_state = self.ll_global_state.value
+        ll_global_state.inst_masterarray = masterarray
+        return [masterarray]



More information about the Pypy-commit mailing list