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

arigo at codespeak.net arigo at codespeak.net
Fri Apr 1 19:43:32 CEST 2005


Author: arigo
Date: Fri Apr  1 19:43:31 2005
New Revision: 10236

Added:
   pypy/dist/pypy/translator/genc_type.h   (contents, props changed)
Modified:
   pypy/dist/pypy/translator/genc.h
   pypy/dist/pypy/translator/genc.py
   pypy/dist/pypy/translator/genc_funcdef.py
   pypy/dist/pypy/translator/genc_pyobj.py
   pypy/dist/pypy/translator/genc_type.py
Log:
Trying to combine the typer and genc, we get a bit more mess into genc_funcdef
but it is hopefully still reasonable.

Types are a bit difficult to follow right now; they don't show up in the
pygame viewers, and the chosen local variable names don't hint at them either.  
Debugging segfaults might become a problem because type errors (which are real
errors) are lost in the sea of the C compiler's warnings (which we don't care
about, like label not used).


Modified: pypy/dist/pypy/translator/genc.h
==============================================================================
--- pypy/dist/pypy/translator/genc.h	(original)
+++ pypy/dist/pypy/translator/genc.h	Fri Apr  1 19:43:31 2005
@@ -14,6 +14,8 @@
 #define MIN(a,b) (((a)<(b))?(a):(b))
 #endif /* MIN */
 
+#include "genc_type.h"
+
 static PyObject *this_module_globals;
 
 /* Set genc_funcdef.USE_CALL_TRACE if you want call trace frames to be built */
@@ -156,13 +158,6 @@
 #define OP_ISSUBTYPE(x,y,r,err)  \
 		op_bool(r,err,PyClass_IsSubclass(x, y))
 
-/*** tests ***/
-
-#define EQ_False(o)     (o == Py_False)
-#define EQ_True(o)      (o == Py_True)
-#define EQ_0(o)         (PyInt_Check(o) && PyInt_AS_LONG(o)==0)
-#define EQ_1(o)         (PyInt_Check(o) && PyInt_AS_LONG(o)==1)
-
 
 /*** misc ***/
 
@@ -533,7 +528,7 @@
 	PyObject* o;
 	PyObject* key;
 	PyObject* t2;
-	int i, nargs, nkwds, nvarargs, starflag, starstarflag;
+	int i, nargs, nkwds, starflag, starstarflag;
 	va_list vargs;
 
 	if (!PyTuple_Check(shape) ||

Modified: pypy/dist/pypy/translator/genc.py
==============================================================================
--- pypy/dist/pypy/translator/genc.py	(original)
+++ pypy/dist/pypy/translator/genc.py	Fri Apr  1 19:43:31 2005
@@ -9,7 +9,7 @@
 from pypy.translator.gensupp import NameManager
 
 from pypy.translator.genc_funcdef import FunctionDef, USE_CALL_TRACE
-from pypy.translator.genc_pyobj import CType_PyObject
+from pypy.translator.genc_pyobj import CType_PyObject, ctypeof
 
 # ____________________________________________________________
 
@@ -41,10 +41,6 @@
            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.pendingfunctions = []
         self.funcdefs = {}
@@ -60,12 +56,14 @@
             crepr = self.ctyperepresenters[type_cls] = type_cls(self)
             return crepr
 
-    def nameofconst(self, c, type_cls=None, debug=None):
-        if type_cls is None:
-            type_cls = getattr(c, 'type_cls', CType_PyObject)
-        crepr = self.getrepresenter(type_cls)
+    def nameofconst(self, c, debug=None):
+        crepr = self.getrepresenter(ctypeof(c))
         return crepr.nameof(c.value, debug=debug)
 
+    def nameofvalue(self, value, type_cls):
+        crepr = self.getrepresenter(type_cls)
+        return crepr.nameof(value)
+
     def getfuncdef(self, func):
         if func not in self.funcdefs:
             if self.translator.frozen:

Modified: pypy/dist/pypy/translator/genc_funcdef.py
==============================================================================
--- pypy/dist/pypy/translator/genc_funcdef.py	(original)
+++ pypy/dist/pypy/translator/genc_funcdef.py	Fri Apr  1 19:43:31 2005
@@ -8,7 +8,7 @@
 from types import FunctionType
 
 from pypy.translator.gensupp import c_string
-
+from pypy.translator.genc_pyobj import ctypeof
 
 # Set this if you want call trace frames to be built
 USE_CALL_TRACE = False
@@ -20,12 +20,14 @@
     The operations of each function are collected in a C function
     with signature:
 
-        static PyObject *fn_xxx(PyObject *arg1, PyObject *arg2, etc);
+        static T fn_xxx(T1 arg1, T2 arg2, etc);
+
+    where the T, T1, T2.. are C types like 'int' or 'PyObject *'.
 
     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);
+        static PyObject *pyfn_xxx(PyObject *self, PyObject *args, PyObject* kw);
 
     The built-in function object, if needed, is put in the global
     variable named gfn_xxx.
@@ -43,6 +45,7 @@
         self.globalobject_name = None                                # gfunc_xxx
         self.localscope = namespace.localScope()
         self.graph = graph = genc.translator.getflowgraph(func)
+        graph_args = graph.getargs()
 
         # collect all the local variables
         localslst = []
@@ -50,27 +53,19 @@
             if isinstance(node, Block):
                 localslst.extend(node.getvariables())
         traverse(visit, graph)
-        self.localnames = [self.expr(a) for a in uniqueitems(localslst)]
+        fast_set = dict(zip(graph_args, graph_args))
+        self.localnames = [self.decl(a) for a in localslst if a not in fast_set]
 
         # 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()
-
-        fast_args = [self.expr(a) for a in positional_args]
-        if vararg is not None:
-            vararg = self.expr(vararg)
-            fast_args.append(vararg)
-
-        declare_fast_args = [('PyObject *' + a) for a in fast_args]
+        fast_args         = [self.expr(a) for a in graph_args]
+        declare_fast_args = [self.decl(a) for a in graph_args]
         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)' % (self.fast_name, declare_fast_args))
+        name_and_arguments = '%s(%s)' % (self.fast_name, declare_fast_args)
+        ctret = ctypeof(graph.getreturnvar())
+        fast_function_header = 'static ' + (
+            ctret.ctypetemplate % (name_and_arguments,))
 
         name_of_defaults = [self.genc.pyobjrepr.nameof(x, debug=('Default argument of',
                                                        self))
@@ -78,11 +73,14 @@
 
         # store misc. information
         self.fast_function_header = fast_function_header
+        self.graphargs = graph_args
+        self.ctret = ctret
+        self.vararg = bool(func.func_code.co_flags & CO_VARARGS)
         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
+        
+        error_return = getattr(ctret, 'error_return', 'NULL')
+        self.return_error = 'FUNCTION_RETURN(%s)' % error_return
 
         # generate the forward header
         self.genc.globaldecl.append(fast_function_header + ';  /* forward */')
@@ -98,9 +96,12 @@
     def clear(self):
         del self.localscope
         del self.localnames
-        del self.fast_set
         del self.graph
 
+    def decl(self, v):
+        assert isinstance(v, Variable)
+        return ctypeof(v).ctypetemplate % (self.localscope.localname(v.name),)
+
     def expr(self, v):
         if isinstance(v, Variable):
             return self.localscope.localname(v.name)
@@ -115,11 +116,12 @@
     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
+        graphargs        = self.graphargs
+        vararg           = self.vararg
+        nb_positional_args = len(graphargs) - vararg
 
-        min_number_of_args = len(self.positional_args) - len(name_of_defaults)
+        min_number_of_args = nb_positional_args - len(name_of_defaults)
         print >> f, 'static PyObject *'
         print >> f, '%s(PyObject* self, PyObject* args, PyObject* kwds)' % (
             f_name,)
@@ -136,53 +138,93 @@
         kwlist.append('0')
         print >> f, '\tstatic char* kwlist[] = {%s};' % (', '.join(kwlist),)
 
-        if self.fast_args:
-            print >> f, '\tPyObject *%s;' % (', *'.join(self.fast_args))
+        numberednames = ['o%d' % (i+1) for i in range(len(graphargs))]
+        if vararg:
+            numberednames[-1] = 'ovararg'
+        numberednames.append('oret')
+        print >> f, '\tPyObject *%s;' % (', *'.join(numberednames))
+        conversions = []
+        call_fast_args = []
+        for a, numberedname in zip(graphargs, numberednames):
+            try:
+                convert_from_obj = a.type_cls.convert_from_obj
+            except AttributeError:
+                call_fast_args.append(numberedname)
+            else:
+                convertedname = numberedname.replace('o', 'a')
+                ct = ctypeof(a)
+                print >> f, '\t%s;' % (ct.ctypetemplate % (convertedname,))
+                conversions.append('\tOP_%s(%s, %s, type_error)' % (
+                    convert_from_obj.upper(), numberedname, convertedname))
+                # XXX successfully converted objects may need to be decrefed
+                # XXX even though they are not PyObjects
+                call_fast_args.append(convertedname)
+        # return value conversion
+        try:
+            convert_to_obj = self.ctret.convert_to_obj
+        except AttributeError:
+            putresultin = 'oret'
+            footer = None
+        else:
+            print >> f, '\t%s;' % (self.ctret.ctypetemplate % ('aret',))
+            putresultin = 'aret'
+            footer = 'OP_%s(aret, oret, type_error)' % convert_to_obj.upper()
         print >> f
 
         if USE_CALL_TRACE:
             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,)
+        if vararg:
+            print >> f, '\tovararg = PyTuple_GetSlice(args, %d, INT_MAX);' % (
+                nb_positional_args,)
+            print >> f, '\tif (ovararg == NULL)'
             print >> f, '\t\tFUNCTION_RETURN(NULL)'
             print >> f, '\targs = PyTuple_GetSlice(args, 0, %d);' % (
-                len(positional_args),)
+                nb_positional_args,)
             print >> f, '\tif (args == NULL) {'
-            print >> f, '\t\tERR_DECREF(%s)' % (vararg,)
+            print >> f, '\t\tERR_DECREF(ovararg)'
             print >> f, '\t\tFUNCTION_RETURN(NULL)'
             print >> f, '\t}'
             tail = """{
 \t\tERR_DECREF(args)
-\t\tERR_DECREF(%s)
+\t\tERR_DECREF(ovararg)
 \t\tFUNCTION_RETURN(NULL);
 \t}
-\tPy_DECREF(args);""" % vararg
+\tPy_DECREF(args);"""
         else:
             tail = '\n\t\tFUNCTION_RETURN(NULL)'
         for i in range(len(name_of_defaults)):
             print >> f, '\t%s = %s;' % (
-                self.fast_args[min_number_of_args+i],
+                numberednames[min_number_of_args+i],
                 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)
+        if min_number_of_args < nb_positional_args:
+            fmt += '|' + 'O'*(nb_positional_args-min_number_of_args)
         lst = ['args', 'kwds',
                '"%s:%s"' % (fmt, func.__name__),
                'kwlist',
                ]
-        lst += ['&' + a for a in self.fast_args]
+        lst += ['&' + a for a in numberednames]
         print >> f, '\tif (!PyArg_ParseTupleAndKeywords(%s))' % ', '.join(lst),
         print >> f, tail
 
-        call_fast_args = list(self.fast_args)
+        for line in conversions:
+            print >> f, line
+
         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, '\t%s = %s(%s);' % (putresultin, self.fast_name,
+                                        call_fast_args)
+        if footer:
+            print >> f, '\t' + footer
+        print >> f, '\treturn oret;'
+
+        if conversions:
+            print >> f, '    type_error:'
+            print >> f, '        return NULL;'
+        
         print >> f, '}'
         print >> f
 
@@ -192,15 +234,24 @@
         print >> f, self.fast_function_header
         print >> f, '{'
 
-        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
+        localnames = self.localnames
+        lengths = [len(a) for a in localnames]
+        lengths.append(9999)
+        start = 0
+        while start < len(localnames):
+            total = lengths[start] + 9
+            end = start+1
+            while total + lengths[end] < 76:
+                total += lengths[end] + 2
+                end += 1
+            print >> f, '\t' + '; '.join(localnames[start:end]) + ';'
+            start = end
         
         # generate an incref for each input argument
-        for v in self.positional_args:
-            print >> f, '\tPy_INCREF(%s);' % self.expr(v)
+        for a in self.graphargs:
+            cincref = getattr(ctypeof(a), 'cincref', None)
+            if cincref:
+                print >> f, '\t' + cincref % (self.expr(a),)
 
         # print the body
         for line in body:
@@ -243,10 +294,17 @@
                 if a1 in has_ref:
                     del has_ref[a1]
                 else:
-                    line += '\tPy_INCREF(%s);' % self.expr(a2)
+                    ct1 = ctypeof(a1)
+                    ct2 = ctypeof(a2)
+                    assert ct1 == ct2
+                    cincref = getattr(ct1, 'cincref', None)
+                    if cincref:
+                        line += '\t' + cincref % (self.expr(a2),)
                 yield line
             for v in has_ref:
-                yield 'Py_DECREF(%s);' % linklocalvars[v]
+                cdecref = getattr(ctypeof(v), 'cdecref', None)
+                if cdecref:
+                    yield cdecref % (linklocalvars[v],)
             yield 'goto block%d;' % blocknum[link.target]
 
         # collect all blocks
@@ -281,7 +339,7 @@
                     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)'
+                    yield self.return_error
                 else:
                     # regular return block
                     retval = self.expr(block.inputargs[0])
@@ -325,15 +383,18 @@
                 err_reachable = True
             else:
                 # block ending in a switch on a value
+                ct = ctypeof(block.exitswitch)
                 for link in block.exits[:-1]:
-                    yield 'if (EQ_%s(%s)) {' % (link.exitcase,
-                                                self.expr(block.exitswitch))
+                    assert link.exitcase in (False, True)
+                    yield 'if (%s == %s) {' % (self.expr(block.exitswitch),
+                                       self.genc.nameofvalue(link.exitcase, ct))
                     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))
+                assert link.exitcase in (False, True)
+                yield 'assert(%s == %s);' % (self.expr(block.exitswitch),
+                                       self.genc.nameofvalue(link.exitcase, ct))
                 for op in gen_link(block.exits[-1]):
                     yield op
                 yield ''
@@ -341,11 +402,16 @@
             while to_release:
                 v = to_release.pop()
                 if err_reachable:
-                    yield 'ERR_DECREF(%s)' % self.expr(v)
+                    if not hasattr(v, 'type_cls'):
+                        yield 'ERR_DECREF(%s)' % self.expr(v)
+                    else:
+                        cdecref = getattr(ctypeof(v), 'cdecref', None)
+                        if cdecref:
+                            yield cdecref % (self.expr(v),)
                 yield 'err%d_%d:' % (blocknum[block], len(to_release))
                 err_reachable = True
             if err_reachable:
-                yield 'FUNCTION_RETURN(NULL)'
+                yield self.return_error
 
     # ____________________________________________________________
 
@@ -388,7 +454,7 @@
         funcdef = self.genc.getfuncdef(target.value)
         if funcdef is None:
             return None
-        if len(funcdef.positional_args) != len(args) or funcdef.vararg:
+        if len(funcdef.graphargs) != len(args) or funcdef.vararg:
             return None
         return 'if (!(%s=%s(%s))) FAIL(%s);' % (
             r, funcdef.fast_name, ', '.join(args), err)

Modified: pypy/dist/pypy/translator/genc_pyobj.py
==============================================================================
--- pypy/dist/pypy/translator/genc_pyobj.py	(original)
+++ pypy/dist/pypy/translator/genc_pyobj.py	Fri Apr  1 19:43:31 2005
@@ -13,6 +13,9 @@
     of Python objects to be 'pickled' as Python source code that will
     reconstruct them.
     """
+    ctypetemplate = 'PyObject *%s'
+    cincref       = 'Py_INCREF(%s);'
+    cdecref       = 'Py_DECREF(%s);'
 
     def __init__(self, genc):
         self.genc = genc
@@ -433,3 +436,7 @@
         co = compile(source, self.genc.modname, 'exec')
         del source
         return marshal.dumps(co)
+
+
+def ctypeof(v):
+    return getattr(v, 'type_cls', CType_PyObject)

Added: pypy/dist/pypy/translator/genc_type.h
==============================================================================
--- (empty file)
+++ pypy/dist/pypy/translator/genc_type.h	Fri Apr  1 19:43:31 2005
@@ -0,0 +1,12 @@
+
+/************************************************************/
+ /***  C header subsection: typed operations               ***/
+
+/* This file is included from genc.h. */
+
+
+#define OP_INT2OBJ(i,r,err)   if (!(r=PyInt_FromLong(i))) FAIL(err)
+#define OP_OBJ2INT(o,r,err)   if ((r=PyInt_AsLong(o))==-1 && PyErr_Occurred()) \
+							  FAIL(err)
+
+#define OP_INT_IS_TRUE(x,r,err)   r = (x != 0);

Modified: pypy/dist/pypy/translator/genc_type.py
==============================================================================
--- pypy/dist/pypy/translator/genc_type.py	(original)
+++ pypy/dist/pypy/translator/genc_type.py	Fri Apr  1 19:43:31 2005
@@ -1,5 +1,13 @@
 
 
 class CType_Int:
+    ctypetemplate    = 'int %s'
     convert_to_obj   = 'int2obj'
     convert_from_obj = 'obj2int'
+    error_return     = '-1'
+
+    def __init__(self, genc):
+        pass
+
+    def nameof(self, v, debug=None):
+        return '%d' % v



More information about the Pypy-commit mailing list