[pypy-svn] r9848 - pypy/dist/pypy/translator

arigo at codespeak.net arigo at codespeak.net
Thu Mar 17 12:30:54 CET 2005


Author: arigo
Date: Thu Mar 17 12:30:54 2005
New Revision: 9848

Added:
   pypy/dist/pypy/translator/genc_funcdef.py
      - copied, changed from r9754, pypy/dist/pypy/translator/genc.py
Modified:
   pypy/dist/pypy/translator/genc.h
   pypy/dist/pypy/translator/genc.py
Log:
Split genc.py in two files, genc.py and genc_funcdef.py.  The latter contains
a FunctionDef class whose instances care about a single function.  It's
slightly less messy now.  As a first application, we generate direct C-to-C
calls instead of OP_SIMPLE_CALL() when possible.  This allows most function to
be compiled into a single C function, instead of a C function plus a
CPython-API-compatible wrapper.


Modified: pypy/dist/pypy/translator/genc.h
==============================================================================
--- pypy/dist/pypy/translator/genc.h	(original)
+++ pypy/dist/pypy/translator/genc.h	Thu Mar 17 12:30:54 2005
@@ -16,10 +16,7 @@
 
 static PyObject *this_module_globals;
 
-/* Set this if you want call trace frames to be built */
-#if 0
-#define USE_CALL_TRACE
-#endif
+/* Set genc_funcdef.USE_CALL_TRACE if you want call trace frames to be built */
 
 #if 0
 #define OBNOXIOUS_PRINT_STATEMENTS
@@ -177,10 +174,8 @@
 
 #if defined(USE_CALL_TRACE)
 
-#define TRACE_CALL       __f, __tstate,
-#define TRACE_ARGS       PyFrameObject *__f, PyThreadState *__tstate,
-#define TRACE_CALL_VOID  __f, __tstate
-#define TRACE_ARGS_VOID  PyFrameObject *__f, PyThreadState *__tstate
+#define TRACE_CALL       __f, __tstate
+#define TRACE_ARGS       PyFrameObject *__f, PyThreadState *__tstate
 
 #define FAIL(err) { __f->f_lineno = __f->f_code->co_firstlineno = __LINE__; goto err; }
 
@@ -198,19 +193,10 @@
 
 #else /* !defined(USE_CALL_TRACE) */
 
-#define TRACE_CALL       /* nothing */
-#define TRACE_ARGS       /* nothing */
-#define TRACE_CALL_VOID  /* nothing */
-#define TRACE_ARGS_VOID  void
-
 #define FAIL(err) { goto err; }
 
-#define FUNCTION_HEAD(signature, self, args, names, file, line)
-
 #define ERR_DECREF(arg) { Py_DECREF(arg); }
 
-#define FUNCTION_CHECK()
-
 #define FUNCTION_RETURN(rval) return rval;
 
 #endif /* defined(USE_CALL_TRACE) */

Modified: pypy/dist/pypy/translator/genc.py
==============================================================================
--- pypy/dist/pypy/translator/genc.py	(original)
+++ pypy/dist/pypy/translator/genc.py	Thu Mar 17 12:30:54 2005
@@ -4,20 +4,16 @@
 """
 from __future__ import generators
 import autopath, os, sys, __builtin__, marshal, zlib
-from pypy.objspace.flow.model import Variable, Constant, SpaceOperation
-from pypy.objspace.flow.model import FunctionGraph, Block, Link
-from pypy.objspace.flow.model import last_exception, last_exc_value
-from pypy.objspace.flow.model import traverse, uniqueitems, checkgraph
-from pypy.translator.simplify import remove_direct_loops
-from pypy.interpreter.pycode import CO_VARARGS
-from pypy.annotation import model as annmodel
+from pypy.objspace.flow.model import Variable, Constant
 from types import FunctionType, CodeType, InstanceType, ClassType
 
-from pypy.translator.gensupp import ordered_blocks, UniqueList, builtin_base, \
-     c_string, uniquemodulename, C_IDENTIFIER, NameManager
+from pypy.translator.gensupp import builtin_base, uniquemodulename
+from pypy.translator.gensupp import NameManager
 
 from pypy.objspace.std.restricted_int import r_int, r_uint
 
+from pypy.translator.genc_funcdef import FunctionDef, USE_CALL_TRACE
+
 # ____________________________________________________________
 
 #def go_figure_out_this_name(source):
@@ -70,7 +66,8 @@
         self.globaldecl = []
         self.globalobjects = []
         self.pendingfunctions = []
-        self.currentfunc = None
+        self.funcdefs = {}
+        self.allfuncdefs = []
         self.debugstack = ()  # linked list of nested nameof()
         self.gen_source()
 
@@ -179,6 +176,14 @@
         self.initcode.append('  raise NotImplementedError')
         return name
 
+    def getfuncdef(self, func):
+        if func not in self.funcdefs:
+            funcdef = FunctionDef(func, self)
+            self.funcdefs[func] = funcdef
+            self.allfuncdefs.append(funcdef)
+            self.pendingfunctions.append(funcdef)
+        return self.funcdefs[func]
+
     def nameof_function(self, func, progress=['-\x08', '\\\x08',
                                               '|\x08', '/\x08']):
         printable_name = '(%s:%d) %s' % (
@@ -197,9 +202,8 @@
             p = progress.pop(0)
             sys.stderr.write(p)
             progress.append(p)
-        name = self.uniquename('gfunc_' + func.__name__)
-        self.pendingfunctions.append(func)
-        return name
+        funcdef = self.getfuncdef(func)
+        return funcdef.get_globalobject()
 
     def nameof_staticmethod(self, sm):
         # XXX XXX XXXX
@@ -455,12 +459,14 @@
             'entrypoint': self.nameof(self.translator.functions[0]),
             }
         # header
+        if USE_CALL_TRACE:
+            print >> f, '#define USE_CALL_TRACE'
         print >> f, self.C_HEADER
 
         # function implementations
         while self.pendingfunctions:
-            func = self.pendingfunctions.pop()
-            self.gen_cfunction(func)
+            funcdef = self.pendingfunctions.pop()
+            self.gen_cfunction(funcdef)
             # collect more of the latercode after each function
             while self.latercode:
                 gen, self.debugstack = self.latercode.pop()
@@ -470,7 +476,12 @@
                 self.debugstack = ()
             self.gen_global_declarations()
 
-        # after all the functions: global object table
+        # after all the ff_xxx() functions we generate the pyff_xxx() wrappers
+        for funcdef in self.allfuncdefs:
+            if funcdef.wrapper_name is not None:
+                funcdef.gen_wrapper(f)
+
+        # global object table
         print >> f, self.C_OBJECT_TABLE
         for name in self.globalobjects:
             if not name.startswith('gfunc_'):
@@ -479,11 +490,13 @@
 
         # global function table
         print >> f, self.C_FUNCTION_TABLE
-        for name in self.globalobjects:
-            if name.startswith('gfunc_'):
-                print >> f, ('\t{&%s, {"%s", (PyCFunction)f_%s, '
+        for funcdef in self.allfuncdefs:
+            if funcdef.globalobject_name is not None:
+                print >> f, ('\t{&%s, {"%s", (PyCFunction)%s, '
                              'METH_VARARGS|METH_KEYWORDS}},' % (
-                    name, name[6:], name[6:]))
+                    funcdef.globalobject_name,
+                    funcdef.base_name,
+                    funcdef.wrapper_name))
         print >> f, self.C_TABLE_END
 
         # frozen init bytecode
@@ -534,293 +547,25 @@
         del source
         return marshal.dumps(co)
     
-    def gen_cfunction(self, func):
+    def gen_cfunction(self, funcdef):
 ##         print 'gen_cfunction (%s:%d) %s' % (
 ##             func.func_globals.get('__name__', '?'),
 ##             func.func_code.co_firstlineno,
 ##             func.__name__)
 
-        f = self.f
-        localscope = self.namespace.localScope()
-        body = list(self.cfunction_body(func, localscope))
-        name_of_defaults = [self.nameof(x, debug=('Default argument of', func))
-                            for x in (func.func_defaults or ())]
-        self.gen_global_declarations()
-
-        # print header
-        cname = self.nameof(func)
-        assert cname.startswith('gfunc_')
-        f_name = 'f_' + cname[6:]
-
-        # collect all the local variables
-        graph = self.translator.getflowgraph(func)
-        localslst = []
-        def visit(node):
-            if isinstance(node, Block):
-                localslst.extend(node.getvariables())
-        traverse(visit, graph)
-        localnames = [self.expr(a, localscope) for a in uniqueitems(localslst)]
-
-        # collect all the arguments
-        if func.func_code.co_flags & CO_VARARGS:
-            vararg = graph.getargs()[-1]
-            positional_args = graph.getargs()[:-1]
-        else:
-            vararg = None
-            positional_args = graph.getargs()
-        min_number_of_args = len(positional_args) - len(name_of_defaults)
-
-        fast_args = [self.expr(a, localscope) for a in positional_args]
-        if vararg is not None:
-            vararg = self.expr(vararg, localscope)
-            fast_args.append(vararg)
-        fast_name = 'fast' + f_name
-
-        fast_set = dict(zip(fast_args, fast_args))
-
-        declare_fast_args = [('PyObject *' + a) for a in fast_args]
-        if declare_fast_args:
-            declare_fast_args = 'TRACE_ARGS ' + ', '.join(declare_fast_args)
-        else:
-            declare_fast_args = 'TRACE_ARGS_VOID'
-        fast_function_header = ('static PyObject *\n'
-                                '%s(%s)' % (fast_name, declare_fast_args))
-
-        print >> f, fast_function_header + ';'  # forward
-        print >> f
-
-        print >> f, 'static PyObject *'
-        print >> f, '%s(PyObject* self, PyObject* args, PyObject* kwds)' % (
-            f_name,)
-        print >> f, '{'
-        print >> f, '\tFUNCTION_HEAD(%s, %s, args, %s, __FILE__, __LINE__ - 2)' % (
-            c_string('%s(%s)' % (cname, ', '.join(name_of_defaults))),
-            cname,
-            '(%s)' % (', '.join(map(c_string, name_of_defaults) + ['NULL']),),
-        )
-
-        kwlist = ['"%s"' % name for name in
-                      func.func_code.co_varnames[:func.func_code.co_argcount]]
-        kwlist.append('0')
-        print >> f, '\tstatic char* kwlist[] = {%s};' % (', '.join(kwlist),)
-
-        if fast_args:
-            print >> f, '\tPyObject *%s;' % (', *'.join(fast_args))
-        print >> f
-
-        print >> f, '\tFUNCTION_CHECK()'
-
-        # argument unpacking
-        if vararg is not None:
-            print >> f, '\t%s = PyTuple_GetSlice(args, %d, INT_MAX);' % (
-                vararg, len(positional_args))
-            print >> f, '\tif (%s == NULL)' % (vararg,)
-            print >> f, '\t\tFUNCTION_RETURN(NULL)'
-            print >> f, '\targs = PyTuple_GetSlice(args, 0, %d);' % (
-                len(positional_args),)
-            print >> f, '\tif (args == NULL) {'
-            print >> f, '\t\tERR_DECREF(%s)' % (vararg,)
-            print >> f, '\t\tFUNCTION_RETURN(NULL)'
-            print >> f, '\t}'
-            tail = """{
-\t\tERR_DECREF(args)
-\t\tERR_DECREF(%s)
-\t\tFUNCTION_RETURN(NULL);
-\t}
-\tPy_DECREF(args);""" % vararg
-        else:
-            tail = '\n\t\tFUNCTION_RETURN(NULL)'
-        for i in range(len(name_of_defaults)):
-            print >> f, '\t%s = %s;' % (
-                self.expr(positional_args[min_number_of_args+i], localscope),
-                name_of_defaults[i])
-        fmt = 'O'*min_number_of_args
-        if min_number_of_args < len(positional_args):
-            fmt += '|' + 'O'*(len(positional_args)-min_number_of_args)
-        lst = ['args', 'kwds',
-               '"%s:%s"' % (fmt, func.__name__),
-               'kwlist',
-               ]
-        lst += ['&' + self.expr(a, localscope) for a in positional_args]
-        print >> f, '\tif (!PyArg_ParseTupleAndKeywords(%s))' % ', '.join(lst),
-        print >> f, tail
-
-        call_fast_args = list(fast_args)
-        if call_fast_args:
-            call_fast_args = 'TRACE_CALL ' + ', '.join(call_fast_args)
-        else:
-            call_fast_args = 'TRACE_CALL_VOID'
-        print >> f, '\treturn %s(%s);' % (fast_name, call_fast_args)
-        print >> f, '}'
-        print >> f
-
-        print >> f, fast_function_header
-        print >> f, '{'
-
-        fast_locals = [arg for arg in localnames if arg not in fast_set]
-        if fast_locals:
-            print >> f, '\tPyObject *%s;' % (', *'.join(fast_locals),)
-            print >> f
-        
-        # generate an incref for each input argument
-        for v in positional_args:
-            print >> f, '\tPy_INCREF(%s);' % self.expr(v, localscope)
-
-        # print the body
-        for line in body:
-            if line.endswith(':'):
-                if line.startswith('err'):
-                    fmt = '\t%s'
-                else:
-                    fmt = '    %s\n'
-            elif line:
-                fmt = '\t%s\n'
-            else:
-                fmt = '%s\n'
-            f.write(fmt % line)
-        print >> f, '}'
+        # compute the whole body
+        body = list(funcdef.cfunction_body())
+
+        # generate the source now
+        self.gen_global_declarations() #.. before the body where they are needed
+        funcdef.gen_cfunction(self.f, body)
 
+        # this is only to keep the RAM consumption under control
+        funcdef.clear()
         if not self.translator.frozen:
-            # this is only to keep the RAM consumption under control
-            del self.translator.flowgraphs[func]
+            del self.translator.flowgraphs[funcdef.func]
             Variable.instances.clear()
 
-    def expr(self, v, localscope):
-        if isinstance(v, Variable):
-            return localscope.localname(v.name)
-        elif isinstance(v, Constant):
-            return self.nameof(v.value,
-                               debug=('Constant in the graph of', self.currentfunc))
-        else:
-            raise TypeError, "expr(%r)" % (v,)
-
-    def cfunction_body(self, func, localscope):
-        graph = self.translator.getflowgraph(func)
-        remove_direct_loops(graph)
-        checkgraph(graph)
-
-        blocknum = {}
-        allblocks = []
-
-        def gen_link(link, linklocalvars=None):
-            "Generate the code to jump across the given Link."
-            has_ref = {}
-            linklocalvars = linklocalvars or {}
-            for v in to_release:
-                linklocalvars[v] = self.expr(v, localscope)
-            has_ref = linklocalvars.copy()
-            for a1, a2 in zip(link.args, link.target.inputargs):
-                if a1 in linklocalvars:
-                    src = linklocalvars[a1]
-                else:
-                    src = self.expr(a1, localscope)
-                line = 'MOVE(%s, %s)' % (src, self.expr(a2, localscope))
-                if a1 in has_ref:
-                    del has_ref[a1]
-                else:
-                    line += '\tPy_INCREF(%s);' % self.expr(a2, localscope)
-                yield line
-            for v in has_ref:
-                yield 'Py_DECREF(%s);' % linklocalvars[v]
-            yield 'goto block%d;' % blocknum[link.target]
-
-        # collect all blocks
-        def visit(block):
-            if isinstance(block, Block):
-                allblocks.append(block)
-                blocknum[block] = len(blocknum)
-        traverse(visit, graph)
-
-        # generate the body of each block
-        for block in allblocks:
-            yield ''
-            yield 'block%d:' % blocknum[block]
-            to_release = list(block.inputargs)
-            for op in block.operations:
-                lst = [self.expr(v, localscope) for v in op.args]
-                lst.append(self.expr(op.result, localscope))
-                lst.append('err%d_%d' % (blocknum[block], len(to_release)))
-                macro = 'OP_%s' % op.opname.upper()
-                meth = getattr(self, macro, None)
-                if meth:
-                    yield meth(lst[:-2], lst[-2], lst[-1])
-                else:
-                    yield '%s(%s)' % (macro, ', '.join(lst))
-                to_release.append(op.result)
-
-            err_reachable = False
-            if len(block.exits) == 0:
-                if len(block.inputargs) == 2:   # exc_cls, exc_value
-                    # exceptional return block
-                    exc_cls   = self.expr(block.inputargs[0], localscope)
-                    exc_value = self.expr(block.inputargs[1], localscope)
-                    yield 'PyErr_Restore(%s, %s, NULL);' % (exc_cls, exc_value)
-                    yield 'FUNCTION_RETURN(NULL)'
-                else:
-                    # regular return block
-                    retval = self.expr(block.inputargs[0], localscope)
-                    yield 'FUNCTION_RETURN(%s)' % retval
-                continue
-            elif block.exitswitch is None:
-                # single-exit block
-                assert len(block.exits) == 1
-                for op in gen_link(block.exits[0]):
-                    yield op
-                yield ''
-            elif block.exitswitch == Constant(last_exception):
-                # block catching the exceptions raised by its last operation
-                # we handle the non-exceptional case first
-                link = block.exits[0]
-                assert link.exitcase is None
-                for op in gen_link(link):
-                    yield op
-                # we must catch the exception raised by the last operation,
-                # which goes to the last err%d_%d label written above.
-                yield ''
-                to_release.pop()  # skip default error handling for this label
-                yield 'err%d_%d:' % (blocknum[block], len(to_release))
-                yield ''
-                for link in block.exits[1:]:
-                    assert issubclass(link.exitcase, Exception)
-                    yield 'if (PyErr_ExceptionMatches(%s)) {' % (
-                        self.nameof(link.exitcase),)
-                    yield '\tPyObject *exc_cls, *exc_value, *exc_tb;'
-                    yield '\tPyErr_Fetch(&exc_cls, &exc_value, &exc_tb);'
-                    yield '\tif (exc_value == NULL) {'
-                    yield '\t\texc_value = Py_None;'
-                    yield '\t\tPy_INCREF(Py_None);'
-                    yield '\t}'
-                    yield '\tPy_XDECREF(exc_tb);'
-                    for op in gen_link(link, {
-                                Constant(last_exception): 'exc_cls',
-                                Constant(last_exc_value): 'exc_value'}):
-                        yield '\t' + op
-                    yield '}'
-                err_reachable = True
-            else:
-                # block ending in a switch on a value
-                for link in block.exits[:-1]:
-                    yield 'if (EQ_%s(%s)) {' % (link.exitcase,
-                                                self.expr(block.exitswitch, localscope))
-                    for op in gen_link(link):
-                        yield '\t' + op
-                    yield '}'
-                link = block.exits[-1]
-                yield 'assert(EQ_%s(%s));' % (link.exitcase,
-                                              self.expr(block.exitswitch, localscope))
-                for op in gen_link(block.exits[-1]):
-                    yield op
-                yield ''
-
-            while to_release:
-                v = to_release.pop()
-                if err_reachable:
-                    yield 'ERR_DECREF(%s)' % self.expr(v, localscope)
-                yield 'err%d_%d:' % (blocknum[block], len(to_release))
-                err_reachable = True
-            if err_reachable:
-                yield 'FUNCTION_RETURN(NULL)'
-
 # ____________________________________________________________
 
     C_HEADER = '#include "genc.h"\n'
@@ -853,46 +598,3 @@
 \tSETUP_MODULE(%(modname)s)
 \tPyModule_AddObject(m, "%(entrypointname)s", %(entrypoint)s);
 }'''
-
-    # the C preprocessor cannot handle operations taking a variable number
-    # of arguments, so here are Python methods that do it
-    
-    def OP_NEWLIST(self, args, r, err):
-        if len(args) == 0:
-            return 'OP_NEWLIST0(%s, %s)' % (r, err)
-        else:
-            args.insert(0, '%d' % len(args))
-            return 'OP_NEWLIST((%s), %s, %s)' % (', '.join(args), r, err)
-
-    def OP_NEWDICT(self, args, r, err):
-        if len(args) == 0:
-            return 'OP_NEWDICT0(%s, %s)' % (r, err)
-        else:
-            assert len(args) % 2 == 0
-            args.insert(0, '%d' % (len(args)//2))
-            return 'OP_NEWDICT((%s), %s, %s)' % (', '.join(args), r, err)
-
-    def OP_NEWTUPLE(self, args, r, err):
-        args.insert(0, '%d' % len(args))
-        return 'OP_NEWTUPLE((%s), %s, %s)' % (', '.join(args), r, err)
-
-    def OP_SIMPLE_CALL(self, args, r, err):
-        args.append('NULL')
-        return 'OP_SIMPLE_CALL((%s), %s, %s)' % (', '.join(args), r, err)
-
-    def OP_CALL_ARGS(self, args, r, err):
-        return 'OP_CALL_ARGS((%s), %s, %s)' % (', '.join(args), r, err)
-
-# ____________________________________________________________
-
-def cdecl(type, name):
-    # Utility to generate a typed name declaration in C syntax.
-    # For local variables, struct fields, function declarations, etc.
-    # For complex C types, the 'type' can contain a '@' character that
-    # specifies where the 'name' should be inserted; for example, an
-    # array of 10 ints has a type of "int @[10]".
-    if '@' in type:
-        return type.replace('@', name)
-    else:
-        return ('%s %s' % (type, name)).rstrip()
-

Copied: pypy/dist/pypy/translator/genc_funcdef.py (from r9754, pypy/dist/pypy/translator/genc.py)
==============================================================================
--- pypy/dist/pypy/translator/genc.py	(original)
+++ pypy/dist/pypy/translator/genc_funcdef.py	Thu Mar 17 12:30:54 2005
@@ -1,565 +1,56 @@
-"""
-Generate a C source file from the flowmodel.
-
-"""
 from __future__ import generators
-import autopath, os, sys, __builtin__, marshal, zlib
-from pypy.objspace.flow.model import Variable, Constant, SpaceOperation
-from pypy.objspace.flow.model import FunctionGraph, Block, Link
-from pypy.objspace.flow.model import last_exception, last_exc_value
+from pypy.objspace.flow.model import Variable, Constant
 from pypy.objspace.flow.model import traverse, uniqueitems, checkgraph
+from pypy.objspace.flow.model import Block, Link
+from pypy.objspace.flow.model import last_exception, last_exc_value
 from pypy.translator.simplify import remove_direct_loops
 from pypy.interpreter.pycode import CO_VARARGS
-from pypy.annotation import model as annmodel
-from types import FunctionType, CodeType, InstanceType, ClassType
+from types import FunctionType
 
-from pypy.translator.gensupp import ordered_blocks, UniqueList, builtin_base, \
-     c_string, uniquemodulename, C_IDENTIFIER, NameManager
+from pypy.translator.gensupp import c_string
 
-from pypy.objspace.std.restricted_int import r_int, r_uint
 
-# ____________________________________________________________
+# Set this if you want call trace frames to be built
+USE_CALL_TRACE = False
 
-#def go_figure_out_this_name(source):
-#    # ahem
-#    return 'PyRun_String("%s", Py_eval_input, PyEval_GetGlobals(), NULL)' % (
-#        source, )
-
-class GenC:
-    MODNAMES = {}
-
-    def __init__(self, f, translator, modname=None, f2=None):
-        self.f = f
-        self.f2 = f2
-        self.translator = translator
-        self.modname = (modname or
-                        uniquemodulename(translator.functions[0].__name__))
-        self.cnames = {Constant(None).key:  'Py_None',
-                       Constant(False).key: 'Py_False',
-                       Constant(True).key:  'Py_True',
-                       }
-        self.seennames = {}
-        self.initcode = [      # list of lines for the module's initxxx()
-            'import new, types, sys',
-            'Py_None  = None',
-            'Py_False = False',
-            'Py_True  = True',
-            ]
-
-        self.latercode = []    # list of generators generating extra lines
-                               #   for later in initxxx() -- for recursive
-                               #   objects
-        self.namespace= NameManager()
-        # keywords cannot be reused.  This is the C99 draft's list.
-        self.namespace.make_reserved_names('''
-           auto      enum      restrict  unsigned
-           break     extern    return    void
-           case      float     short     volatile
-           char      for       signed    while
-           const     goto      sizeof    _Bool
-           continue  if        static    _Complex
-           default   inline    struct    _Imaginary
-           do        int       switch
-           double    long      typedef
-           else      register  union
-           ''')
-        # these names are used in function headers,
-        # therefore pseudo-preserved in scope 1:
-        self.namespace.make_reserved_names('self args kwds')
-
-        self.globaldecl = []
-        self.globalobjects = []
-        self.pendingfunctions = []
-        self.currentfunc = None
-        self.debugstack = ()  # linked list of nested nameof()
-        self.gen_source()
-
-    def nameof(self, obj, debug=None):
-        key = Constant(obj).key
-        try:
-            return self.cnames[key]
-        except KeyError:
-            if debug:
-                stackentry = debug, obj
-            else:
-                stackentry = obj
-            self.debugstack = (self.debugstack, stackentry)
-            obj_builtin_base = builtin_base(obj)
-            if obj_builtin_base in (object, int, long) and type(obj) is not obj_builtin_base:
-                # assume it's a user defined thingy
-                name = self.nameof_instance(obj)
-            else:
-                for cls in type(obj).__mro__:
-                    meth = getattr(self,
-                                   'nameof_' + cls.__name__.replace(' ', ''),
-                                   None)
-                    if meth:
-                        break
-                else:
-                    raise Exception, "nameof(%r)" % (obj,)
-                name = meth(obj)
-            self.debugstack, x = self.debugstack
-            assert x is stackentry
-            self.cnames[key] = name
-            return name
-
-    def uniquename(self, basename):
-        name = self.namespace.uniquename(basename)
-        self.globalobjects.append(name)
-        self.globaldecl.append('static PyObject *%s;' % (name,))
-        return name
-
-    def initcode_python(self, name, pyexpr):
-        # generate init code that will evaluate the given Python expression
-        #self.initcode.append("print 'setting up', %r" % name)
-        self.initcode.append("%s = %s" % (name, pyexpr))
-
-    def nameof_object(self, value):
-        if type(value) is not object:
-            raise Exception, "nameof(%r)" % (value,)
-        name = self.uniquename('g_object')
-        self.initcode_python(name, "object()")
-        return name
-
-    def nameof_module(self, value):
-        assert value is os or not hasattr(value, "__file__") or \
-               not (value.__file__.endswith('.pyc') or
-                    value.__file__.endswith('.py') or
-                    value.__file__.endswith('.pyo')), \
-               "%r is not a builtin module (probably :)"%value
-        name = self.uniquename('mod%s'%value.__name__)
-        self.initcode_python(name, "__import__(%r)" % (value.__name__,))
-        return name
-        
 
-    def nameof_int(self, value):
-        if value >= 0:
-            name = 'gint_%d' % value
-        else:
-            name = 'gint_minus%d' % abs(value)
-        name = self.uniquename(name)
-        self.initcode_python(name, repr(value))
-        return name
-
-    def nameof_long(self, value):
-        if value >= 0:
-            name = 'glong%d' % value
-        else:
-            name = 'glong_minus%d' % abs(value)
-        name = self.uniquename(name)
-        self.initcode_python(name, repr(value))
-        return name
-
-    def nameof_float(self, value):
-        name = 'gfloat_%s' % value
-        name = (name.replace('-', 'minus')
-                    .replace('.', 'dot'))
-        name = self.uniquename(name)
-        self.initcode_python(name, repr(value))
-        return name
-
-    def nameof_str(self, value):
-        name = self.uniquename('gstr_' + value[:32])
-##        if [c for c in value if c<' ' or c>'~' or c=='"' or c=='\\']:
-##            # non-printable string
-##            s = 'chr_%s' % name
-##            self.globaldecl.append('static char %s[] = { %s };' % (
-##                s, ', '.join(['%d' % ord(c) for c in value])))
-##        else:
-##            # printable string
-##            s = '"%s"' % value
-        self.initcode_python(name, repr(value))
-        return name
-
-    def skipped_function(self, func):
-        # debugging only!  Generates a placeholder for missing functions
-        # that raises an exception when called.
-        name = self.uniquename('gskippedfunc_' + func.__name__)
-        self.initcode.append('def %s(*a,**k):' % name)
-        self.initcode.append('  raise NotImplementedError')
-        return name
-
-    def nameof_function(self, func, progress=['-\x08', '\\\x08',
-                                              '|\x08', '/\x08']):
-        printable_name = '(%s:%d) %s' % (
-            func.func_globals.get('__name__', '?'),
-            func.func_code.co_firstlineno,
-            func.__name__)
-        if self.translator.frozen:
-            if func not in self.translator.flowgraphs:
-                print "NOT GENERATING", printable_name
-                return self.skipped_function(func)
-        else:
-            if (func.func_doc and
-                func.func_doc.lstrip().startswith('NOT_RPYTHON')):
-                print "skipped", printable_name
-                return self.skipped_function(func)
-            p = progress.pop(0)
-            sys.stderr.write(p)
-            progress.append(p)
-        name = self.uniquename('gfunc_' + func.__name__)
-        self.pendingfunctions.append(func)
-        return name
-
-    def nameof_staticmethod(self, sm):
-        # XXX XXX XXXX
-        func = sm.__get__(42.5)
-        name = self.uniquename('gsm_' + func.__name__)
-        functionname = self.nameof(func)
-        self.initcode_python(name, 'staticmethod(%s)' % functionname)
-        return name
-
-    def nameof_instancemethod(self, meth):
-        if meth.im_self is None:
-            # no error checking here
-            return self.nameof(meth.im_func)
-        else:
-            ob = self.nameof(meth.im_self)
-            func = self.nameof(meth.im_func)
-            typ = self.nameof(meth.im_class)
-            name = self.uniquename('gmeth_'+meth.im_func.__name__)
-            self.initcode_python(name, 'new.instancemethod(%s, %s, %s)' % (
-                func, ob, typ))
-            return name
-
-    def should_translate_attr(self, pbc, attr):
-        ann = self.translator.annotator
-        if ann is None:
-            ignore = getattr(pbc.__class__, 'NOT_RPYTHON_ATTRIBUTES', [])
-            if attr in ignore:
-                return False
-            else:
-                return "probably"   # True
-        classdef = ann.getuserclasses().get(pbc.__class__)
-        if classdef and classdef.about_attribute(attr) is not None:
-            return True
-        return False
-
-    def later(self, gen):
-        self.latercode.append((gen, self.debugstack))
-
-    def nameof_instance(self, instance):
-        klass = instance.__class__
-        name = self.uniquename('ginst_' + klass.__name__)
-        cls = self.nameof(klass)
-        if hasattr(klass, '__base__'):
-            base_class = builtin_base(instance)
-            base = self.nameof(base_class)
-        else:
-            base_class = None
-            base = cls
-        def initinstance():
-            content = instance.__dict__.items()
-            content.sort()
-            for key, value in content:
-                if self.should_translate_attr(instance, key):
-                    line = '%s.%s = %s' % (name, key, self.nameof(value))
-                    yield line
-        if hasattr(instance,'__reduce_ex__'):
-            import copy_reg
-            reduced = instance.__reduce_ex__()
-            assert reduced[0] is copy_reg._reconstructor,"not clever enough"
-            assert reduced[1][1] is base_class, "not clever enough for %r vs. %r" % (base_class, reduced)
-            state = reduced[1][2]
-        else:
-            state = None
-        self.initcode.append('if isinstance(%s, type):' % cls)
-        if state is not None:
-            self.initcode.append('    %s = %s.__new__(%s, %r)' % (name, base, cls, state))
-        else:
-            self.initcode.append('    %s = %s.__new__(%s)' % (name, base, cls))
-        self.initcode.append('else:')
-        self.initcode.append('    %s = new.instance(%s)' % (name, cls))
-        self.later(initinstance())
-        return name
-
-    def nameof_builtin_function_or_method(self, func):
-        if func.__self__ is None:
-            # builtin function
-            # where does it come from? Python2.2 doesn't have func.__module__
-            for modname, module in sys.modules.items():
-                if hasattr(module, '__file__'):
-                    if (module.__file__.endswith('.py') or
-                        module.__file__.endswith('.pyc') or
-                        module.__file__.endswith('.pyo')):
-                        continue    # skip non-builtin modules
-                if func is getattr(module, func.__name__, None):
-                    break
-            else:
-                raise Exception, '%r not found in any built-in module' % (func,)
-            name = self.uniquename('gbltin_' + func.__name__)
-            if modname == '__builtin__':
-                self.initcode_python(name, func.__name__)
-            else:
-                modname = self.nameof(module)
-                self.initcode_python(name, '%s.%s' % (modname, func.__name__))
-        else:
-            # builtin (bound) method
-            name = self.uniquename('gbltinmethod_' + func.__name__)
-            selfname = self.nameof(func.__self__)
-            self.initcode_python(name, '%s.%s' % (selfname, func.__name__))
-        return name
-
-    def nameof_classobj(self, cls):
-        if cls.__doc__ and cls.__doc__.lstrip().startswith('NOT_RPYTHON'):
-            raise Exception, "%r should never be reached" % (cls,)
-
-        metaclass = "type"
-        if issubclass(cls, Exception):
-            if cls.__module__ == 'exceptions':
-                name = self.uniquename('gexc_' + cls.__name__)
-                self.initcode_python(name, cls.__name__)
-                return name
-            #else:
-            #    # exceptions must be old-style classes (grr!)
-            #    metaclass = "&PyClass_Type"
-        # For the moment, use old-style classes exactly when the
-        # pypy source uses old-style classes, to avoid strange problems.
-        if not isinstance(cls, type):
-            assert type(cls) is ClassType
-            metaclass = "types.ClassType"
-
-        name = self.uniquename('gcls_' + cls.__name__)
-        basenames = [self.nameof(base) for base in cls.__bases__]
-        def initclassobj():
-            content = cls.__dict__.items()
-            content.sort()
-            for key, value in content:
-                if key.startswith('__'):
-                    if key in ['__module__', '__doc__', '__dict__',
-                               '__weakref__', '__repr__', '__metaclass__']:
-                        continue
-                    # XXX some __NAMES__ are important... nicer solution sought
-                    #raise Exception, "unexpected name %r in class %s"%(key, cls)
-                if isinstance(value, staticmethod) and value.__get__(1) not in self.translator.flowgraphs and self.translator.frozen:
-                    print value
-                    continue
-                if isinstance(value, classmethod) and value.__get__(cls).__doc__.lstrip().startswith("NOT_RPYTHON"):
-                    continue
-                if isinstance(value, FunctionType) and value not in self.translator.flowgraphs and self.translator.frozen:
-                    print value
-                    continue
-                    
-                yield '%s.%s = %s' % (name, key, self.nameof(value))
-
-        baseargs = ", ".join(basenames)
-        if baseargs:
-            baseargs = '(%s)' % baseargs
-        self.initcode.append('class %s%s:' % (name, baseargs))
-        self.initcode.append('  __metaclass__ = %s' % metaclass)
-        self.later(initclassobj())
-        return name
-
-    nameof_class = nameof_classobj   # for Python 2.2
-
-    typename_mapping = {
-        InstanceType: 'types.InstanceType',
-        type(None):   'type(None)',
-        CodeType:     'types.CodeType',
-        type(sys):    'type(new)',
-
-        r_int:        'int',   # XXX
-        r_uint:       'int',   # XXX
-
-        # XXX more hacks
-        # type 'builtin_function_or_method':
-        type(len): 'type(len)',
-        # type 'method_descriptor':
-        type(list.append): 'type(list.append)',
-        # type 'wrapper_descriptor':
-        type(type(None).__repr__): 'type(type(None).__repr__)',
-        # type 'getset_descriptor':
-        type(type.__dict__['__dict__']): "type(type.__dict__['__dict__'])",
-        # type 'member_descriptor':
-        type(type.__dict__['__basicsize__']): "type(type.__dict__['__basicsize__'])",
-        }
-
-    def nameof_type(self, cls):
-        if cls.__module__ != '__builtin__':
-            return self.nameof_classobj(cls)   # user-defined type
-        name = self.uniquename('gtype_%s' % cls.__name__)
-        if getattr(__builtin__, cls.__name__, None) is cls:
-            expr = cls.__name__    # type available from __builtin__
-        else:
-            expr = self.typename_mapping[cls]
-        self.initcode_python(name, expr)
-        return name
-
-    def nameof_tuple(self, tup):
-        name = self.uniquename('g%dtuple' % len(tup))
-        args = [self.nameof(x) for x in tup]
-        args = ', '.join(args)
-        if args:
-            args += ','
-        self.initcode_python(name, '(%s)' % args)
-        return name
-
-    def nameof_list(self, lis):
-        name = self.uniquename('g%dlist' % len(lis))
-        def initlist():
-            for i in range(len(lis)):
-                item = self.nameof(lis[i])
-                yield '%s.append(%s)' % (name, item)
-        self.initcode_python(name, '[]')
-        self.later(initlist())
-        return name
-
-    def nameof_dict(self, dic):
-        assert dic is not __builtins__
-        assert '__builtins__' not in dic, 'Seems to be the globals of %s' % (
-            dic.get('__name__', '?'),)
-        name = self.uniquename('g%ddict' % len(dic))
-        def initdict():
-            for k in dic:
-                if type(k) is str:
-                    yield '%s[%r] = %s' % (name, k, self.nameof(dic[k]))
-                else:
-                    yield '%s[%s] = %s' % (name, self.nameof(k),
-                                           self.nameof(dic[k]))
-        self.initcode_python(name, '{}')
-        self.later(initdict())
-        return name
-
-    # strange prebuilt instances below, don't look too closely
-    # XXX oh well.
-    def nameof_member_descriptor(self, md):
-        name = self.uniquename('gdescriptor_%s_%s' % (
-            md.__objclass__.__name__, md.__name__))
-        cls = self.nameof(md.__objclass__)
-        self.initcode_python(name, '%s.__dict__[%r]' % (cls, md.__name__))
-        return name
-    nameof_getset_descriptor  = nameof_member_descriptor
-    nameof_method_descriptor  = nameof_member_descriptor
-    nameof_wrapper_descriptor = nameof_member_descriptor
-
-    def nameof_file(self, fil):
-        if fil is sys.stdin:
-            name = self.uniquename("gsys_stdin")
-            self.initcode_python(name, "sys.stdin")
-            return name
-        if fil is sys.stdout:
-            name = self.uniquename("gsys_stdout")
-            self.initcode_python(name, "sys.stdout")
-            return name
-        if fil is sys.stderr:
-            name = self.uniquename("gsys_stderr")
-            self.initcode_python(name, "sys.stderr")
-            return name
-        raise Exception, 'Cannot translate an already-open file: %r' % (fil,)
-
-    def gen_source(self):
-        f = self.f
-        info = {
-            'modname': self.modname,
-            'entrypointname': self.translator.functions[0].__name__,
-            'entrypoint': self.nameof(self.translator.functions[0]),
-            }
-        # header
-        print >> f, self.C_HEADER
-
-        # function implementations
-        while self.pendingfunctions:
-            func = self.pendingfunctions.pop()
-            self.gen_cfunction(func)
-            # collect more of the latercode after each function
-            while self.latercode:
-                gen, self.debugstack = self.latercode.pop()
-                #self.initcode.extend(gen) -- eats TypeError! bad CPython!
-                for line in gen:
-                    self.initcode.append(line)
-                self.debugstack = ()
-            self.gen_global_declarations()
-
-        # after all the functions: global object table
-        print >> f, self.C_OBJECT_TABLE
-        for name in self.globalobjects:
-            if not name.startswith('gfunc_'):
-                print >> f, '\t{&%s, "%s"},' % (name, name)
-        print >> f, self.C_TABLE_END
-
-        # global function table
-        print >> f, self.C_FUNCTION_TABLE
-        for name in self.globalobjects:
-            if name.startswith('gfunc_'):
-                print >> f, ('\t{&%s, {"%s", (PyCFunction)f_%s, '
-                             'METH_VARARGS|METH_KEYWORDS}},' % (
-                    name, name[6:], name[6:]))
-        print >> f, self.C_TABLE_END
-
-        # frozen init bytecode
-        print >> f, self.C_FROZEN_BEGIN
-        bytecode = self.getfrozenbytecode()
-        def char_repr(c):
-            if c in '\\"': return '\\' + c
-            if ' ' <= c < '\x7F': return c
-            return '\\%03o' % ord(c)
-        for i in range(0, len(bytecode), 32):
-            print >> f, ''.join([char_repr(c) for c in bytecode[i:i+32]])+'\\'
-            if (i+32) % 1024 == 0:
-                print >> f, self.C_FROZEN_BETWEEN
-        print >> f, self.C_FROZEN_END
-        print >> f, "#define FROZEN_INITCODE_SIZE %d" % len(bytecode)
-
-        # the footer proper: the module init function */
-        print >> f, self.C_FOOTER % info
-
-    def gen_global_declarations(self):
-        g = self.globaldecl
-        if g:
-            f = self.f
-            print >> f, '/* global declaration%s */' % ('s'*(len(g)>1))
-            for line in g:
-                print >> f, line
-            print >> f
-            del g[:]
-        if self.f2 is not None:
-            for line in self.initcode:
-                print >> self.f2, line
-            del self.initcode[:]
-
-    def getfrozenbytecode(self):
-        if self.f2 is not None:
-            self.f2.seek(0)
-            self.initcode.insert(0, self.f2.read())
-        self.initcode.append('')
-        source = '\n'.join(self.initcode)
-        del self.initcode[:]
-        co = compile(source, self.modname, 'exec')
-        del source
-        small = zlib.compress(marshal.dumps(co))
-        source = """if 1:
-            import zlib, marshal
-            exec marshal.loads(zlib.decompress(%r))""" % small
-        co = compile(source, self.modname, 'exec')
-        del source
-        return marshal.dumps(co)
-    
-    def gen_cfunction(self, func):
-##         print 'gen_cfunction (%s:%d) %s' % (
-##             func.func_globals.get('__name__', '?'),
-##             func.func_code.co_firstlineno,
-##             func.__name__)
-
-        f = self.f
-        localscope = self.namespace.localScope()
-        body = list(self.cfunction_body(func, localscope))
-        name_of_defaults = [self.nameof(x, debug=('Default argument of', func))
-                            for x in (func.func_defaults or ())]
-        self.gen_global_declarations()
+class FunctionDef:
+    """
+    Collects information about a function which we have to generate.
+    The operations of each function are collected in a C function
+    with signature:
 
-        # print header
-        cname = self.nameof(func)
-        assert cname.startswith('gfunc_')
-        f_name = 'f_' + cname[6:]
+        static PyObject *fn_xxx(PyObject *arg1, PyObject *arg2, etc);
+
+    If needed, another wrapper function is created with a signature
+    suitable for the built-in function type of CPython:
+
+        static PyObject *pyfn_xxx(PyObject *self, PyObject *args);
+
+    The built-in function object, if needed, is put in the global
+    variable named gfn_xxx.
+    """
+
+    def __init__(self, func, genc):
+        self.func = func
+        self.genc = genc
+
+        # get the function name
+        namespace = genc.namespace
+        self.fast_name = namespace.uniquename('fn_' + func.__name__) # fn_xxx
+        self.base_name = self.fast_name[3:]                          # xxx
+        self.wrapper_name = None                                     # pyfn_xxx
+        self.globalobject_name = None                                # gfunc_xxx
+        self.localscope = namespace.localScope()
+        self.graph = graph = genc.translator.getflowgraph(func)
 
         # collect all the local variables
-        graph = self.translator.getflowgraph(func)
         localslst = []
         def visit(node):
             if isinstance(node, Block):
                 localslst.extend(node.getvariables())
         traverse(visit, graph)
-        localnames = [self.expr(a, localscope) for a in uniqueitems(localslst)]
+        self.localnames = [self.expr(a) for a in uniqueitems(localslst)]
 
         # collect all the arguments
         if func.func_code.co_flags & CO_VARARGS:
@@ -568,47 +59,89 @@
         else:
             vararg = None
             positional_args = graph.getargs()
-        min_number_of_args = len(positional_args) - len(name_of_defaults)
 
-        fast_args = [self.expr(a, localscope) for a in positional_args]
+        fast_args = [self.expr(a) for a in positional_args]
         if vararg is not None:
-            vararg = self.expr(vararg, localscope)
+            vararg = self.expr(vararg)
             fast_args.append(vararg)
-        fast_name = 'fast' + f_name
-
-        fast_set = dict(zip(fast_args, fast_args))
 
         declare_fast_args = [('PyObject *' + a) for a in fast_args]
-        if declare_fast_args:
-            declare_fast_args = 'TRACE_ARGS ' + ', '.join(declare_fast_args)
-        else:
-            declare_fast_args = 'TRACE_ARGS_VOID'
+        if USE_CALL_TRACE:
+            declare_fast_args.insert(0, 'TRACE_ARGS')
+        declare_fast_args = ', '.join(declare_fast_args) or 'void'
         fast_function_header = ('static PyObject *\n'
-                                '%s(%s)' % (fast_name, declare_fast_args))
+                                '%s(%s)' % (self.fast_name, declare_fast_args))
 
-        print >> f, fast_function_header + ';'  # forward
-        print >> f
+        name_of_defaults = [self.genc.nameof(x, debug=('Default argument of',
+                                                       self))
+                            for x in (func.func_defaults or ())]
+
+        # store misc. information
+        self.fast_function_header = fast_function_header
+        self.fast_args = fast_args
+        self.fast_set = dict(zip(fast_args, fast_args))
+        self.vararg = vararg
+        self.positional_args = positional_args
+        self.name_of_defaults = name_of_defaults
+
+        # generate the forward header
+        self.genc.globaldecl.append(fast_function_header + ';  /* forward */')
+
+
+    def get_globalobject(self):
+        if self.globalobject_name is None:
+            self.wrapper_name = 'py' + self.fast_name
+            self.globalobject_name = self.genc.uniquename('gfunc_' +
+                                                          self.base_name)
+        return self.globalobject_name
+
+    def clear(self):
+        del self.localscope
+        del self.localnames
+        del self.fast_set
+        del self.graph
+
+    def expr(self, v):
+        if isinstance(v, Variable):
+            return self.localscope.localname(v.name)
+        elif isinstance(v, Constant):
+            return self.genc.nameof(v.value,
+                                    debug=('Constant in the graph of', self))
+        else:
+            raise TypeError, "expr(%r)" % (v,)
 
+    # ____________________________________________________________
+
+    def gen_wrapper(self, f):
+        func             = self.func
+        f_name           = self.wrapper_name
+        positional_args  = self.positional_args
+        vararg           = self.vararg
+        name_of_defaults = self.name_of_defaults
+
+        min_number_of_args = len(self.positional_args) - len(name_of_defaults)
         print >> f, 'static PyObject *'
         print >> f, '%s(PyObject* self, PyObject* args, PyObject* kwds)' % (
             f_name,)
         print >> f, '{'
-        print >> f, '\tFUNCTION_HEAD(%s, %s, args, %s, __FILE__, __LINE__ - 2)' % (
-            c_string('%s(%s)' % (cname, ', '.join(name_of_defaults))),
-            cname,
-            '(%s)' % (', '.join(map(c_string, name_of_defaults) + ['NULL']),),
-        )
+        if USE_CALL_TRACE:
+            print >> f, '\tFUNCTION_HEAD(%s, %s, args, %s, __FILE__, __LINE__ - 2)' % (
+                c_string('%s(%s)' % (self.base_name, ', '.join(name_of_defaults))),
+                self.globalobject_name,
+                '(%s)' % (', '.join(map(c_string, name_of_defaults) + ['NULL']),),
+            )
 
         kwlist = ['"%s"' % name for name in
                       func.func_code.co_varnames[:func.func_code.co_argcount]]
         kwlist.append('0')
         print >> f, '\tstatic char* kwlist[] = {%s};' % (', '.join(kwlist),)
 
-        if fast_args:
-            print >> f, '\tPyObject *%s;' % (', *'.join(fast_args))
+        if self.fast_args:
+            print >> f, '\tPyObject *%s;' % (', *'.join(self.fast_args))
         print >> f
 
-        print >> f, '\tFUNCTION_CHECK()'
+        if USE_CALL_TRACE:
+            print >> f, '\tFUNCTION_CHECK()'
 
         # argument unpacking
         if vararg is not None:
@@ -632,7 +165,7 @@
             tail = '\n\t\tFUNCTION_RETURN(NULL)'
         for i in range(len(name_of_defaults)):
             print >> f, '\t%s = %s;' % (
-                self.expr(positional_args[min_number_of_args+i], localscope),
+                self.fast_args[min_number_of_args+i],
                 name_of_defaults[i])
         fmt = 'O'*min_number_of_args
         if min_number_of_args < len(positional_args):
@@ -641,30 +174,33 @@
                '"%s:%s"' % (fmt, func.__name__),
                'kwlist',
                ]
-        lst += ['&' + self.expr(a, localscope) for a in positional_args]
+        lst += ['&' + a for a in self.fast_args]
         print >> f, '\tif (!PyArg_ParseTupleAndKeywords(%s))' % ', '.join(lst),
         print >> f, tail
 
-        call_fast_args = list(fast_args)
-        if call_fast_args:
-            call_fast_args = 'TRACE_CALL ' + ', '.join(call_fast_args)
-        else:
-            call_fast_args = 'TRACE_CALL_VOID'
-        print >> f, '\treturn %s(%s);' % (fast_name, call_fast_args)
+        call_fast_args = list(self.fast_args)
+        if USE_CALL_TRACE:
+            call_fast_args.insert(0, 'TRACE_CALL')
+        call_fast_args = ', '.join(call_fast_args)
+        print >> f, '\treturn %s(%s);' % (self.fast_name, call_fast_args)
         print >> f, '}'
         print >> f
 
-        print >> f, fast_function_header
+    # ____________________________________________________________
+
+    def gen_cfunction(self, f, body):
+        print >> f, self.fast_function_header
         print >> f, '{'
 
-        fast_locals = [arg for arg in localnames if arg not in fast_set]
+        fast_locals = [arg for arg in self.localnames
+                           if arg not in self.fast_set]
         if fast_locals:
             print >> f, '\tPyObject *%s;' % (', *'.join(fast_locals),)
             print >> f
         
         # generate an incref for each input argument
-        for v in positional_args:
-            print >> f, '\tPy_INCREF(%s);' % self.expr(v, localscope)
+        for v in self.positional_args:
+            print >> f, '\tPy_INCREF(%s);' % self.expr(v)
 
         # print the body
         for line in body:
@@ -679,23 +215,12 @@
                 fmt = '%s\n'
             f.write(fmt % line)
         print >> f, '}'
+        print >> f
 
-        if not self.translator.frozen:
-            # this is only to keep the RAM consumption under control
-            del self.translator.flowgraphs[func]
-            Variable.instances.clear()
+    # ____________________________________________________________
 
-    def expr(self, v, localscope):
-        if isinstance(v, Variable):
-            return localscope.localname(v.name)
-        elif isinstance(v, Constant):
-            return self.nameof(v.value,
-                               debug=('Constant in the graph of', self.currentfunc))
-        else:
-            raise TypeError, "expr(%r)" % (v,)
-
-    def cfunction_body(self, func, localscope):
-        graph = self.translator.getflowgraph(func)
+    def cfunction_body(self):
+        graph = self.graph
         remove_direct_loops(graph)
         checkgraph(graph)
 
@@ -707,18 +232,18 @@
             has_ref = {}
             linklocalvars = linklocalvars or {}
             for v in to_release:
-                linklocalvars[v] = self.expr(v, localscope)
+                linklocalvars[v] = self.expr(v)
             has_ref = linklocalvars.copy()
             for a1, a2 in zip(link.args, link.target.inputargs):
                 if a1 in linklocalvars:
                     src = linklocalvars[a1]
                 else:
-                    src = self.expr(a1, localscope)
-                line = 'MOVE(%s, %s)' % (src, self.expr(a2, localscope))
+                    src = self.expr(a1)
+                line = 'MOVE(%s, %s)' % (src, self.expr(a2))
                 if a1 in has_ref:
                     del has_ref[a1]
                 else:
-                    line += '\tPy_INCREF(%s);' % self.expr(a2, localscope)
+                    line += '\tPy_INCREF(%s);' % self.expr(a2)
                 yield line
             for v in has_ref:
                 yield 'Py_DECREF(%s);' % linklocalvars[v]
@@ -737,14 +262,15 @@
             yield 'block%d:' % blocknum[block]
             to_release = list(block.inputargs)
             for op in block.operations:
-                lst = [self.expr(v, localscope) for v in op.args]
-                lst.append(self.expr(op.result, localscope))
-                lst.append('err%d_%d' % (blocknum[block], len(to_release)))
+                args  = [lazy(self.expr, v) for v in op.args]
+                res   = self.expr(op.result)
+                err   = 'err%d_%d' % (blocknum[block], len(to_release))
                 macro = 'OP_%s' % op.opname.upper()
-                meth = getattr(self, macro, None)
+                meth  = getattr(self, macro, None)
                 if meth:
-                    yield meth(lst[:-2], lst[-2], lst[-1])
+                    yield meth(args, res, err)
                 else:
+                    lst = [arg.compute() for arg in args] + [res, err]
                     yield '%s(%s)' % (macro, ', '.join(lst))
                 to_release.append(op.result)
 
@@ -752,13 +278,13 @@
             if len(block.exits) == 0:
                 if len(block.inputargs) == 2:   # exc_cls, exc_value
                     # exceptional return block
-                    exc_cls   = self.expr(block.inputargs[0], localscope)
-                    exc_value = self.expr(block.inputargs[1], localscope)
+                    exc_cls   = self.expr(block.inputargs[0])
+                    exc_value = self.expr(block.inputargs[1])
                     yield 'PyErr_Restore(%s, %s, NULL);' % (exc_cls, exc_value)
                     yield 'FUNCTION_RETURN(NULL)'
                 else:
                     # regular return block
-                    retval = self.expr(block.inputargs[0], localscope)
+                    retval = self.expr(block.inputargs[0])
                     yield 'FUNCTION_RETURN(%s)' % retval
                 continue
             elif block.exitswitch is None:
@@ -783,7 +309,7 @@
                 for link in block.exits[1:]:
                     assert issubclass(link.exitcase, Exception)
                     yield 'if (PyErr_ExceptionMatches(%s)) {' % (
-                        self.nameof(link.exitcase),)
+                        self.genc.nameof(link.exitcase),)
                     yield '\tPyObject *exc_cls, *exc_value, *exc_tb;'
                     yield '\tPyErr_Fetch(&exc_cls, &exc_value, &exc_tb);'
                     yield '\tif (exc_value == NULL) {'
@@ -801,13 +327,13 @@
                 # block ending in a switch on a value
                 for link in block.exits[:-1]:
                     yield 'if (EQ_%s(%s)) {' % (link.exitcase,
-                                                self.expr(block.exitswitch, localscope))
+                                                self.expr(block.exitswitch))
                     for op in gen_link(link):
                         yield '\t' + op
                     yield '}'
                 link = block.exits[-1]
                 yield 'assert(EQ_%s(%s));' % (link.exitcase,
-                                              self.expr(block.exitswitch, localscope))
+                                              self.expr(block.exitswitch))
                 for op in gen_link(block.exits[-1]):
                     yield op
                 yield ''
@@ -815,49 +341,19 @@
             while to_release:
                 v = to_release.pop()
                 if err_reachable:
-                    yield 'ERR_DECREF(%s)' % self.expr(v, localscope)
+                    yield 'ERR_DECREF(%s)' % self.expr(v)
                 yield 'err%d_%d:' % (blocknum[block], len(to_release))
                 err_reachable = True
             if err_reachable:
                 yield 'FUNCTION_RETURN(NULL)'
 
-# ____________________________________________________________
-
-    C_HEADER = '#include "genc.h"\n'
-
-    C_SEP = "/************************************************************/"
-
-    C_OBJECT_TABLE = C_SEP + '''
-
-/* Table of global objects */
-static globalobjectdef_t globalobjectdefs[] = {'''
-
-    C_FUNCTION_TABLE = '''
-/* Table of functions */
-static globalfunctiondef_t globalfunctiondefs[] = {'''
-
-    C_TABLE_END = '\t{ NULL }\t/* Sentinel */\n};'
-
-    C_FROZEN_BEGIN = '''
-/* Frozen Python bytecode: the initialization code */
-static char *frozen_initcode[] = {"\\'''
-
-    C_FROZEN_BETWEEN = '''", "\\'''
-
-    C_FROZEN_END = '''"};\n'''
-
-    C_FOOTER = C_SEP + '''
-
-MODULE_INITFUNC(%(modname)s)
-{
-\tSETUP_MODULE(%(modname)s)
-\tPyModule_AddObject(m, "%(entrypointname)s", %(entrypoint)s);
-}'''
+    # ____________________________________________________________
 
     # the C preprocessor cannot handle operations taking a variable number
     # of arguments, so here are Python methods that do it
     
     def OP_NEWLIST(self, args, r, err):
+        args = [arg.compute() for arg in args]
         if len(args) == 0:
             return 'OP_NEWLIST0(%s, %s)' % (r, err)
         else:
@@ -865,6 +361,7 @@
             return 'OP_NEWLIST((%s), %s, %s)' % (', '.join(args), r, err)
 
     def OP_NEWDICT(self, args, r, err):
+        args = [arg.compute() for arg in args]
         if len(args) == 0:
             return 'OP_NEWDICT0(%s, %s)' % (r, err)
         else:
@@ -873,26 +370,36 @@
             return 'OP_NEWDICT((%s), %s, %s)' % (', '.join(args), r, err)
 
     def OP_NEWTUPLE(self, args, r, err):
+        args = [arg.compute() for arg in args]
         args.insert(0, '%d' % len(args))
         return 'OP_NEWTUPLE((%s), %s, %s)' % (', '.join(args), r, err)
 
-    def OP_SIMPLE_CALL(self, args, r, err):
+    def OP_SIMPLE_CALL(self, target_args, r, err):
+        # try to use the shortcut: a direct call to
+        # the ff_xxx() function, using its C signature.
+        target = target_args[0].args[0]
+        args = [arg.compute() for arg in target_args[1:]]
+        if (isinstance(target, Constant) and
+            isinstance(target.value, FunctionType) and not USE_CALL_TRACE):
+            funcdef = self.genc.getfuncdef(target.value)
+            if len(funcdef.positional_args) == len(args) and not funcdef.vararg:
+                return 'if (!(%s=%s(%s))) FAIL(%s);' % (
+                    r, funcdef.fast_name, ', '.join(args), err)
+        # fall-back
+        args.insert(0, target_args[0].compute())
         args.append('NULL')
         return 'OP_SIMPLE_CALL((%s), %s, %s)' % (', '.join(args), r, err)
 
     def OP_CALL_ARGS(self, args, r, err):
+        args = [arg.compute() for arg in args]
         return 'OP_CALL_ARGS((%s), %s, %s)' % (', '.join(args), r, err)
 
 # ____________________________________________________________
 
-def cdecl(type, name):
-    # Utility to generate a typed name declaration in C syntax.
-    # For local variables, struct fields, function declarations, etc.
-    # For complex C types, the 'type' can contain a '@' character that
-    # specifies where the 'name' should be inserted; for example, an
-    # array of 10 ints has a type of "int @[10]".
-    if '@' in type:
-        return type.replace('@', name)
-    else:
-        return ('%s %s' % (type, name)).rstrip()
-
+class lazy:
+    def __init__(self, fn, *args, **kwds):
+        self.fn = fn
+        self.args = args
+        self.kwds = kwds
+    def compute(self):
+        return self.fn(*self.args, **self.kwds)



More information about the Pypy-commit mailing list