[pypy-svn] r10430 - in pypy/dist/pypy/translator: . genc tool
arigo at codespeak.net
arigo at codespeak.net
Fri Apr 8 13:29:43 CEST 2005
Author: arigo
Date: Fri Apr 8 13:29:42 2005
New Revision: 10430
Added:
pypy/dist/pypy/translator/genc/g_simple.h
- copied unchanged from r10428, pypy/dist/pypy/translator/genc/g_int.h
pypy/dist/pypy/translator/genc/t_simple.py
- copied, changed from r10428, pypy/dist/pypy/translator/genc/t_int.py
Removed:
pypy/dist/pypy/translator/genc/g_int.h
pypy/dist/pypy/translator/genc/parametric.py
pypy/dist/pypy/translator/genc/t_int.py
Modified:
pypy/dist/pypy/translator/genc/ctyper.py
pypy/dist/pypy/translator/genc/funcdef.py
pypy/dist/pypy/translator/genc/g_include.h
pypy/dist/pypy/translator/genc/genc.py
pypy/dist/pypy/translator/genc/t_func.py
pypy/dist/pypy/translator/genc/t_pyobj.py
pypy/dist/pypy/translator/tool/graphpage.py
pypy/dist/pypy/translator/translator.py
pypy/dist/pypy/translator/typer.py
pypy/dist/pypy/translator/unsimplify.py
Log:
A good clean-up of the CType_Xxx classes: it is no more creating parametrized
subclasses on-the-fly. Instead, the CXxxType classes are instantiated and
cached in the translator. Each instance stands for a specific concrete type
in the code generator. For example, there is one CIntType instance in the
translator, but generally several CFuncPtrType instances, one per function
signature.
Modified: pypy/dist/pypy/translator/genc/ctyper.py
==============================================================================
--- pypy/dist/pypy/translator/genc/ctyper.py (original)
+++ pypy/dist/pypy/translator/genc/ctyper.py Fri Apr 8 13:29:42 2005
@@ -2,36 +2,46 @@
GenC-specific type specializer
"""
-from pypy.translator.typer import Specializer, TypeMatch
-from pypy.annotation.model import SomeInteger, SomePBC
-from pypy.translator.genc.t_pyobj import CType_PyObject
-from pypy.translator.genc.t_int import CType_Int, CType_None
-from pypy.translator.genc.t_func import CType_FuncPtr
+from __future__ import generators
+from pypy.translator.typer import Specializer
+from pypy.objspace.flow.model import Constant, Variable, SpaceOperation
+from pypy.annotation.model import SomeInteger, SomePBC, SomeTuple
+from pypy.translator.genc.t_pyobj import CPyObjectType
+from pypy.translator.genc.t_simple import CIntType, CNoneType
+from pypy.translator.genc.t_func import CFuncPtrType
import types
from pypy.interpreter.pycode import CO_VARARGS
class GenCSpecializer(Specializer):
- TInt = TypeMatch(SomeInteger(), CType_Int)
- TNone = TypeMatch(SomePBC({None: True}), CType_None)
-
- # in more-specific-first, more-general-last order
- typematches = [TNone, TInt]
-
- defaulttypecls = CType_PyObject
-
- specializationtable = [
- ## op specialized op arg types concrete return type
- ('add', 'int_add', TInt, TInt, CType_Int),
- ('inplace_add', 'int_add', TInt, TInt, CType_Int),
- ('sub', 'int_sub', TInt, TInt, CType_Int),
- ('inplace_sub', 'int_sub', TInt, TInt, CType_Int),
- ('is_true', 'int_is_true', TInt, CType_Int),
- ]
-
- def annotation2typecls(self, s_value):
- besttype = Specializer.annotation2typecls(self, s_value)
- if besttype is None:
+ def __init__(self, annotator):
+ # instantiate the common concrete types
+ t = annotator.translator
+ TInt = t.getconcretetype(CIntType)
+ TNone = t.getconcretetype(CNoneType)
+ TPyObject = t.getconcretetype(CPyObjectType)
+
+ # initialization
+ Specializer.__init__(
+ self, annotator,
+ defaultconcretetype = TPyObject,
+
+ # in more-specific-first, more-general-last order
+ typematches = [TNone, TInt],
+
+ specializationtable = [
+ ## op specialized op arg types concrete return type
+ ('add', 'int_add', TInt, TInt, TInt),
+ ('inplace_add', 'int_add', TInt, TInt, TInt),
+ ('sub', 'int_sub', TInt, TInt, TInt),
+ ('inplace_sub', 'int_sub', TInt, TInt, TInt),
+ ('is_true', 'int_is_true', TInt, TInt),
+ ],
+ )
+
+ def annotation2concretetype(self, s_value):
+ besttype = Specializer.annotation2concretetype(self, s_value)
+ if besttype == self.defaultconcretetype:
if isinstance(s_value, SomePBC):
# XXX! must be somehow unified with bookkeeper.pycall()!
@@ -44,19 +54,59 @@
graph = self.annotator.translator.flowgraphs[s_value.const]
args_ct = [self.setbesttype(a) for a in graph.getargs()]
res_ct = self.setbesttype(graph.getreturnvar())
- key = tuple(args_ct + [res_ct])
- besttype = CType_FuncPtr[key]
+ besttype = self.annotator.translator.getconcretetype(
+ CFuncPtrType, tuple(args_ct), res_ct)
+
+## elif isinstance(s_value, SomeTuple):
+## key = tuple([self.annotation2concretetype(s_item)
+## for s_item in s_value.items])
+## besttype = CType_Tuple[key]
return besttype
- def getspecializedop(self, op, bindings):
+ def make_specialized_op(self, op, bindings):
if op.opname == 'simple_call':
s_callable = self.annotator.binding(op.args[0], True)
if s_callable is not None:
- ct = self.annotation2typecls(s_callable)
- if ct is not None and issubclass(ct, CType_FuncPtr):
- args_typecls = [ct]
- args_typecls += ct.args_typecls
- return 'direct_call', args_typecls, ct.return_typecls
+ ct = self.annotation2concretetype(s_callable)
+ if isinstance(ct, CFuncPtrType):
+ argtypes = [ct]
+ argtypes += ct.argtypes
+ self.make_typed_op(op, argtypes, ct.returntype,
+ newopname='direct_call')
+ return
+
+## if op.opname == 'getitem':
+## s_obj = self.annotator.binding(op.args[0], True)
+## if s_obj is not None:
+## ct = self.annotation2typecls(s_obj)
+## if issubclass(ct, CType_Tuple):
+## if isinstance(op.args[1], Constant):
+## index = op.args[1].value
+## try:
+## ct1 = ct.items_typecls[index]
+## except IndexError:
+## print "*** getitem: IndexError in tuple access"
+## else:
+## self.make_typed_op(op, [ct, CType_Int], ct1,
+## newopname='tuple_getitem')
+## return
+
+## if op.opname == 'newtuple':
+## s_tuple = self.annotator.binding(op.result, True)
+## if s_tuple is not None:
+## ct = self.annotation2typecls(s_tuple)
+## if issubclass(ct, CType_Tuple):
+## op1 = SpaceOperation('tuple_new', [], op.result)
+## self.make_typed_op(op1, [], ct)
+## for i in range(len(ct.items_typecls)):
+## op1 = SpaceOperation('tuple_inititem',
+## [op.result, Constant(i), op.args[i]],
+## Variable())
+## ct1 = ct.items_typecls[i]
+## self.make_typed_op(op1,
+## [ct, CType_Int, ct1],
+## CType_None)
+## return
- return Specializer.getspecializedop(self, op, bindings)
+ Specializer.make_specialized_op(self, op, bindings)
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 8 13:29:42 2005
@@ -8,7 +8,6 @@
from types import FunctionType
from pypy.translator.gensupp import c_string
-from pypy.translator.genc.t_pyobj import ctypeof
# Set this if you want call trace frames to be built
USE_CALL_TRACE = False
@@ -68,12 +67,12 @@
declare_fast_args.insert(0, 'TRACE_ARGS')
declare_fast_args = ', '.join(declare_fast_args) or 'void'
name_and_arguments = '%s(%s)' % (self.fast_name, declare_fast_args)
- ctret = ctypeof(graph.getreturnvar())
+ ctret = self.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))
+ name_of_defaults = [self.genc.nameofvalue(x, debug=(
+ 'Default argument of', self))
for x in (func.func_defaults or ())]
# store misc. information
@@ -91,10 +90,16 @@
self.genc.globaldecl.append(fast_function_header + '; /* forward */')
+ def ctypeof(self, var_or_const):
+ try:
+ return var_or_const.concretetype
+ except AttributeError:
+ return self.genc.pyobjtype
+
def get_globalobject(self):
if self.globalobject_name is None:
self.wrapper_name = 'py' + self.fast_name
- self.globalobject_name = self.genc.pyobjrepr.uniquename('gfunc_' +
+ self.globalobject_name = self.genc.pyobjtype.uniquename('gfunc_' +
self.base_name)
return self.globalobject_name
@@ -105,7 +110,8 @@
def decl(self, v):
assert isinstance(v, Variable)
- return ctypeof(v).ctypetemplate % (self.localscope.localname(v.name),)
+ ct = self.ctypeof(v)
+ return ct.ctypetemplate % (self.localscope.localname(v.name),)
def expr(self, v):
if isinstance(v, Variable):
@@ -119,6 +125,8 @@
# ____________________________________________________________
def gen_wrapper(self, f):
+ # XXX this is a huge mess. Think about producing the wrapper by
+ # generating its content as a flow graph...
func = self.func
f_name = self.wrapper_name
name_of_defaults = self.name_of_defaults
@@ -151,13 +159,12 @@
conversions = []
call_fast_args = []
for a, numberedname in zip(graphargs, numberednames):
- try:
- convert_from_obj = a.type_cls.convert_from_obj
- except AttributeError:
+ ct = self.ctypeof(a)
+ if ct == self.genc.pyobjtype:
call_fast_args.append(numberedname)
else:
+ convert_from_obj = ct.opname_conv_from_obj # simple conv only!
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))
@@ -165,13 +172,13 @@
# 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:
+ ct = self.ctret
+ if ct == self.genc.pyobjtype:
putresultin = 'oret'
footer = None
else:
- print >> f, '\t%s;' % (self.ctret.ctypetemplate % ('aret',))
+ convert_to_obj = ct.opname_conv_to_obj # simple conv only for now!
+ print >> f, '\t%s;' % (ct.ctypetemplate % ('aret',))
putresultin = 'aret'
footer = 'OP_%s(aret, oret, type_error)' % convert_to_obj.upper()
print >> f
@@ -254,7 +261,7 @@
# generate an incref for each input argument
for a in self.graphargs:
- cincref = getattr(ctypeof(a), 'cincref', None)
+ cincref = self.ctypeof(a).cincref
if cincref:
print >> f, '\t' + cincref % (self.expr(a),)
@@ -297,15 +304,14 @@
if a1 in has_ref:
del has_ref[a1]
else:
- ct1 = ctypeof(a1)
- ct2 = ctypeof(a2)
+ ct1 = self.ctypeof(a1)
+ ct2 = self.ctypeof(a2)
assert ct1 == ct2
- cincref = getattr(ct1, 'cincref', None)
- if cincref:
- line += '\t' + cincref % (self.expr(a2),)
+ if ct1.cincref:
+ line += '\t' + ct1.cincref % (self.expr(a2),)
yield line
for v in has_ref:
- cdecref = getattr(ctypeof(v), 'cdecref', None)
+ cdecref = self.ctypeof(v).cdecref
if cdecref:
yield cdecref % (linklocalvars[v],)
yield 'goto block%d;' % blocknum[link.target]
@@ -370,7 +376,7 @@
for link in block.exits[1:]:
assert issubclass(link.exitcase, Exception)
yield 'if (PyErr_ExceptionMatches(%s)) {' % (
- self.genc.pyobjrepr.nameof(link.exitcase),)
+ self.genc.nameofvalue(link.exitcase),)
yield '\tPyObject *exc_cls, *exc_value, *exc_tb;'
yield '\tPyErr_Fetch(&exc_cls, &exc_value, &exc_tb);'
yield '\tif (exc_value == NULL) {'
@@ -386,7 +392,7 @@
err_reachable = True
else:
# block ending in a switch on a value
- ct = ctypeof(block.exitswitch)
+ ct = self.ctypeof(block.exitswitch)
for link in block.exits[:-1]:
assert link.exitcase in (False, True)
yield 'if (%s == %s) {' % (self.expr(block.exitswitch),
@@ -405,12 +411,12 @@
while to_release:
v = to_release.pop()
if err_reachable:
- if not hasattr(v, 'type_cls'):
- yield 'ERR_DECREF(%s)' % self.expr(v)
+ if not hasattr(v, 'concretetype'):
+ cdecref = 'ERR_DECREF(%s)'
else:
- cdecref = getattr(ctypeof(v), 'cdecref', None)
- if cdecref:
- yield cdecref % (self.expr(v),)
+ cdecref = v.concretetype.cdecref
+ if cdecref:
+ yield cdecref % (self.expr(v),)
yield 'err%d_%d:' % (blocknum[block], len(to_release))
err_reachable = True
if err_reachable:
Modified: pypy/dist/pypy/translator/genc/g_include.h
==============================================================================
--- pypy/dist/pypy/translator/genc/g_include.h (original)
+++ pypy/dist/pypy/translator/genc/g_include.h Fri Apr 8 13:29:42 2005
@@ -11,7 +11,7 @@
#include "eval.h"
#include "g_operation.h"
-#include "g_int.h"
+#include "g_simple.h"
#include "g_trace.h"
#include "g_support.h"
#include "g_module.h"
Deleted: /pypy/dist/pypy/translator/genc/g_int.h
==============================================================================
--- /pypy/dist/pypy/translator/genc/g_int.h Fri Apr 8 13:29:42 2005
+++ (empty file)
@@ -1,16 +0,0 @@
-
-/************************************************************/
- /*** C header subsection: operations between ints ***/
-
-
-#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_NONE2OBJ(n,r,err) r = Py_None; Py_INCREF(r);
-#define OP_OBJ2NONE(o,n,err) assert(o == Py_None); n = 0;
-
-#define OP_INT_IS_TRUE(x,r,err) r = (x != 0);
-
-#define OP_INT_ADD(x,y,r,err) r = x + y;
-#define OP_INT_SUB(x,y,r,err) r = x - y;
Modified: pypy/dist/pypy/translator/genc/genc.py
==============================================================================
--- pypy/dist/pypy/translator/genc/genc.py (original)
+++ pypy/dist/pypy/translator/genc/genc.py Fri Apr 8 13:29:42 2005
@@ -5,11 +5,11 @@
import autopath, os
from pypy.objspace.flow.model import Variable, Constant
+from pypy.interpreter.miscutils import getthreadlocals
from pypy.translator.gensupp import uniquemodulename
-from pypy.translator.gensupp import NameManager
from pypy.translator.genc.funcdef import FunctionDef, USE_CALL_TRACE
-from pypy.translator.genc.t_pyobj import CType_PyObject, ctypeof
+from pypy.translator.genc.t_pyobj import CPyObjectType
# ____________________________________________________________
@@ -27,42 +27,29 @@
self.translator = translator
self.modname = (modname or
uniquemodulename(translator.functions[0].__name__))
- 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
- ''')
self.globaldecl = []
self.pendingfunctions = []
self.funcdefs = {}
self.allfuncdefs = []
- self.ctyperepresenters = {}
- self.pyobjrepr = self.getrepresenter(CType_PyObject)
- self.gen_source()
+ self.pyobjtype = translator.getconcretetype(CPyObjectType)
+ self.namespace = self.pyobjtype.namespace
- def getrepresenter(self, type_cls):
+ assert not hasattr(getthreadlocals(), 'genc')
+ getthreadlocals().genc = self
try:
- return self.ctyperepresenters[type_cls]
- except KeyError:
- crepr = self.ctyperepresenters[type_cls] = type_cls(self)
- return crepr
+ self.gen_source()
+ finally:
+ del getthreadlocals().genc
def nameofconst(self, c, debug=None):
- crepr = self.getrepresenter(ctypeof(c))
- return crepr.nameof(c.value, debug=debug)
+ try:
+ concretetype = c.concretetype
+ except AttributeError:
+ concretetype = self.pyobjtype
+ return concretetype.nameof(c.value, debug=debug)
- def nameofvalue(self, value, type_cls):
- crepr = self.getrepresenter(type_cls)
- return crepr.nameof(value)
+ def nameofvalue(self, value, concretetype=None, debug=None):
+ return (concretetype or self.pyobjtype).nameof(value, debug=debug)
def getfuncdef(self, func):
if func not in self.funcdefs:
@@ -86,7 +73,7 @@
info = {
'modname': self.modname,
'entrypointname': self.translator.functions[0].__name__,
- 'entrypoint': self.pyobjrepr.nameof(self.translator.functions[0]),
+ 'entrypoint': self.pyobjtype.nameof(self.translator.functions[0]),
}
# header
if USE_CALL_TRACE:
@@ -97,10 +84,6 @@
while self.pendingfunctions:
funcdef = self.pendingfunctions.pop()
self.gen_cfunction(funcdef)
- # collect more of the latercode after each function
- for crepr in self.ctyperepresenters.values():
- if hasattr(crepr, 'collect_globals'):
- crepr.collect_globals()
self.gen_global_declarations()
# after all the ff_xxx() functions we generate the pyff_xxx() wrappers
@@ -110,7 +93,7 @@
# global object table
print >> f, self.C_OBJECT_TABLE
- for name in self.pyobjrepr.globalobjects:
+ for name in self.pyobjtype.globalobjects:
if not name.startswith('gfunc_'):
print >> f, '\t{&%s, "%s"},' % (name, name)
print >> f, self.C_TABLE_END
@@ -128,7 +111,7 @@
# frozen init bytecode
print >> f, self.C_FROZEN_BEGIN
- bytecode = self.pyobjrepr.getfrozenbytecode()
+ bytecode = self.pyobjtype.getfrozenbytecode(self)
def char_repr(c):
if c in '\\"': return '\\' + c
if ' ' <= c < '\x7F': return c
@@ -144,6 +127,11 @@
print >> f, self.C_FOOTER % info
def gen_global_declarations(self):
+ # collect more of the latercode between the functions,
+ # and produce the corresponding global declarations
+ for ct in self.translator.concretetypes.values():
+ if hasattr(ct, 'collect_globals'):
+ self.globaldecl += ct.collect_globals(self)
g = self.globaldecl
if g:
f = self.f
Deleted: /pypy/dist/pypy/translator/genc/parametric.py
==============================================================================
--- /pypy/dist/pypy/translator/genc/parametric.py Fri Apr 8 13:29:42 2005
+++ (empty file)
@@ -1,41 +0,0 @@
-import types
-
-
-class parametrictype(type):
- """The metaclass of parametric type classes."""
-
- def __getitem__(cls, key):
- if '_parametrizedinstances_' not in cls.__dict__:
- cls._parametrizedinstances_ = {}
- elif cls._parametrizedinstances_ is None:
- raise TypeError, "'%s' is already specialized" % cls.__name__
- try:
- return cls._parametrizedinstances_[key]
- except KeyError:
- keyrepr = recrepr(key)
- if keyrepr.startswith('(') and keyrepr.endswith(')') and key != ():
- keyrepr = keyrepr[1:-1]
- newname = '%s[%s]' % (cls.__name__, keyrepr)
- CType_Parametrized = type(cls)(newname, (cls,), {
- '_parametrizedinstances_': None,
- '__module__': cls.__module__,
- })
- cls._parametrizedinstances_[key] = CType_Parametrized
- for basecls in CType_Parametrized.__mro__:
- raw = basecls.__dict__.get('__initsubclass__')
- if isinstance(raw, types.FunctionType):
- raw(CType_Parametrized, key) # call it as a class method
- return CType_Parametrized
-
-
-def recrepr(key):
- if isinstance(key, tuple):
- items = [recrepr(x) for x in key]
- if len(items) == 1:
- return '(%s,)' % (items[0],)
- else:
- return '(%s)' % (', '.join(items),)
- try:
- return key.__name__
- except AttributeError:
- return repr(key)
Modified: pypy/dist/pypy/translator/genc/t_func.py
==============================================================================
--- pypy/dist/pypy/translator/genc/t_func.py (original)
+++ pypy/dist/pypy/translator/genc/t_func.py Fri Apr 8 13:29:42 2005
@@ -1,19 +1,29 @@
-from pypy.translator.genc.parametric import parametrictype
+from pypy.translator.genc.t_simple import CType
-class CType_FuncPtr:
- __metaclass__ = parametrictype
+class CFuncPtrType(CType):
+ error_return = 'NULL'
- def __initsubclass__(cls, key):
- cls.args_typecls = key[:-1]
- cls.return_typecls = key[-1]
- arglist = [tc.ctypetemplate % ('',) for tc in cls.args_typecls]
+ def __init__(self, translator, argtypes, returntype):
+ super(CFuncPtrType, self).__init__(translator)
+ self.argtypes = argtypes
+ self.returntype = returntype
+ # build a type declaration template matching the strange C syntax
+ # for function pointer types:
+ # <returntype> (*<name_to_insert_here>) (<argument types>)
+ # which becomes funny when <returntype> itself is a complex type;
+ # in that case, the whole rest of the line, i.e. the "(*..)(...)",
+ # is what should be inserted into the returntype's "%s".
+ arglist = [ct.ctypetemplate % ('',) for ct in argtypes]
argtemplate = ', '.join(arglist or ['void'])
header = '(*%s)(' + argtemplate + ')'
- cls.ctypetemplate = cls.return_typecls.ctypetemplate % (header,)
+ self.ctypetemplate = returntype.ctypetemplate % (header,)
- def __init__(self, genc):
- self.genc = genc
+ def debugname(self):
+ # a nice textual name for debugging...
+ argnames = [ct.debugname() for ct in self.argtypes]
+ returnname = self.returntype.debugname()
+ return 'fn (%s) -> %s' % (', '.join(argnames), returnname)
def nameof(self, func, debug=None):
- return self.genc.getfuncdef(func).fast_name
+ return self.genc().getfuncdef(func).fast_name
Deleted: /pypy/dist/pypy/translator/genc/t_int.py
==============================================================================
--- /pypy/dist/pypy/translator/genc/t_int.py Fri Apr 8 13:29:42 2005
+++ (empty file)
@@ -1,27 +0,0 @@
-
-
-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
-
-
-class CType_None:
- ctypetemplate = 'int %s'
- convert_to_obj = 'none2obj'
- convert_from_obj = 'obj2none'
- error_return = '-1'
-
- def __init__(self, genc):
- pass
-
- def nameof(self, v, debug=None):
- assert v is None
- return '0'
Modified: pypy/dist/pypy/translator/genc/t_pyobj.py
==============================================================================
--- pypy/dist/pypy/translator/genc/t_pyobj.py (original)
+++ pypy/dist/pypy/translator/genc/t_pyobj.py Fri Apr 8 13:29:42 2005
@@ -1,13 +1,14 @@
from __future__ import generators
import autopath, os, sys, __builtin__, marshal, zlib
from pypy.objspace.flow.model import Variable, Constant
-from pypy.translator.gensupp import builtin_base
+from pypy.translator.gensupp import builtin_base, NameManager
+from pypy.translator.genc.t_simple import CType
from types import FunctionType, CodeType, InstanceType, ClassType
from pypy.objspace.std.restricted_int import r_int, r_uint
-class CType_PyObject:
+class CPyObjectType(CType):
"""The PyObject* C type.
This class contains all the nameof_xxx() methods that allow a wild variety
of Python objects to be 'pickled' as Python source code that will
@@ -16,9 +17,24 @@
ctypetemplate = 'PyObject *%s'
cincref = 'Py_INCREF(%s);'
cdecref = 'Py_DECREF(%s);'
+ error_return = 'NULL'
- def __init__(self, genc):
- self.genc = genc
+ def __init__(self, translator):
+ self.translator = translator
+ 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
+ ''')
self.cnames = {Constant(None).key: 'Py_None',
Constant(False).key: 'Py_False',
Constant(True).key: 'Py_True',
@@ -30,6 +46,7 @@
'Py_True = True',
]
+ self.globaldecl = []
self.latercode = [] # list of generators generating extra lines
# for later in initxxx() -- for recursive
# objects
@@ -66,9 +83,9 @@
return name
def uniquename(self, basename):
- name = self.genc.namespace.uniquename(basename)
+ name = self.namespace.uniquename(basename)
self.globalobjects.append(name)
- self.genc.globaldecl.append('static PyObject *%s;' % (name,))
+ self.globaldecl.append('static PyObject *%s;' % (name,))
return name
def initcode_python(self, name, pyexpr):
@@ -136,7 +153,7 @@
def skipped_function(self, func):
# debugging only! Generates a placeholder for missing functions
# that raises an exception when called.
- if self.genc.translator.frozen:
+ if self.translator.frozen:
warning = 'NOT GENERATING'
else:
warning = 'skipped'
@@ -152,10 +169,10 @@
def nameof_function(self, func, progress=['-\x08', '\\\x08',
'|\x08', '/\x08']):
- funcdef = self.genc.getfuncdef(func)
+ funcdef = self.genc().getfuncdef(func)
if funcdef is None:
return self.skipped_function(func)
- if not self.genc.translator.frozen:
+ if not self.translator.frozen:
p = progress.pop(0)
sys.stderr.write(p)
progress.append(p)
@@ -183,7 +200,7 @@
return name
def should_translate_attr(self, pbc, attr):
- ann = self.genc.translator.annotator
+ ann = self.translator.annotator
if ann is None:
ignore = getattr(pbc.__class__, 'NOT_RPYTHON_ATTRIBUTES', [])
if attr in ignore:
@@ -288,12 +305,12 @@
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.genc.translator.flowgraphs and self.genc.translator.frozen:
+ 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.genc.translator.flowgraphs and self.genc.translator.frozen:
+ if isinstance(value, FunctionType) and value not in self.translator.flowgraphs and self.translator.frozen:
print value
continue
@@ -408,26 +425,29 @@
def later(self, gen):
self.latercode.append((gen, self.debugstack))
- def collect_globals(self):
+ def collect_globals(self, genc):
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 = ()
- if self.genc.f2 is not None:
+ if genc.f2 is not None:
for line in self.initcode:
- print >> self.genc.f2, line
+ print >> genc.f2, line
del self.initcode[:]
-
- def getfrozenbytecode(self):
- if self.genc.f2 is not None:
- self.genc.f2.seek(0)
- self.initcode.insert(0, self.genc.f2.read())
+ result = self.globaldecl
+ self.globaldecl = []
+ return result
+
+ def getfrozenbytecode(self, genc):
+ if genc.f2 is not None:
+ genc.f2.seek(0)
+ self.initcode.insert(0, genc.f2.read())
self.initcode.append('')
source = '\n'.join(self.initcode)
del self.initcode[:]
- co = compile(source, self.genc.modname, 'exec')
+ co = compile(source, genc.modname, 'exec')
del source
small = zlib.compress(marshal.dumps(co))
source = """if 1:
@@ -435,10 +455,6 @@
exec marshal.loads(zlib.decompress(%r))""" % small
# Python 2.2 SyntaxError without newline: Bug #501622
source += '\n'
- co = compile(source, self.genc.modname, 'exec')
+ co = compile(source, genc.modname, 'exec')
del source
return marshal.dumps(co)
-
-
-def ctypeof(v):
- return getattr(v, 'type_cls', CType_PyObject)
Copied: pypy/dist/pypy/translator/genc/t_simple.py (from r10428, pypy/dist/pypy/translator/genc/t_int.py)
==============================================================================
--- pypy/dist/pypy/translator/genc/t_int.py (original)
+++ pypy/dist/pypy/translator/genc/t_simple.py Fri Apr 8 13:29:42 2005
@@ -1,26 +1,47 @@
+from pypy.annotation.model import SomeInteger, SomePBC
+from pypy.objspace.flow.model import SpaceOperation
+from pypy.interpreter.miscutils import getthreadlocals
-class CType_Int:
- ctypetemplate = 'int %s'
- convert_to_obj = 'int2obj'
- convert_from_obj = 'obj2int'
- error_return = '-1'
+class CType(object):
+ cincref = None
+ cdecref = None
- def __init__(self, genc):
- pass
+ def __init__(self, translator):
+ self.translator = translator
- def nameof(self, v, debug=None):
- return '%d' % v
+ def convert_to_obj(self, v1, v2):
+ return [SpaceOperation(self.opname_conv_to_obj, [v1], v2)]
+
+ def convert_from_obj(self, v1, v2):
+ return [SpaceOperation(self.opname_conv_from_obj, [v1], v2)]
+
+ def debugname(self):
+ return self.__class__.__name__
+
+ def genc():
+ """A hack to get at the currently running GenC instance."""
+ return getthreadlocals().genc
+ genc = staticmethod(genc)
-class CType_None:
- ctypetemplate = 'int %s'
- convert_to_obj = 'none2obj'
- convert_from_obj = 'obj2none'
- error_return = '-1'
+class CIntType(CType):
+ error_return = '-1'
+ ctypetemplate = 'int %s'
+ s_annotation = SomeInteger()
+ opname_conv_to_obj = 'int2obj'
+ opname_conv_from_obj = 'obj2int'
+
+ def nameof(self, v, debug=None):
+ return '%d' % (v,)
+
- def __init__(self, genc):
- pass
+class CNoneType(CType):
+ error_return = '-1'
+ ctypetemplate = 'int %s'
+ s_annotation = SomePBC({None: True})
+ opname_conv_to_obj = 'none2obj'
+ opname_conv_from_obj = 'obj2none'
def nameof(self, v, debug=None):
assert v is None
Modified: pypy/dist/pypy/translator/tool/graphpage.py
==============================================================================
--- pypy/dist/pypy/translator/tool/graphpage.py (original)
+++ pypy/dist/pypy/translator/tool/graphpage.py Fri Apr 8 13:29:42 2005
@@ -127,9 +127,10 @@
def visit(node):
if isinstance(node, Block):
for var in node.getvariables():
- if hasattr(var, 'type_cls'):
+ if hasattr(var, 'concretetype'):
+ typename = var.concretetype.debugname()
info = self.links.get(var.name, var.name)
- info = '(%s) %s' % (var.type_cls.__name__, info)
+ info = '(%s) %s' % (typename, info)
self.links[var.name] = info
for graph in graphs:
traverse(visit, graph)
Modified: pypy/dist/pypy/translator/translator.py
==============================================================================
--- pypy/dist/pypy/translator/translator.py (original)
+++ pypy/dist/pypy/translator/translator.py Fri Apr 8 13:29:42 2005
@@ -63,6 +63,7 @@
self.functions = [] # the keys of self.flowgraphs, in creation order
self.callgraph = {} # {opaque_tag: (caller, callee)}
self.frozen = False # when frozen, no more flowgraphs can be generated
+ self.concretetypes = {} # see getconcretetype()
if self.entrypoint:
self.getflowgraph()
@@ -265,6 +266,17 @@
## # not actually start the analysis of the called function yet.
## return impossiblevalue
+ def getconcretetype(self, cls, *args):
+ # Return a (cached) 'concrete type' object attached to this translator.
+ # Concrete types are what is put in the 'concretetype' attribute of
+ # the Variables and Constants of the flow graphs by typer.py to guide
+ # the code generators.
+ try:
+ return self.concretetypes[cls, args]
+ except KeyError:
+ result = self.concretetypes[cls, args] = cls(self, *args)
+ return result
+
if __name__ == '__main__':
from pypy.translator.test import snippet as test
Modified: pypy/dist/pypy/translator/typer.py
==============================================================================
--- pypy/dist/pypy/translator/typer.py (original)
+++ pypy/dist/pypy/translator/typer.py Fri Apr 8 13:29:42 2005
@@ -4,91 +4,89 @@
from pypy.translator.unsimplify import insert_empty_block
-class TypeMatch:
- def __init__(self, s_type, type_cls):
- self.s_type = s_type
- self.type_cls = type_cls
-
class TyperError(Exception):
pass
class Specializer:
- specializationdict = {}
- def __init__(self, annotator):
- if not self.specializationdict:
- # setup the class
- d = self.specializationdict
- for e in self.specializationtable:
- opname1 = e[0]
- opname2 = e[1]
- spectypes = e[2:-1]
- restypecls = e[-1]
- info = opname2, spectypes, restypecls
- d.setdefault(opname1, []).append(info)
- d.setdefault(opname2, []).append(info)
+ def __init__(self, annotator, defaultconcretetype, typematches,
+ specializationtable):
self.annotator = annotator
+ self.defaultconcretetype = defaultconcretetype
+ self.typematches = typematches
+ # turn the table into a dict for faster look-ups
+ d = {}
+ for e in specializationtable:
+ opname1 = e[0]
+ opname2 = e[1]
+ spectypes = e[2:-1]
+ restype = e[-1]
+ info = opname2, spectypes, restype
+ d.setdefault(opname1, []).append(info)
+ d.setdefault(opname2, []).append(info)
+ self.specializationdict = d
def specialize(self):
for block in self.annotator.annotated:
if block.operations != ():
self.specialize_block(block)
- def settype(self, a, type_cls):
- """Set the type_cls of a Variable or Constant."""
- if hasattr(a, 'type_cls') and a.type_cls != type_cls:
+ def settype(self, a, concretetype):
+ """Set the concretetype of a Variable or Constant."""
+ if hasattr(a, 'concretetype') and a.concretetype != concretetype:
raise TyperError, "inconsitent type for %r" % (a,)
- a.type_cls = type_cls
+ a.concretetype = concretetype
def setbesttype(self, a):
- """Set the best type_cls for a Variable or Constant according to
+ """Set the best concretetype for a Variable or Constant according to
the annotations."""
try:
- return a.type_cls
+ return a.concretetype
except AttributeError:
- besttype = self.defaulttypecls
s_value = self.annotator.binding(a, True)
if s_value is not None:
- besttype = self.annotation2typecls(s_value) or besttype
+ besttype = self.annotation2concretetype(s_value)
+ else:
+ besttype = self.defaultconcretetype
self.settype(a, besttype)
return besttype
- def annotation2typecls(self, s_value):
- for tmatch in self.typematches:
- if tmatch.s_type.contains(s_value):
- return tmatch.type_cls
- return None
+ def annotation2concretetype(self, s_value):
+ for concretetype in self.typematches:
+ if concretetype.s_annotation.contains(s_value):
+ return concretetype
+ return self.defaultconcretetype
- def convertvar(self, v, type_cls):
+ def convertvar(self, v, concretetype):
"""Get the operation(s) needed to convert 'v' to the given type."""
ops = []
if isinstance(v, Constant):
try:
# mark the concrete type of the Constant
- self.settype(v, type_cls)
+ self.settype(v, concretetype)
except TyperError:
v = Constant(v.value) # need a copy of the Constant
- self.settype(v, type_cls)
+ self.settype(v, concretetype)
- elif v.type_cls is not type_cls:
+ elif v.concretetype != concretetype:
# XXX do we need better conversion paths?
# 1) convert to the generic type
- if v.type_cls is not self.defaulttypecls:
+ if v.concretetype != self.defaultconcretetype:
v2 = Variable()
- v2.type_cls = self.defaulttypecls
- op = SpaceOperation(v.type_cls.convert_to_obj, [v], v2)
+ v2.concretetype = self.defaultconcretetype
+ newops = list(v.concretetype.convert_to_obj(v, v2))
v = v2
- ops.append(op)
+ ops += newops
# 2) convert back from the generic type
- if type_cls is not self.defaulttypecls:
+ if concretetype != self.defaultconcretetype:
v2 = Variable()
- v2.type_cls = type_cls
- op = SpaceOperation(type_cls.convert_from_obj, [v], v2)
+ v2.concretetype = concretetype
+ newops = list(concretetype.convert_from_obj(v, v2))
v = v2
- ops.append(op)
+ ops += newops
return v, ops
@@ -98,41 +96,46 @@
self.setbesttype(a)
# specialize all the operations, as far as possible
- newops = []
+ self.newops = []
for op in block.operations:
- indices = range(len(op.args))
args = list(op.args)
bindings = [self.annotator.binding(a, True) for a in args]
# replace constant annotations with real Constants
- for i in indices:
+ for i in range(len(op.args)):
if isinstance(args[i], Variable) and bindings[i] is not None:
if bindings[i].is_constant():
args[i] = Constant(bindings[i].const)
op = SpaceOperation(op.opname, args, op.result)
- # look for a specialized version of the current operation
- opname2, argtypes, restypecls = self.getspecializedop(op, bindings)
- assert len(argtypes) == len(args)
-
- # type-convert the input arguments
- for i in indices:
- args[i], convops = self.convertvar(args[i], argtypes[i])
- newops += convops
-
- # store the result variable's type
- self.settype(op.result, restypecls)
-
- # store the possibly modified SpaceOperation
- if opname2 != op.opname or args != op.args:
- op = SpaceOperation(opname2, args, op.result)
- newops.append(op)
-
- block.operations[:] = newops
+ # make a specialized version of the current operation
+ # (which may become several operations)
+ self.make_specialized_op(op, bindings)
+ block.operations[:] = self.newops
self.insert_link_conversions(block)
+
+ def make_typed_op(self, op, argtypes, restype, newopname=None):
+ """Make a typed copy of the given SpaceOperation."""
+ args = list(op.args)
+ assert len(argtypes) == len(args)
+
+ # type-convert the input arguments
+ for i in range(len(args)):
+ args[i], convops = self.convertvar(args[i], argtypes[i])
+ self.newops += convops
+
+ # store the result variable's type
+ self.settype(op.result, restype)
+
+ # store the possibly modified SpaceOperation
+ if newopname is not None or args != op.args:
+ op = SpaceOperation(newopname or op.opname, args, op.result)
+ self.newops.append(op)
+
+
def insert_link_conversions(self, block):
# insert the needed conversions on the links
can_insert_here = block.exitswitch is None and len(block.exits) == 1
@@ -154,23 +157,20 @@
block.operations += convops
link.args[i] = a1
- def getspecializedop(self, op, bindings):
+
+ def make_specialized_op(self, op, bindings):
specializations = self.specializationdict.get(op.opname, ())
- for opname2, spectypes, restypecls in specializations:
+ for opname2, spectypes, restype in specializations:
assert len(spectypes) == len(op.args) == len(bindings)
for i in range(len(spectypes)):
if bindings[i] is None:
break
- if not spectypes[i].s_type.contains(bindings[i]):
+ if not spectypes[i].s_annotation.contains(bindings[i]):
break
else:
# specialization found
- # opname2 and restypecls are set above by the for loop
- argtypes = [tmatch.type_cls for tmatch in spectypes]
- break
- else:
- # specialization not found
- opname2 = op.opname
- argtypes = [self.defaulttypecls] * len(op.args)
- restypecls = self.defaulttypecls
- return opname2, argtypes, restypecls
+ self.make_typed_op(op, spectypes, restype, newopname=opname2)
+ return
+ # specialization not found
+ argtypes = [self.defaultconcretetype] * len(op.args)
+ self.make_typed_op(op, argtypes, self.defaultconcretetype)
Modified: pypy/dist/pypy/translator/unsimplify.py
==============================================================================
--- pypy/dist/pypy/translator/unsimplify.py (original)
+++ pypy/dist/pypy/translator/unsimplify.py Fri Apr 8 13:29:42 2005
@@ -1,14 +1,14 @@
from pypy.objspace.flow.model import *
def copyvar(translator, v):
- """Make a copy of the Variable v, preserving annotations and type_cls."""
+ """Make a copy of the Variable v, preserving annotations and concretetype."""
assert isinstance(v, Variable)
newvar = Variable(v)
annotator = translator.annotator
if annotator is not None and v in annotator.bindings:
annotator.bindings[newvar] = annotator.bindings[v]
- if hasattr(v, 'type_cls'):
- newvar.type_cls = v.type_cls
+ if hasattr(v, 'concretetype'):
+ newvar.concretetype = v.concretetype
return newvar
def insert_empty_block(translator, link):
More information about the Pypy-commit
mailing list