Author: Amaury Forgeot d'Arc <[email protected]>
Branch: sepcomp2
Changeset: r52772:1516c6c5964a
Date: 2012-02-22 21:17 +0100
http://bitbucket.org/pypy/pypy/changeset/1516c6c5964a/
Log: Refactor and create a FunctionExportInfo similar to the
ClassExportInfo. These classes have methods for the different
stages:
- save_repr() runs in the context of the first translation.
- make_external_function() runs in the context of the second
translation, and replaces the RPython function/class with
something that calls into the first library.
The idea is that after save_repr(), the object can be pickled and
the second translation done in another process.
diff --git a/pypy/translator/c/exportinfo.py b/pypy/translator/c/exportinfo.py
--- a/pypy/translator/c/exportinfo.py
+++ b/pypy/translator/c/exportinfo.py
@@ -4,7 +4,7 @@
from pypy.rpython.controllerentry import (
Controller, ControllerEntry, SomeControlledInstance)
from pypy.rpython.extregistry import ExtRegistryEntry
-from pypy.rlib.objectmodel import instantiate
+from pypy.rlib.objectmodel import instantiate, specialize
from pypy.rlib.unroll import unrolling_iterable
from pypy.tool.sourcetools import func_with_new_name
from pypy.translator.tool.cbuild import ExternalCompilationInfo
@@ -51,6 +51,68 @@
return func
+class FunctionExportInfo:
+ def __init__(self, name, func):
+ self.name = name
+ self.func = func
+
+ def save_repr(self, builder):
+ bk = builder.translator.annotator.bookkeeper
+ desc = bk.getdesc(self.func)
+ if isinstance(desc, description.FunctionDesc):
+ graph = desc.getuniquegraph()
+ funcptr = getfunctionptr(graph)
+ else:
+ raise NotImplementedError
+ self.external_name = builder.db.get(funcptr)
+ self.functype = lltype.typeOf(funcptr)
+
+ def make_llexternal_function(self, eci):
+ functype = self.functype
+ imported_func = rffi.llexternal(
+ self.external_name, functype.TO.ARGS, functype.TO.RESULT,
+ compilation_info=eci,
+ )
+ ARGS = functype.TO.ARGS
+ unrolling_ARGS = unrolling_iterable(enumerate(ARGS))
+ def wrapper(*args):
+ real_args = ()
+ for i, TARGET in unrolling_ARGS:
+ arg = args[i]
+ if isinstance(TARGET, lltype.Ptr): # XXX more precise check?
+ arg = self.make_ll_import_arg_converter(TARGET)(arg)
+
+ real_args = real_args + (arg,)
+ res = imported_func(*real_args)
+ return res
+ wrapper._always_inline_ = True
+ return func_with_new_name(wrapper, self.external_name)
+
+ @staticmethod
+ @specialize.memo()
+ def make_ll_import_arg_converter(TARGET):
+ from pypy.annotation import model
+
+ def convert(x):
+ UNUSED
+
+ class Entry(ExtRegistryEntry):
+ _about_ = convert
+
+ def compute_result_annotation(self, s_arg):
+ if not (isinstance(s_arg, SomeControlledInstance) and
+ s_arg.s_real_obj.ll_ptrtype == TARGET):
+ raise TypeError("Expected a proxy for %s" % (TARGET,))
+ return model.lltype_to_annotation(TARGET)
+
+ def specialize_call(self, hop):
+ [v_instance] = hop.inputargs(*hop.args_r)
+ return hop.genop('force_cast', [v_instance],
+ resulttype=TARGET)
+
+ return convert
+
+
class ClassExportInfo:
def __init__(self, name, cls):
self.name = name
@@ -69,12 +131,12 @@
miniglobals = {'cls': self.cls, 'instantiate': instantiate}
exec source.compile() in miniglobals
constructor = miniglobals[self.constructor_name]
- constructor._annspecialcase_ = 'specialize:ll'
constructor._always_inline_ = True
constructor.argtypes = self.cls.__init__.argtypes
return constructor
- def save_repr(self, rtyper):
+ def save_repr(self, builder):
+ rtyper = builder.db.translator.rtyper
bookkeeper = rtyper.annotator.bookkeeper
classdef = bookkeeper.getuniqueclassdef(self.cls)
self.classrepr = rtyper.getrepr(model.SomeInstance(classdef)
@@ -113,7 +175,7 @@
def add_function(self, name, func):
"""Adds a function to export."""
- self.functions[name] = func
+ self.functions[name] = FunctionExportInfo(name, func)
def add_class(self, name, cls):
"""Adds a class to export."""
@@ -126,17 +188,19 @@
# annotate constructors of exported classes
for name, class_info in self.classes.items():
constructor = class_info.make_constructor()
- self.functions[constructor.__name__] = constructor
+ self.add_function(constructor.__name__, constructor)
# annotate functions with signatures
- for name, func in self.functions.items():
+ for name, func_info in self.functions.items():
+ func = func_info.func
if hasattr(func, 'argtypes'):
annotator.build_types(func, func.argtypes,
complete_now=False)
annotator.complete()
# Ensure that functions without signature are not constant-folded
- for funcname, func in self.functions.items():
+ for name, func_info in self.functions.items():
+ func = func_info.func
if not hasattr(func, 'argtypes'):
# build a list of arguments where constants are erased
newargs = []
@@ -149,40 +213,19 @@
# and reflow
annotator.build_types(func, newargs)
- def get_lowlevel_functions(self, annotator):
- """Builds a map of low_level objects."""
- bk = annotator.bookkeeper
-
- exported_funcptr = {}
- for name, item in self.functions.items():
- desc = bk.getdesc(item)
- if isinstance(desc, description.FunctionDesc):
- graph = desc.getuniquegraph()
- funcptr = getfunctionptr(graph)
- else:
- raise NotImplementedError
-
- exported_funcptr[name] = funcptr
- return exported_funcptr
-
def make_import_module(self, builder):
"""Builds an object with all exported functions."""
- rtyper = builder.db.translator.rtyper
-
- for clsname, class_info in self.classes.items():
- class_info.save_repr(rtyper)
-
- exported_funcptr = self.get_lowlevel_functions(
- builder.translator.annotator)
- # Map exported functions to the names given by the translator.
- node_names = dict(
- (funcname, builder.db.get(funcptr))
- for funcname, funcptr in exported_funcptr.items())
+ for name, class_info in self.classes.items():
+ class_info.save_repr(builder)
+ for name, func_info in self.functions.items():
+ func_info.save_repr(builder)
# Declarations of functions defined in the first module.
forwards = []
+ node_names = set(func_info.external_name
+ for func_info in self.functions.values())
for node in builder.db.globalcontainers():
- if node.nodekind == 'func' and node.name in node_names.values():
+ if node.nodekind == 'func' and node.name in node_names:
forwards.append('\n'.join(node.forward_declaration()))
so_name = py.path.local(builder.so_name)
@@ -200,58 +243,12 @@
class Module(object):
__file__ = builder.so_name
mod = Module()
- for funcname, funcptr in exported_funcptr.items():
- import_name = node_names[funcname]
- func = make_llexternal_function(import_name, funcptr, import_eci)
- setattr(mod, funcname, func)
- for clsname, class_info in self.classes.items():
+ for name, func_info in self.functions.items():
+ funcptr = func_info.make_llexternal_function(import_eci)
+ setattr(mod, name, funcptr)
+ for name, class_info in self.classes.items():
structptr = class_info.make_controller(mod)
- setattr(mod, clsname, structptr)
+ setattr(mod, name, structptr)
return mod
-def make_ll_import_arg_converter(TARGET):
- from pypy.annotation import model
-
- def convert(x):
- UNUSED
-
- class Entry(ExtRegistryEntry):
- _about_ = convert
-
- def compute_result_annotation(self, s_arg):
- if not (isinstance(s_arg, SomeControlledInstance) and
- s_arg.s_real_obj.ll_ptrtype == TARGET):
- raise TypeError("Expected a proxy for %s" % (TARGET,))
- return model.lltype_to_annotation(TARGET)
-
- def specialize_call(self, hop):
- [v_instance] = hop.inputargs(*hop.args_r)
- return hop.genop('force_cast', [v_instance],
- resulttype=TARGET)
-
- return convert
-make_ll_import_arg_converter._annspecialcase_ = 'specialize:memo'
-
-def make_llexternal_function(name, funcptr, eci):
- functype = lltype.typeOf(funcptr)
- imported_func = rffi.llexternal(
- name, functype.TO.ARGS, functype.TO.RESULT,
- compilation_info=eci,
- )
- ARGS = functype.TO.ARGS
- unrolling_ARGS = unrolling_iterable(enumerate(ARGS))
- def wrapper(*args):
- real_args = ()
- for i, TARGET in unrolling_ARGS:
- arg = args[i]
- if isinstance(TARGET, lltype.Ptr): # XXX more precise check?
- arg = make_ll_import_arg_converter(TARGET)(arg)
-
- real_args = real_args + (arg,)
- res = imported_func(*real_args)
- return res
- wrapper._annspecialcase_ = 'specialize:ll'
- wrapper._always_inline_ = True
- return func_with_new_name(wrapper, name)
-
diff --git a/pypy/translator/c/test/test_export.py
b/pypy/translator/c/test/test_export.py
--- a/pypy/translator/c/test/test_export.py
+++ b/pypy/translator/c/test/test_export.py
@@ -27,7 +27,8 @@
t.buildrtyper().specialize()
backend_optimizations(t)
- functions = [(f, None) for f in export_info.functions.values()]
+ functions = [(info.func, None)
+ for info in export_info.functions.values()]
builder = CLibraryBuilder(t, None, config=t.config,
name='lib' + modulename,
functions=functions)
_______________________________________________
pypy-commit mailing list
[email protected]
http://mail.python.org/mailman/listinfo/pypy-commit