[pypy-svn] r26154 - in pypy/dist/pypy/translator/c: . test
tismer at codespeak.net
tismer at codespeak.net
Sun Apr 23 03:50:29 CEST 2006
Author: tismer
Date: Sun Apr 23 03:50:26 2006
New Revision: 26154
Modified:
pypy/dist/pypy/translator/c/pyobj.py
pypy/dist/pypy/translator/c/test/test_wrapping.py
pypy/dist/pypy/translator/c/wrapper.py
Log:
creating instances as a side effect of __init__ was much much harder than expected.
__init__ needs to be cloned for every subclass that doesn't have its own.
Suppress wrapping of __del__ because it is supported by RPython already.
Modified: pypy/dist/pypy/translator/c/pyobj.py
==============================================================================
--- pypy/dist/pypy/translator/c/pyobj.py (original)
+++ pypy/dist/pypy/translator/c/pyobj.py Sun Apr 23 03:50:26 2006
@@ -2,10 +2,10 @@
import autopath, os, sys, __builtin__, marshal, zlib
from types import FunctionType, CodeType, InstanceType, ClassType
-from pypy.objspace.flow.model import Variable, Constant
+from pypy.objspace.flow.model import Variable, Constant, FunctionGraph
from pypy.translator.gensupp import builtin_base, builtin_type_base
from pypy.translator.c.support import log
-from pypy.translator.c.wrapper import gen_wrapper
+from pypy.translator.c.wrapper import gen_wrapper, new_method_graph
from pypy.rpython.rarithmetic import r_int, r_uint
from pypy.rpython.lltypesystem.lltype import pyobjectptr, LowLevelType
@@ -55,6 +55,8 @@
def computenameof(self, obj):
obj_builtin_base = builtin_base(obj)
if obj_builtin_base in (object, int, long) and type(obj) is not obj_builtin_base:
+ if isinstance(obj, FunctionGraph):
+ return self.nameof_graph(obj)
# assume it's a user defined thingy
return self.nameof_instance(obj)
else:
@@ -209,7 +211,8 @@
if self.shouldskipfunc(func):
return self.skipped_function(func)
- fwrapper = gen_wrapper(func, self.translator, self.name_for_meth.get(func, func.__name__))
+ fwrapper = gen_wrapper(func, self.translator,
+ newname=self.name_for_meth.get(func, func.__name__))
pycfunctionobj = self.uniquename('gfunc_' + func.__name__)
self.wrappers[pycfunctionobj] = func.__name__, self.getvalue(fwrapper), func.__doc__
return pycfunctionobj
@@ -371,7 +374,8 @@
ignore = getattr(cls, 'NOT_RPYTHON_ATTRIBUTES', [])
for key, value in content:
if key.startswith('__'):
- if key in ['__module__', '__doc__', '__dict__',
+ # we do not expose __del__, because it would be called twice
+ if key in ['__module__', '__doc__', '__dict__', '__del__',
'__weakref__', '__repr__', '__metaclass__']:
continue
# XXX some __NAMES__ are important... nicer solution sought
@@ -534,20 +538,46 @@
metaclass = "type"
name = self.uniquename('gwcls_' + cls.__name__)
basenames = [self.nameof(base) for base in cls.__bases__]
+ # we merge the class dicts for more speed
+ def merge_classdicts(cls):
+ dic = {}
+ for cls in cls.mro()[:-1]:
+ for key, value in cls.__dict__.items():
+ if key not in dic:
+ dic[key] = value
+ return dic
def initclassobj():
- content = cls.__dict__.items()
+ content = merge_classdicts(cls).items()
content.sort()
+ init_seen = False
for key, value in content:
if key.startswith('__'):
- if key in ['__module__', '__dict__', '__doc__',
+ # we do not expose __del__, because it would be called twice
+ if key in ['__module__', '__dict__', '__doc__', '__del__',
'__weakref__', '__repr__', '__metaclass__']:
continue
if self.shouldskipfunc(value):
log.WARNING("skipped class function: %r" % value)
continue
- if callable(value):
- self.name_for_meth[value] = '%s.%s' % (cls.__name__, value.__name__)
+ if isinstance(value, FunctionType):
+ func = value
+ fname = '%s.%s' % (cls.__name__, func.__name__)
+ if func.__name__ == '__init__':
+ init_seen = True
+ # there is the problem with exposed classes inheriting from
+ # classes which are internal. We need to create a new wrapper
+ # for every class which uses an inherited __init__, because
+ # this is the context where we create the instance.
+ ann = self.translator.annotator
+ clsdef = ann.bookkeeper.getuniqueclassdef(cls)
+ graph = ann.bookkeeper.getdesc(func).cachedgraph(None)
+ if ann.binding(graph.getargs()[0]).classdef is not clsdef:
+ value = new_method_graph(graph, clsdef, fname, self.translator)
+ self.name_for_meth[value] = fname
yield '%s.%s = %s' % (name, key, self.nameof(value))
+ if not init_seen:
+ log.WARNING('No __init__ found for %s - you cannot build instances' %
+ cls.__name__)
baseargs = ", ".join(basenames)
if baseargs:
@@ -561,3 +591,10 @@
a(' __slots__ = ["__self__"] # for PyCObject')
self.later(initclassobj())
return name
+
+ def nameof_graph(self, g):
+ newname=self.name_for_meth.get(g, g.func.__name__)
+ fwrapper = gen_wrapper(g, self.translator, newname=newname)
+ pycfunctionobj = self.uniquename('gfunc_' + newname)
+ self.wrappers[pycfunctionobj] = g.func.__name__, self.getvalue(fwrapper), g.func.__doc__
+ return pycfunctionobj
Modified: pypy/dist/pypy/translator/c/test/test_wrapping.py
==============================================================================
--- pypy/dist/pypy/translator/c/test/test_wrapping.py (original)
+++ pypy/dist/pypy/translator/c/test/test_wrapping.py Sun Apr 23 03:50:26 2006
@@ -7,7 +7,7 @@
from pypy.rpython import robject, rclass
from pypy.translator.tool.cbuild import enable_fast_compilation
-import sys
+import sys, types
P = False # debug printing
@@ -22,7 +22,7 @@
missing = [object] * (func.func_code.co_argcount - len(argstypelist))
return missing + argstypelist
-def get_compiled_module(func, view=conftest.option.view, inline_threshold=0*1,
+def get_compiled_module(func, view=conftest.option.view, inline_threshold=1,
use_boehm=False, exports=None):
from pypy.translator.translator import TranslationContext
from pypy.translator.backendopt.all import backend_optimizations
@@ -35,22 +35,20 @@
t.buildannotator()
rtyper = t.buildrtyper()
bk = rtyper.annotator.bookkeeper
- t.annotator.build_types(func, get_annotation(func))
if not exports:
exports = []
all = [obj.__name__ for obj in exports]
exports = exports + [('__all__', all)]
+
+ t.annotator.build_types(func, get_annotation(func))
+
for obj in exports:
if isinstance(obj, type):
clsdef = bk.getuniqueclassdef(obj)
rtyper.add_wrapper(clsdef)
- # pull it all out
- for name, value in obj.__dict__.items():
- continue # do we want that
- if callable(value):
- t.annotator.build_types(value, get_annotation(value))
- elif callable(obj):
+ elif isinstance(obj, types.FunctionType):
t.annotator.build_types(obj, get_annotation(obj))
+
if view:
t.viewcg()
rtyper.specialize()
@@ -70,10 +68,10 @@
# explicit build of database
db = cbuilder.build_database(exports=exports)
cbuilder.generate_source(db)
- cbuilder.compile()
-
if view:
t.viewcg()
+ cbuilder.compile()
+
return cbuilder.import_module()
def getcompiled(func, *args, **kwds):
@@ -142,10 +140,6 @@
delmonitor = DelMonitor()
class DemoBaseNotExposed(object):
- pass
-
-# a trivial class to be exposed
-class DemoClass(DemoBaseNotExposed):
"""this is the doc string"""
def __init__(self, a, b):
self.a = a
@@ -157,6 +151,9 @@
if P:print 'demo'
return self.a + self.b
+
+# a trivial class to be exposed
+class DemoClass(DemoBaseNotExposed):
def demonotcalled(self):
return self.demo() + 42
@@ -283,17 +280,19 @@
assert res == DemoClass(2, 3).demo()
def t(a=int, b=int, c=DemoClass):
- DemoClass(a, b).demo()
+ x = DemoClass(a, b)
+ x.demo()
DemoSubclass(a, a, b).demo()
DemoSubclass(a, a, b).demo(6)
- DemoSubclass(a, a, b).demo(6, 'hu')
+ y = DemoSubclass(a, a, b).demo(6, 'hu')
if isinstance(c, DemoSubclass):
print 42
-
+ return DemoBaseNotExposed(17, 4) # see if it works without wrapper
+
# exposing and using classes from a generasted extension module
def test_asd():
m = get_compiled_module(t, use_boehm=not True, exports=[
- DemoClass, DemoSubclass, DemoNotAnnotated, setup_new_module])
+ DemoClass, DemoSubclass, DemoNotAnnotated])
obj = m.DemoClass(2, 3)
res = obj.demo()
assert res == DemoClass(2, 3).demo()
Modified: pypy/dist/pypy/translator/c/wrapper.py
==============================================================================
--- pypy/dist/pypy/translator/c/wrapper.py (original)
+++ pypy/dist/pypy/translator/c/wrapper.py Sun Apr 23 03:50:26 2006
@@ -1,14 +1,17 @@
from pypy.objspace.flow.model import Variable, Constant
from pypy.objspace.flow.model import Block, Link, FunctionGraph, checkgraph
from pypy.rpython.lltypesystem.lltype import \
- Ptr, PyObject, typeOf, Signed, FuncType, functionptr
+ Ptr, PyObject, typeOf, Signed, FuncType, functionptr, nullptr, Void
from pypy.rpython.rtyper import LowLevelOpList
from pypy.rpython.rmodel import inputconst, PyObjPtr
from pypy.rpython.robject import pyobj_repr
from pypy.interpreter.pycode import CO_VARARGS
from pypy.rpython.typesystem import getfunctionptr
+from pypy.annotation.model import s_None, SomeInstance
+from pypy.translator.backendopt.inline import simple_inline_function
+ALWAYS_INLINE = False
def gen_wrapper(func, translator, newname=None):
"""generate a wrapper function for 'func' that can be put in a
@@ -21,20 +24,28 @@
# 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)
+ do_inline = ALWAYS_INLINE
if translator.annotator is None:
# get the graph from the translator, "push it back" so that it's
# still available for further buildflowgraph() calls
graph = translator.buildflowgraph(func)
translator._prebuilt_graphs[func] = graph
else:
- bk = translator.annotator.bookkeeper
- graph = bk.getdesc(func).cachedgraph(None)
+ if isinstance(func, FunctionGraph):
+ graph = func
+ func = graph.func
+ # in this case we want to inline for sure, because we
+ # created this extra graph with a single call-site.
+ do_inline = True
+ else:
+ bk = translator.annotator.bookkeeper
+ graph = bk.getdesc(func).cachedgraph(None)
f = getfunctionptr(graph)
FUNCTYPE = typeOf(f).TO
+ nb_positional_args = func.func_code.co_argcount
+ vararg = bool(func.func_code.co_flags & CO_VARARGS)
assert len(FUNCTYPE.ARGS) == nb_positional_args + vararg
newops = LowLevelOpList(translator.rtyper)
@@ -133,6 +144,8 @@
# that need to be specialized now
translator.rtyper.specialize_more_blocks()
+ if do_inline:
+ simple_inline_function(translator, graph, wgraph)
return functionptr(FuncType([PyObjPtr,
PyObjPtr,
PyObjPtr],
@@ -140,3 +153,46 @@
wgraph.name,
graph = wgraph,
exception_policy = "CPython")
+
+def new_method_graph(graph, clsdef, newname, translator):
+ ann = translator.annotator
+ rtyper = translator.rtyper
+
+ f = getfunctionptr(graph)
+ FUNCTYPE = typeOf(f).TO
+
+ newops = LowLevelOpList(translator.rtyper)
+
+ callargs = graph.getargs()[:]
+ v_self_old = callargs.pop(0)
+ v_self = Variable(v_self_old.name)
+ binding = SomeInstance(clsdef)
+ v_self.concretetype = rtyper.getrepr(binding).lowleveltype
+ ann.setbinding(v_self, binding)
+ v_self_call = newops.convertvar(v_self,
+ r_from = rtyper.bindingrepr(v_self),
+ r_to = rtyper.bindingrepr(v_self_old))
+
+ vlist = [inputconst(typeOf(f), f)] + [v_self_call] + callargs
+ newops.genop('direct_call', vlist, resulttype=Void)
+
+ # "return result"
+ funcargs = [v_self] + callargs
+ block = Block(funcargs)
+ newgraph = FunctionGraph(newname, block)
+ translator.update_call_graph(newgraph, graph, object())
+ translator.graphs.append(newgraph)
+ block.operations[:] = newops
+ block.closeblock(Link([inputconst(Void, None)], newgraph.returnblock))
+
+ vres = newgraph.getreturnvar()
+ ann.setbinding(vres, s_None)
+ checkgraph(newgraph)
+ # pretend to be the same function, as we actually
+ # will become inlined.
+ newgraph.func = graph.func
+ translator.rtyper.specialize_more_blocks()
+ # not sure if we want this all the time?
+ if ALWAYS_INLINE:
+ simple_inline_function(translator, graph, newgraph)
+ return newgraph
More information about the Pypy-commit
mailing list