[pypy-commit] pypy sepcomp2: Refactor and create a FunctionExportInfo similar to the ClassExportInfo.

amauryfa noreply at buildbot.pypy.org
Wed Feb 22 21:19:41 CET 2012


Author: Amaury Forgeot d'Arc <amauryfa at gmail.com>
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)


More information about the pypy-commit mailing list