[pypy-svn] r12868 - in pypy/dist/pypy/translator/c: . test
arigo at codespeak.net
arigo at codespeak.net
Sun May 29 16:20:58 CEST 2005
Author: arigo
Date: Sun May 29 16:20:58 2005
New Revision: 12868
Added:
pypy/dist/pypy/translator/c/int_include.h
- copied unchanged from r12866, pypy/dist/pypy/translator/genc/int_include.h
pypy/dist/pypy/translator/c/wrapper.py (contents, props changed)
Modified:
pypy/dist/pypy/translator/c/database.py
pypy/dist/pypy/translator/c/funcgen.py
pypy/dist/pypy/translator/c/g_include.h
pypy/dist/pypy/translator/c/g_support.h
pypy/dist/pypy/translator/c/genc.py
pypy/dist/pypy/translator/c/node.py
pypy/dist/pypy/translator/c/pyobj.py
pypy/dist/pypy/translator/c/test/test_database.py
pypy/dist/pypy/translator/c/test/test_genc.py
Log:
Reintroduced the PyObject wrappers for C functions.
Now we can again write tests that compile and run C code.
Modified: pypy/dist/pypy/translator/c/database.py
==============================================================================
--- pypy/dist/pypy/translator/c/database.py (original)
+++ pypy/dist/pypy/translator/c/database.py Sun May 29 16:20:58 2005
@@ -13,13 +13,13 @@
class LowLevelDatabase:
- def __init__(self):
+ def __init__(self, rtyper=None):
self.structdefnodes = {}
self.structdeflist = []
self.containernodes = {}
self.containerlist = []
self.namespace = CNameManager()
- self.pyobjmaker = PyObjMaker(self.namespace, self.get)
+ self.pyobjmaker = PyObjMaker(self.namespace, self.get, rtyper)
def gettypedefnode(self, T, varlength=1):
if varlength <= 1:
Modified: pypy/dist/pypy/translator/c/funcgen.py
==============================================================================
--- pypy/dist/pypy/translator/c/funcgen.py (original)
+++ pypy/dist/pypy/translator/c/funcgen.py Sun May 29 16:20:58 2005
@@ -34,6 +34,7 @@
result.extend(block.inputargs)
for op in block.operations:
result.extend(op.args)
+ result.append(op.result)
for link in block.exits:
result.extend(link.args)
traverse(visit, self.graph)
@@ -61,10 +62,6 @@
if isinstance(v, Constant):
yield llvalue_from_constant(v)
- def decl(self, v):
- assert isinstance(v, Variable), repr(v)
- return cdecl(self.typemap[v], v.name)
-
def expr(self, v):
if isinstance(v, Variable):
return v.name
@@ -87,7 +84,10 @@
for v in self.allvariables():
if v not in inputargset:
- yield '%s;' % self.decl(v)
+ result = cdecl(self.typemap[v], v.name) + ';'
+ if self.lltypemap[v] == Void:
+ result = '/*%s*/' % result
+ yield result
# ____________________________________________________________
@@ -122,7 +122,9 @@
line += '\t' + self.cincref(a2)
yield line
for v in has_ref:
- yield self.cdecref(v, linklocalvars[v])
+ line = self.cdecref(v, linklocalvars[v])
+ if line:
+ yield line
yield 'goto block%d;' % blocknum[link.target]
# collect all blocks
Modified: pypy/dist/pypy/translator/c/g_include.h
==============================================================================
--- pypy/dist/pypy/translator/c/g_include.h (original)
+++ pypy/dist/pypy/translator/c/g_include.h Sun May 29 16:20:58 2005
@@ -14,4 +14,5 @@
#include "g_support.h"
#include "g_module.h"
+#include "int_include.h"
#include "pyobj_include.h"
Modified: pypy/dist/pypy/translator/c/g_support.h
==============================================================================
--- pypy/dist/pypy/translator/c/g_support.h (original)
+++ pypy/dist/pypy/translator/c/g_support.h Sun May 29 16:20:58 2005
@@ -9,8 +9,6 @@
#define MIN(a,b) (((a)<(b))?(a):(b))
#endif /* MIN */
-#define MOVE(x, y) y = x;
-
#define FAIL_EXCEPTION(err, exc, msg) \
{ \
PyErr_SetString(exc, msg); \
@@ -336,7 +334,7 @@
}
PyErr_Format(PyExc_TypeError, "%s() got only %d argument(s)",
PyString_AS_STRING(fname),
- position-1);
+ position);
return NULL;
}
Modified: pypy/dist/pypy/translator/c/genc.py
==============================================================================
--- pypy/dist/pypy/translator/c/genc.py (original)
+++ pypy/dist/pypy/translator/c/genc.py Sun May 29 16:20:58 2005
@@ -44,6 +44,7 @@
#
# PyObject support (strange) code
#
+ pyobjmaker = database.pyobjmaker
print >> f
print >> f, '/***********************************************************/'
print >> f, '/*** Table of global PyObjects ***/'
@@ -52,7 +53,7 @@
for node in database.globalcontainers():
if isinstance(node, PyObjectNode):
name = node.name
- if not name.startswith('gfunc_'):
+ if name not in pyobjmaker.wrappers:
print >> f, '\t{&%s, "%s"},' % (name, name)
print >> f, '\t{ NULL }\t/* Sentinel */'
print >> f, '};'
@@ -61,7 +62,14 @@
print >> f, '/*** Table of functions ***/'
print >> f
print >> f, 'static globalfunctiondef_t globalfunctiondefs[] = {'
- print >> f, '\t/* XXX */'
+ wrappers = pyobjmaker.wrappers.items()
+ wrappers.sort()
+ for globalobject_name, (base_name, wrapper_name) in wrappers:
+ print >> f, ('\t{&%s, {"%s", (PyCFunction)%s, '
+ 'METH_VARARGS|METH_KEYWORDS}},' % (
+ globalobject_name,
+ base_name,
+ wrapper_name))
print >> f, '\t{ NULL }\t/* Sentinel */'
print >> f, '};'
print >> f
Modified: pypy/dist/pypy/translator/c/node.py
==============================================================================
--- pypy/dist/pypy/translator/c/node.py (original)
+++ pypy/dist/pypy/translator/c/node.py Sun May 29 16:20:58 2005
@@ -246,6 +246,41 @@
yield '}'
+class CExternalFuncNode(ContainerNode):
+ globalcontainer = True
+
+ def __init__(self, db, T, obj):
+ self.db = db
+ self.T = T
+ self.obj = obj
+ #self.dependencies = {}
+ self.typename = db.gettype(T) #, who_asks=self)
+ self.name = obj._name
+ self.ptrname = self.name
+
+ def enum_dependencies(self):
+ return []
+
+ def implementation(self):
+ return []
+
+ def forward_declaration(self):
+ return []
+
+ def implementation(self):
+ return []
+
+
+def funcnodemaker(db, T, obj):
+ if hasattr(obj, 'graph'):
+ cls = FuncNode
+ elif getattr(obj, 'external', None) == 'C':
+ cls = CExternalFuncNode
+ else:
+ raise ValueError, "don't know about %r" % (obj,)
+ return cls(db, T, obj)
+
+
class PyObjectNode(ContainerNode):
globalcontainer = True
typename = 'PyObject @'
@@ -271,6 +306,6 @@
GcStruct: StructNode,
Array: ArrayNode,
GcArray: ArrayNode,
- FuncType: FuncNode,
+ FuncType: funcnodemaker,
PyObjectType: PyObjectNode,
}
Modified: pypy/dist/pypy/translator/c/pyobj.py
==============================================================================
--- pypy/dist/pypy/translator/c/pyobj.py (original)
+++ pypy/dist/pypy/translator/c/pyobj.py Sun May 29 16:20:58 2005
@@ -22,9 +22,10 @@
reconstruct them.
"""
- def __init__(self, namespace, getvalue):
+ def __init__(self, namespace, getvalue, rtyper=None):
self.namespace = namespace
self.getvalue = getvalue
+ self.rtyper = rtyper
self.initcode = [ # list of lines for the module's initxxx()
'import new, types, sys',
]
@@ -33,6 +34,7 @@
# for later in initxxx() -- for recursive
# objects
self.debugstack = () # linked list of nested nameof()
+ self.wrappers = {} # {'pycfunctionvariable': ('name', 'wrapperfn')}
def nameof(self, obj, debug=None):
if debug:
@@ -141,16 +143,25 @@
self.initcode.append(' raise NotImplementedError')
return name
- def nameof_function(self, func, progress=['-\x08', '\\\x08',
- '|\x08', '/\x08']):
- funcdef = self.genc().getfuncdef(func)
- if funcdef is None:
- return self.skipped_function(func)
- if not self.translator.frozen:
- p = progress.pop(0)
- sys.stderr.write(p)
- progress.append(p)
- return funcdef.get_globalobject()
+ def nameof_function(self, func):
+ assert self.rtyper is not None, (
+ "for now, rtyper must be specified to build a PyObject "
+ "wrapper for %r" % (func,))
+ # look for skipped functions
+ a = self.rtyper.annotator
+ if a.translator.frozen:
+ if func not in a.translator.flowgraphs:
+ return self.skipped_function(func)
+ else:
+ if (func.func_doc and
+ func.func_doc.lstrip().startswith('NOT_RPYTHON')):
+ return self.skipped_function(func)
+
+ from pypy.translator.c.wrapper import gen_wrapper
+ fwrapper = gen_wrapper(func, self.rtyper)
+ pycfunctionobj = self.uniquename('gfunc_' + func.__name__)
+ self.wrappers[pycfunctionobj] = func.__name__, self.getvalue(fwrapper)
+ return pycfunctionobj
def nameof_staticmethod(self, sm):
# XXX XXX XXXX
Modified: pypy/dist/pypy/translator/c/test/test_database.py
==============================================================================
--- pypy/dist/pypy/translator/c/test/test_database.py (original)
+++ pypy/dist/pypy/translator/c/test/test_database.py Sun May 29 16:20:58 2005
@@ -181,10 +181,15 @@
db.complete()
dump_on_stdout(db)
-def INPROGRESS_test_func_as_pyobject():
+def test_func_as_pyobject():
def f(x):
return x+1
- db = LowLevelDatabase()
+ t = Translator(f)
+ a = t.annotate([int])
+ rtyper = RPythonTyper(t.annotator)
+ rtyper.specialize()
+
+ db = LowLevelDatabase(rtyper)
db.get(pyobjectptr(f))
db.complete()
dump_on_stdout(db)
Modified: pypy/dist/pypy/translator/c/test/test_genc.py
==============================================================================
--- pypy/dist/pypy/translator/c/test/test_genc.py (original)
+++ pypy/dist/pypy/translator/c/test/test_genc.py Sun May 29 16:20:58 2005
@@ -1,5 +1,6 @@
-import autopath, sys, os
+import autopath, sys, os, py
from pypy.rpython.lltype import *
+from pypy.rpython.rtyper import RPythonTyper
from pypy.translator.translator import Translator
from pypy.translator.c.database import LowLevelDatabase
from pypy.translator.c.genc import gen_source
@@ -14,8 +15,9 @@
modulename = uniquemodulename('testing')
targetdir = udir.join(modulename).ensure(dir=1)
gen_source(db, modulename, str(targetdir))
- make_module_from_c(targetdir.join(modulename+'.c'),
- include_dirs = [os.path.dirname(autopath.this_dir)])
+ m = make_module_from_c(targetdir.join(modulename+'.c'),
+ include_dirs = [os.path.dirname(autopath.this_dir)])
+ return m
def test_untyped_func():
@@ -33,3 +35,26 @@
db.get(s)
db.complete()
compile_db(db)
+
+
+def test_func_as_pyobject():
+ def f(x):
+ return x*2
+ t = Translator(f)
+ a = t.annotate([int])
+ rtyper = RPythonTyper(t.annotator)
+ rtyper.specialize()
+
+ db = LowLevelDatabase(rtyper)
+ entrypoint = db.get(pyobjectptr(f))
+ db.complete()
+ module = compile_db(db)
+
+ f1 = getattr(module, entrypoint)
+ assert f1(5) == 10
+ assert f1(x=5) == 10
+ assert f1(-123) == -246
+ py.test.raises(TypeError, f1, "world") # check that it's really typed
+ py.test.raises(TypeError, f1)
+ py.test.raises(TypeError, f1, 2, 3)
+ py.test.raises(TypeError, f1, 2, x=2)
Added: pypy/dist/pypy/translator/c/wrapper.py
==============================================================================
--- (empty file)
+++ pypy/dist/pypy/translator/c/wrapper.py Sun May 29 16:20:58 2005
@@ -0,0 +1,112 @@
+from pypy.objspace.flow.model import Variable, Constant, SpaceOperation
+from pypy.objspace.flow.model import Block, Link, FunctionGraph, checkgraph
+from pypy.annotation import model as annmodel
+from pypy.rpython.lltype import GcPtr, NonGcPtr, PyObject, typeOf, Signed, Void
+from pypy.rpython.lltype import FuncType, functionptr
+from pypy.rpython.rtyper import LowLevelOpList, inputconst
+from pypy.interpreter.pycode import CO_VARARGS
+
+
+def gen_wrapper(func, rtyper):
+ """generate a wrapper function for 'func' that can be put in a
+ PyCFunction object. The wrapper has signature
+
+ PyObject *pyfn_xxx(PyObject *self, PyObject *args, PyObject* kw);
+ """
+ # The basic idea is to produce a flow graph from scratch, using the
+ # help of the rtyper for the conversion of the arguments after they
+ # have been decoded.
+
+ # get the fully typed low-level pointer to the function, if available
+ nb_positional_args = func.func_code.co_argcount
+ vararg = bool(func.func_code.co_flags & CO_VARARGS)
+ f = rtyper.getfunctionptr(func)
+ FUNCTYPE = typeOf(f).TO
+ assert len(FUNCTYPE.ARGS) == nb_positional_args + vararg
+
+ newops = LowLevelOpList(rtyper)
+
+ # "def wrapper(self, args, kwds)"
+ vself = Variable('self')
+ vargs = Variable('args')
+ vkwds = Variable('kwds')
+ vfname = Constant(func.func_name)
+ # avoid incref/decref on the arguments: 'self' and 'kwds' can be NULL
+ vself.concretetype = NonGcPtr(PyObject)
+ vargs.concretetype = NonGcPtr(PyObject)
+ vkwds.concretetype = NonGcPtr(PyObject)
+
+ varguments = []
+ varnames = func.func_code.co_varnames
+ func_defaults = func.func_defaults or ()
+ for i in range(nb_positional_args):
+ # "argument_i = decode_arg(fname, i, name, vargs, vkwds)" or
+ # "argument_i = decode_arg_def(fname, i, name, vargs, vkwds, default)"
+ vlist = [vfname,
+ inputconst(Signed, i),
+ Constant(varnames[i]),
+ vargs,
+ vkwds]
+ try:
+ default_value = func_defaults[i - nb_positional_args]
+ except IndexError:
+ opname = 'decode_arg'
+ else:
+ opname = 'decode_arg_def'
+ vlist.append(Constant(default_value))
+
+ v = newops.genop(opname, vlist, resulttype=GcPtr(PyObject))
+ v._name = 'a%d' % i
+ varguments.append(v)
+
+ if vararg:
+ # "vararg = vargs[n:]"
+ vlist = [vargs,
+ Constant(nb_positional_args),
+ Constant(None),
+ ]
+ vararg = newops.genop('getslice', vlist, resulttype=GcPtr(PyObject))
+ vararg._name = 'vararg'
+ varguments.append(vararg)
+ else:
+ # "check_no_more_arg(fname, n, vargs)"
+ vlist = [vfname,
+ inputconst(Signed, nb_positional_args),
+ vargs,
+ ]
+ newops.genop('check_no_more_arg', vlist)
+
+ # use the rtyper to produce the conversions
+ inputargs = f._obj.graph.getargs()
+ for i in range(len(varguments)):
+ # "argument_i = type_conversion_operations(argument_i)"
+ s_arg = rtyper.annotator.binding(inputargs[i], True)
+ if s_arg is not None:
+ varguments[i] = newops.convertvar(varguments[i],
+ s_from = annmodel.SomeObject(),
+ s_to = s_arg)
+
+ # "result = direct_call(func, argument_0, argument_1, ..)"
+ vlist = [inputconst(typeOf(f), f)] + varguments
+ vresult = newops.genop('direct_call', vlist, resulttype=FUNCTYPE.RESULT)
+
+ # convert "result" back to a PyObject
+ s_result = rtyper.annotator.binding(f._obj.graph.getreturnvar(), True)
+ if s_result is not None:
+ vresult = newops.convertvar(vresult,
+ s_from = s_result,
+ s_to = annmodel.SomeObject())
+
+ # "return result"
+ block = Block([vself, vargs, vkwds])
+ wgraph = FunctionGraph('pyfn_' + func.func_name, block)
+ block.operations[:] = newops
+ block.closeblock(Link([vresult], wgraph.returnblock))
+ checkgraph(wgraph)
+
+ return functionptr(FuncType([NonGcPtr(PyObject),
+ NonGcPtr(PyObject),
+ NonGcPtr(PyObject)],
+ GcPtr(PyObject)),
+ wgraph.name,
+ graph = wgraph)
More information about the Pypy-commit
mailing list