[pypy-commit] pypy s390x-backend: catchup with default

plan_rich pypy.commits at gmail.com
Mon Feb 1 03:12:08 EST 2016


Author: Richard Plangger <planrichi at gmail.com>
Branch: s390x-backend
Changeset: r82023:f3b48b1063f6
Date: 2016-02-01 09:11 +0100
http://bitbucket.org/pypy/pypy/changeset/f3b48b1063f6/

Log:	catchup with default

diff too long, truncating to 2000 out of 2165 lines

diff --git a/pypy/doc/faq.rst b/pypy/doc/faq.rst
--- a/pypy/doc/faq.rst
+++ b/pypy/doc/faq.rst
@@ -54,7 +54,8 @@
 It is quite common nowadays that xyz is available on PyPI_ and
 installable with ``pip install xyz``.  The simplest solution is to `use
 virtualenv (as documented here)`_.  Then enter (activate) the virtualenv
-and type: ``pip install xyz``.
+and type: ``pip install xyz``.  If you don't know or don't want virtualenv,
+you can also install ``pip`` globally by saying ``pypy -m ensurepip``.
 
 If you get errors from the C compiler, the module is a CPython C
 Extension module using unsupported features.  `See below.`_
diff --git a/pypy/doc/whatsnew-head.rst b/pypy/doc/whatsnew-head.rst
--- a/pypy/doc/whatsnew-head.rst
+++ b/pypy/doc/whatsnew-head.rst
@@ -133,6 +133,13 @@
 `rpython/jit/metainterp/optimizeopt/pure.py`, which can result in better codegen
 for traces containing a large number of pure getfield operations.
 
+.. branch: exctrans
+
+Try to ensure that no new functions get annotated during the 'source_c' phase.
+Refactor sandboxing to operate at a higher level.
+
+.. branch: cpyext-bootstrap
+
 .. branch: memop-simplify3
 
 Further simplifying the backend operations malloc_cond_varsize and zero_array.
diff --git a/pypy/module/cpyext/__init__.py b/pypy/module/cpyext/__init__.py
--- a/pypy/module/cpyext/__init__.py
+++ b/pypy/module/cpyext/__init__.py
@@ -36,7 +36,6 @@
 import pypy.module.cpyext.object
 import pypy.module.cpyext.stringobject
 import pypy.module.cpyext.tupleobject
-import pypy.module.cpyext.ndarrayobject
 import pypy.module.cpyext.setobject
 import pypy.module.cpyext.dictobject
 import pypy.module.cpyext.intobject
diff --git a/pypy/module/cpyext/api.py b/pypy/module/cpyext/api.py
--- a/pypy/module/cpyext/api.py
+++ b/pypy/module/cpyext/api.py
@@ -143,7 +143,7 @@
         target.chmod(0444) # make the file read-only, to make sure that nobody
                            # edits it by mistake
 
-def copy_header_files(dstdir):
+def copy_header_files(dstdir, copy_numpy_headers):
     # XXX: 20 lines of code to recursively copy a directory, really??
     assert dstdir.check(dir=True)
     headers = include_dir.listdir('*.h') + include_dir.listdir('*.inl')
@@ -151,15 +151,16 @@
         headers.append(udir.join(name))
     _copy_header_files(headers, dstdir)
 
-    try:
-        dstdir.mkdir('numpy')
-    except py.error.EEXIST:
-        pass
-    numpy_dstdir = dstdir / 'numpy'
+    if copy_numpy_headers:
+        try:
+            dstdir.mkdir('numpy')
+        except py.error.EEXIST:
+            pass
+        numpy_dstdir = dstdir / 'numpy'
 
-    numpy_include_dir = include_dir / 'numpy'
-    numpy_headers = numpy_include_dir.listdir('*.h') + numpy_include_dir.listdir('*.inl')
-    _copy_header_files(numpy_headers, numpy_dstdir)
+        numpy_include_dir = include_dir / 'numpy'
+        numpy_headers = numpy_include_dir.listdir('*.h') + numpy_include_dir.listdir('*.inl')
+        _copy_header_files(numpy_headers, numpy_dstdir)
 
 
 class NotSpecified(object):
@@ -442,8 +443,8 @@
 TYPES = {}
 GLOBALS = { # this needs to include all prebuilt pto, otherwise segfaults occur
     '_Py_NoneStruct#': ('PyObject*', 'space.w_None'),
-    '_Py_TrueStruct#': ('PyObject*', 'space.w_True'),
-    '_Py_ZeroStruct#': ('PyObject*', 'space.w_False'),
+    '_Py_TrueStruct#': ('PyIntObject*', 'space.w_True'),
+    '_Py_ZeroStruct#': ('PyIntObject*', 'space.w_False'),
     '_Py_NotImplementedStruct#': ('PyObject*', 'space.w_NotImplemented'),
     '_Py_EllipsisObject#': ('PyObject*', 'space.w_Ellipsis'),
     'PyDateTimeAPI': ('PyDateTime_CAPI*', 'None'),
@@ -482,7 +483,6 @@
         "PyComplex_Type": "space.w_complex",
         "PyByteArray_Type": "space.w_bytearray",
         "PyMemoryView_Type": "space.w_memoryview",
-        "PyArray_Type": "space.gettypeobject(W_NDimArray.typedef)",
         "PyBaseObject_Type": "space.w_object",
         'PyNone_Type': 'space.type(space.w_None)',
         'PyNotImplemented_Type': 'space.type(space.w_NotImplemented)',
@@ -506,7 +506,9 @@
 def get_structtype_for_ctype(ctype):
     from pypy.module.cpyext.typeobjectdefs import PyTypeObjectPtr
     from pypy.module.cpyext.cdatetime import PyDateTime_CAPI
+    from pypy.module.cpyext.intobject import PyIntObject
     return {"PyObject*": PyObject, "PyTypeObject*": PyTypeObjectPtr,
+            "PyIntObject*": PyIntObject,
             "PyDateTime_CAPI*": lltype.Ptr(PyDateTime_CAPI)}[ctype]
 
 PyTypeObject = lltype.ForwardReference()
@@ -771,6 +773,8 @@
     "NOT_RPYTHON"
     from pypy.module.cpyext.pyobject import make_ref
 
+    use_micronumpy = setup_micronumpy(space)
+
     export_symbols = list(FUNCTIONS) + SYMBOLS_C + list(GLOBALS)
     from rpython.translator.c.database import LowLevelDatabase
     db = LowLevelDatabase()
@@ -828,6 +832,7 @@
     space.fromcache(State).install_dll(eci)
 
     # populate static data
+    builder = StaticObjectBuilder(space)
     for name, (typ, expr) in GLOBALS.iteritems():
         from pypy.module import cpyext
         w_obj = eval(expr)
@@ -852,7 +857,7 @@
                 assert False, "Unknown static pointer: %s %s" % (typ, name)
             ptr.value = ctypes.cast(ll2ctypes.lltype2ctypes(value),
                                     ctypes.c_void_p).value
-        elif typ in ('PyObject*', 'PyTypeObject*'):
+        elif typ in ('PyObject*', 'PyTypeObject*', 'PyIntObject*'):
             if name.startswith('PyPyExc_') or name.startswith('cpyexttestExc_'):
                 # we already have the pointer
                 in_dll = ll2ctypes.get_ctypes_type(PyObject).in_dll(bridge, name)
@@ -861,17 +866,10 @@
                 # we have a structure, get its address
                 in_dll = ll2ctypes.get_ctypes_type(PyObject.TO).in_dll(bridge, name)
                 py_obj = ll2ctypes.ctypes2lltype(PyObject, ctypes.pointer(in_dll))
-            from pypy.module.cpyext.pyobject import (
-                track_reference, get_typedescr)
-            w_type = space.type(w_obj)
-            typedescr = get_typedescr(w_type.instancetypedef)
-            py_obj.c_ob_refcnt = 1
-            py_obj.c_ob_type = rffi.cast(PyTypeObjectPtr,
-                                         make_ref(space, w_type))
-            typedescr.attach(space, py_obj, w_obj)
-            track_reference(space, py_obj, w_obj)
+            builder.prepare(py_obj, w_obj)
         else:
             assert False, "Unknown static object: %s %s" % (typ, name)
+    builder.attach_all()
 
     pypyAPI = ctypes.POINTER(ctypes.c_void_p).in_dll(bridge, 'pypyAPI')
 
@@ -888,6 +886,36 @@
     setup_init_functions(eci, translating=False)
     return modulename.new(ext='')
 
+
+class StaticObjectBuilder:
+    def __init__(self, space):
+        self.space = space
+        self.to_attach = []
+
+    def prepare(self, py_obj, w_obj):
+        from pypy.module.cpyext.pyobject import track_reference
+        py_obj.c_ob_refcnt = 1
+        track_reference(self.space, py_obj, w_obj)
+        self.to_attach.append((py_obj, w_obj))
+
+    def attach_all(self):
+        from pypy.module.cpyext.pyobject import get_typedescr, make_ref
+        from pypy.module.cpyext.typeobject import finish_type_1, finish_type_2
+        space = self.space
+        space._cpyext_type_init = []
+        for py_obj, w_obj in self.to_attach:
+            w_type = space.type(w_obj)
+            typedescr = get_typedescr(w_type.instancetypedef)
+            py_obj.c_ob_type = rffi.cast(PyTypeObjectPtr,
+                                         make_ref(space, w_type))
+            typedescr.attach(space, py_obj, w_obj)
+        cpyext_type_init = space._cpyext_type_init
+        del space._cpyext_type_init
+        for pto, w_type in cpyext_type_init:
+            finish_type_1(space, pto)
+            finish_type_2(space, pto, w_type)
+
+
 def mangle_name(prefix, name):
     if name.startswith('Py'):
         return prefix + name[2:]
@@ -983,6 +1011,24 @@
     pypy_decl_h.write('\n'.join(pypy_decls))
     return functions
 
+separate_module_files = [source_dir / "varargwrapper.c",
+                         source_dir / "pyerrors.c",
+                         source_dir / "modsupport.c",
+                         source_dir / "getargs.c",
+                         source_dir / "abstract.c",
+                         source_dir / "stringobject.c",
+                         source_dir / "mysnprintf.c",
+                         source_dir / "pythonrun.c",
+                         source_dir / "sysmodule.c",
+                         source_dir / "bufferobject.c",
+                         source_dir / "cobject.c",
+                         source_dir / "structseq.c",
+                         source_dir / "capsule.c",
+                         source_dir / "pysignals.c",
+                         source_dir / "pythread.c",
+                         source_dir / "missing.c",
+                         ]
+
 def build_eci(building_bridge, export_symbols, code):
     "NOT_RPYTHON"
     # Build code and get pointer to the structure
@@ -1036,24 +1082,7 @@
 
     eci = ExternalCompilationInfo(
         include_dirs=include_dirs,
-        separate_module_files=[source_dir / "varargwrapper.c",
-                               source_dir / "pyerrors.c",
-                               source_dir / "modsupport.c",
-                               source_dir / "getargs.c",
-                               source_dir / "abstract.c",
-                               source_dir / "stringobject.c",
-                               source_dir / "mysnprintf.c",
-                               source_dir / "pythonrun.c",
-                               source_dir / "sysmodule.c",
-                               source_dir / "bufferobject.c",
-                               source_dir / "cobject.c",
-                               source_dir / "structseq.c",
-                               source_dir / "capsule.c",
-                               source_dir / "pysignals.c",
-                               source_dir / "pythread.c",
-                               source_dir / "ndarrayobject.c",
-                               source_dir / "missing.c",
-                               ],
+        separate_module_files= separate_module_files,
         separate_module_sources=separate_module_sources,
         compile_extra=compile_extra,
         **kwds
@@ -1061,10 +1090,22 @@
 
     return eci
 
+def setup_micronumpy(space):
+    use_micronumpy = space.config.objspace.usemodules.micronumpy
+    if not use_micronumpy:
+        return use_micronumpy
+    # import to register api functions by side-effect
+    import pypy.module.cpyext.ndarrayobject 
+    global GLOBALS, SYMBOLS_C, separate_module_files
+    GLOBALS["PyArray_Type#"]= ('PyTypeObject*', "space.gettypeobject(W_NDimArray.typedef)")
+    SYMBOLS_C += ['PyArray_Type', '_PyArray_FILLWBYTE', '_PyArray_ZEROS']
+    separate_module_files.append(source_dir / "ndarrayobject.c")
+    return use_micronumpy
 
 def setup_library(space):
     "NOT_RPYTHON"
     from pypy.module.cpyext.pyobject import make_ref
+    use_micronumpy = setup_micronumpy(space)
 
     export_symbols = list(FUNCTIONS) + SYMBOLS_C + list(GLOBALS)
     from rpython.translator.c.database import LowLevelDatabase
@@ -1082,14 +1123,33 @@
     run_bootstrap_functions(space)
     setup_va_functions(eci)
 
+    from pypy.module import cpyext   # for eval() below
+
+    # Set up the types.  Needs a special case, because of the
+    # immediate cycle involving 'c_ob_type', and because we don't
+    # want these types to be Py_TPFLAGS_HEAPTYPE.
+    static_types = {}
+    for name, (typ, expr) in GLOBALS.items():
+        if typ == 'PyTypeObject*':
+            pto = lltype.malloc(PyTypeObject, immortal=True,
+                                zero=True, flavor='raw')
+            pto.c_ob_refcnt = 1
+            pto.c_tp_basicsize = -1
+            static_types[name] = pto
+    builder = StaticObjectBuilder(space)
+    for name, pto in static_types.items():
+        pto.c_ob_type = static_types['PyType_Type#']
+        w_type = eval(GLOBALS[name][1])
+        builder.prepare(rffi.cast(PyObject, pto), w_type)
+    builder.attach_all()
+
     # populate static data
     for name, (typ, expr) in GLOBALS.iteritems():
         name = name.replace("#", "")
         if name.startswith('PyExc_'):
             name = '_' + name
-        from pypy.module import cpyext
         w_obj = eval(expr)
-        if typ in ('PyObject*', 'PyTypeObject*'):
+        if typ in ('PyObject*', 'PyTypeObject*', 'PyIntObject*'):
             struct_ptr = make_ref(space, w_obj)
         elif typ == 'PyDateTime_CAPI*':
             continue
@@ -1106,7 +1166,7 @@
 
     setup_init_functions(eci, translating=True)
     trunk_include = pypydir.dirpath() / 'include'
-    copy_header_files(trunk_include)
+    copy_header_files(trunk_include, use_micronumpy)
 
 def _load_from_cffi(space, name, path, initptr):
     from pypy.module._cffi_backend import cffi1_module
diff --git a/pypy/module/cpyext/include/stringobject.h b/pypy/module/cpyext/include/stringobject.h
--- a/pypy/module/cpyext/include/stringobject.h
+++ b/pypy/module/cpyext/include/stringobject.h
@@ -7,8 +7,8 @@
 extern "C" {
 #endif
 
-#define PyString_GET_SIZE(op) PyString_Size(op)
-#define PyString_AS_STRING(op) PyString_AsString(op)
+#define PyString_GET_SIZE(op) PyString_Size((PyObject*)(op))
+#define PyString_AS_STRING(op) PyString_AsString((PyObject*)(op))
 
 typedef struct {
     PyObject_HEAD
diff --git a/pypy/module/cpyext/test/test_api.py b/pypy/module/cpyext/test/test_api.py
--- a/pypy/module/cpyext/test/test_api.py
+++ b/pypy/module/cpyext/test/test_api.py
@@ -98,7 +98,7 @@
 
 
 def test_copy_header_files(tmpdir):
-    api.copy_header_files(tmpdir)
+    api.copy_header_files(tmpdir, True)
     def check(name):
         f = tmpdir.join(name)
         assert f.check(file=True)
diff --git a/pypy/module/cpyext/test/test_typeobject.py b/pypy/module/cpyext/test/test_typeobject.py
--- a/pypy/module/cpyext/test/test_typeobject.py
+++ b/pypy/module/cpyext/test/test_typeobject.py
@@ -374,6 +374,11 @@
         module = self.import_extension('foo', [
             ("test_type", "METH_O",
              '''
+                 /* "args->ob_type" is a strange way to get at 'type',
+                    which should have a different tp_getattro/tp_setattro
+                    than its tp_base, which is 'object'.
+                  */
+                  
                  if (!args->ob_type->tp_setattro)
                  {
                      PyErr_SetString(PyExc_ValueError, "missing tp_setattro");
@@ -382,8 +387,12 @@
                  if (args->ob_type->tp_setattro ==
                      args->ob_type->tp_base->tp_setattro)
                  {
-                     PyErr_SetString(PyExc_ValueError, "recursive tp_setattro");
-                     return NULL;
+                     /* Note that unlike CPython, in PyPy 'type.tp_setattro'
+                        is the same function as 'object.tp_setattro'.  This
+                        test used to check that it was not, but that was an
+                        artifact of the bootstrap logic only---in the final
+                        C sources I checked and they are indeed the same.
+                        So we ignore this problem here. */
                  }
                  if (!args->ob_type->tp_getattro)
                  {
diff --git a/pypy/module/cpyext/typeobject.py b/pypy/module/cpyext/typeobject.py
--- a/pypy/module/cpyext/typeobject.py
+++ b/pypy/module/cpyext/typeobject.py
@@ -146,7 +146,7 @@
             assert len(slot_names) == 2
             struct = getattr(pto, slot_names[0])
             if not struct:
-                assert not space.config.translating
+                #assert not space.config.translating
                 assert not pto.c_tp_flags & Py_TPFLAGS_HEAPTYPE
                 if slot_names[0] == 'c_tp_as_number':
                     STRUCT_TYPE = PyNumberMethods
@@ -310,55 +310,6 @@
                    realize=type_realize,
                    dealloc=type_dealloc)
 
-    # some types are difficult to create because of cycles.
-    # - object.ob_type = type
-    # - type.ob_type   = type
-    # - tuple.ob_type  = type
-    # - type.tp_base   = object
-    # - tuple.tp_base  = object
-    # - type.tp_bases is a tuple
-    # - object.tp_bases is a tuple
-    # - tuple.tp_bases is a tuple
-
-    # insert null placeholders to please create_ref()
-    track_reference(space, lltype.nullptr(PyObject.TO), space.w_type)
-    track_reference(space, lltype.nullptr(PyObject.TO), space.w_object)
-    track_reference(space, lltype.nullptr(PyObject.TO), space.w_tuple)
-    track_reference(space, lltype.nullptr(PyObject.TO), space.w_str)
-
-    # create the objects
-    py_type = create_ref(space, space.w_type)
-    py_object = create_ref(space, space.w_object)
-    py_tuple = create_ref(space, space.w_tuple)
-    py_str = create_ref(space, space.w_str)
-    # XXX py_str is not initialized here correctly, because we are
-    #     not tracking it, it gets an empty c_ob_type from py_basestring
-
-    # form cycles
-    pto_type = rffi.cast(PyTypeObjectPtr, py_type)
-    py_type.c_ob_type = pto_type
-    py_object.c_ob_type = pto_type
-    py_tuple.c_ob_type = pto_type
-
-    pto_object = rffi.cast(PyTypeObjectPtr, py_object)
-    pto_type.c_tp_base = pto_object
-    pto_tuple = rffi.cast(PyTypeObjectPtr, py_tuple)
-    pto_tuple.c_tp_base = pto_object
-
-    pto_type.c_tp_bases.c_ob_type = pto_tuple
-    pto_object.c_tp_bases.c_ob_type = pto_tuple
-    pto_tuple.c_tp_bases.c_ob_type = pto_tuple
-
-    for typ in (py_type, py_object, py_tuple, py_str):
-        heaptype = rffi.cast(PyHeapTypeObject, typ)
-        heaptype.c_ht_name.c_ob_type = pto_type
-
-    # Restore the mapping
-    track_reference(space, py_type, space.w_type, replace=True)
-    track_reference(space, py_object, space.w_object, replace=True)
-    track_reference(space, py_tuple, space.w_tuple, replace=True)
-    track_reference(space, py_str, space.w_str, replace=True)
-
 
 @cpython_api([PyObject], lltype.Void, external=False)
 def subtype_dealloc(space, obj):
@@ -476,6 +427,8 @@
     pto.c_tp_as_sequence = heaptype.c_as_sequence
     pto.c_tp_as_mapping = heaptype.c_as_mapping
     pto.c_tp_as_buffer = heaptype.c_as_buffer
+    pto.c_tp_basicsize = -1 # hopefully this makes malloc bail out
+    pto.c_tp_itemsize = 0
 
     return rffi.cast(PyObject, heaptype)
 
@@ -511,8 +464,6 @@
         pto.c_tp_name = PyString_AsString(space, heaptype.c_ht_name)
     else:
         pto.c_tp_name = rffi.str2charp(w_type.name)
-    pto.c_tp_basicsize = -1 # hopefully this makes malloc bail out
-    pto.c_tp_itemsize = 0
     # uninitialized fields:
     # c_tp_print, c_tp_getattr, c_tp_setattr
     # XXX implement
@@ -520,8 +471,11 @@
     w_base = best_base(space, w_type.bases_w)
     pto.c_tp_base = rffi.cast(PyTypeObjectPtr, make_ref(space, w_base))
 
-    finish_type_1(space, pto)
-    finish_type_2(space, pto, w_type)
+    if hasattr(space, '_cpyext_type_init'):
+        space._cpyext_type_init.append((pto, w_type))
+    else:
+        finish_type_1(space, pto)
+        finish_type_2(space, pto, w_type)
 
     pto.c_tp_basicsize = rffi.sizeof(typedescr.basestruct)
     if pto.c_tp_base:
diff --git a/pypy/objspace/std/mapdict.py b/pypy/objspace/std/mapdict.py
--- a/pypy/objspace/std/mapdict.py
+++ b/pypy/objspace/std/mapdict.py
@@ -116,7 +116,7 @@
 
     def _find_map_attr(self, name, index):
         while isinstance(self, PlainAttribute):
-            if name == self.name and index == self.index:
+            if index == self.index and name == self.name:
                 return self
             self = self.back
         return None
@@ -156,7 +156,6 @@
             jit.isconstant(name) and
             jit.isconstant(index))
     def add_attr(self, obj, name, index, w_value):
-        # grumble, jit needs this
         attr = self._get_new_attr(name, index)
         oldattr = obj._get_mapdict_map()
         if not jit.we_are_jitted():
@@ -296,7 +295,7 @@
         new_obj._get_mapdict_map().add_attr(new_obj, self.name, self.index, w_value)
 
     def delete(self, obj, name, index):
-        if name == self.name and index == self.index:
+        if index == self.index and name == self.name:
             # ok, attribute is deleted
             if not self.ever_mutated:
                 self.ever_mutated = True
diff --git a/pypy/objspace/std/setobject.py b/pypy/objspace/std/setobject.py
--- a/pypy/objspace/std/setobject.py
+++ b/pypy/objspace/std/setobject.py
@@ -942,7 +942,7 @@
             return False
         if w_set.length() == 0:
             return True
-        # it's possible to have 0-lenght strategy that's not empty
+        # it's possible to have 0-length strategy that's not empty
         if w_set.strategy is w_other.strategy:
             return self._issubset_unwrapped(w_set, w_other)
         if not self.may_contain_equal_elements(w_other.strategy):
diff --git a/rpython/memory/gctransform/boehm.py b/rpython/memory/gctransform/boehm.py
--- a/rpython/memory/gctransform/boehm.py
+++ b/rpython/memory/gctransform/boehm.py
@@ -74,7 +74,7 @@
 
     def gct_fv_gc_malloc_varsize(self, hop, flags, TYPE, v_length, c_const_size, c_item_size,
                                                                    c_offset_to_length):
-        # XXX same behavior for zero=True: in theory that's wrong        
+        # XXX same behavior for zero=True: in theory that's wrong
         if c_offset_to_length is None:
             v_raw = hop.genop("direct_call",
                                [self.malloc_varsize_no_length_ptr, v_length,
@@ -156,6 +156,11 @@
                           resulttype = lltype.Signed)
         hop.genop('int_invert', [v_int], resultvar=hop.spaceop.result)
 
+    def gcheader_initdata(self, defnode):
+        hdr = lltype.malloc(self.HDR, immortal=True)
+        hdr.hash = lltype.identityhash_nocache(defnode.obj._as_ptr())
+        return hdr._obj
+
 
 ########## weakrefs ##########
 # Boehm: weakref objects are small structures containing only a Boehm
diff --git a/rpython/memory/gctransform/framework.py b/rpython/memory/gctransform/framework.py
--- a/rpython/memory/gctransform/framework.py
+++ b/rpython/memory/gctransform/framework.py
@@ -288,7 +288,6 @@
 
         s_gcref = SomePtr(llmemory.GCREF)
         gcdata = self.gcdata
-        translator = self.translator
         #use the GC flag to find which malloc method to use
         #malloc_zero_filled == Ture -> malloc_fixedsize/varsize_clear
         #malloc_zero_filled == Flase -> malloc_fixedsize/varsize
@@ -322,7 +321,7 @@
                     GCClass.malloc_varsize.im_func,
                     [s_gc, s_typeid16]
                     + [annmodel.SomeInteger(nonneg=True) for i in range(4)], s_gcref)
-        
+
         self.collect_ptr = getfn(GCClass.collect.im_func,
             [s_gc, annmodel.SomeInteger()], annmodel.s_None)
         self.can_move_ptr = getfn(GCClass.can_move.im_func,
@@ -1385,7 +1384,7 @@
                                 [v] + previous_steps + [c_name, c_null])
                     else:
                         llops.genop('bare_setfield', [v, c_name, c_null])
-         
+
             return
         elif isinstance(TYPE, lltype.Array):
             ITEM = TYPE.OF
@@ -1412,6 +1411,25 @@
                             resulttype=llmemory.Address)
         llops.genop('raw_memclear', [v_adr, v_totalsize])
 
+    def gcheader_initdata(self, defnode):
+        o = lltype.top_container(defnode.obj)
+        needs_hash = self.get_prebuilt_hash(o) is not None
+        hdr = self.gc_header_for(o, needs_hash)
+        return hdr._obj
+
+    def get_prebuilt_hash(self, obj):
+        # for prebuilt objects that need to have their hash stored and
+        # restored.  Note that only structures that are StructNodes all
+        # the way have their hash stored (and not e.g. structs with var-
+        # sized arrays at the end).  'obj' must be the top_container.
+        TYPE = lltype.typeOf(obj)
+        if not isinstance(TYPE, lltype.GcStruct):
+            return None
+        if TYPE._is_varsize():
+            return None
+        return getattr(obj, '_hash_cache_', None)
+
+
 
 class TransformerLayoutBuilder(gctypelayout.TypeLayoutBuilder):
 
diff --git a/rpython/memory/gctransform/refcounting.py b/rpython/memory/gctransform/refcounting.py
--- a/rpython/memory/gctransform/refcounting.py
+++ b/rpython/memory/gctransform/refcounting.py
@@ -285,3 +285,7 @@
                           resulttype=llmemory.Address)
         hop.genop("direct_call", [self.identityhash_ptr, v_adr],
                   resultvar=hop.spaceop.result)
+
+    def gcheader_initdata(self, defnode):
+        top = lltype.top_container(defnode.obj)
+        return self.gcheaderbuilder.header_of_object(top)._obj
diff --git a/rpython/memory/gctransform/test/test_framework.py b/rpython/memory/gctransform/test/test_framework.py
--- a/rpython/memory/gctransform/test/test_framework.py
+++ b/rpython/memory/gctransform/test/test_framework.py
@@ -40,7 +40,7 @@
     t.config.translation.gc = "minimark"
     cbuild = CStandaloneBuilder(t, entrypoint, t.config,
                                 gcpolicy=FrameworkGcPolicy2)
-    db = cbuild.generate_graphs_for_llinterp()
+    db = cbuild.build_database()
     entrypointptr = cbuild.getentrypointptr()
     entrygraph = entrypointptr._obj.graph
 
@@ -69,7 +69,7 @@
         return -x
     t = rtype(g, [int])
     gg = graphof(t, g)
-    assert not CollectAnalyzer(t).analyze_direct_call(gg)    
+    assert not CollectAnalyzer(t).analyze_direct_call(gg)
 
 def test_cancollect_external():
     fext1 = rffi.llexternal('fext1', [], lltype.Void, releasegil=False)
@@ -110,12 +110,12 @@
 
     def entrypoint(argv):
         return g() + 2
-    
+
     t = rtype(entrypoint, [s_list_of_strings])
     t.config.translation.gc = "minimark"
     cbuild = CStandaloneBuilder(t, entrypoint, t.config,
                                 gcpolicy=FrameworkGcPolicy2)
-    db = cbuild.generate_graphs_for_llinterp()
+    db = cbuild.build_database()
 
 def test_no_collect_detection():
     from rpython.rlib import rgc
@@ -134,12 +134,13 @@
 
     def entrypoint(argv):
         return g() + 2
-    
+
     t = rtype(entrypoint, [s_list_of_strings])
     t.config.translation.gc = "minimark"
     cbuild = CStandaloneBuilder(t, entrypoint, t.config,
                                 gcpolicy=FrameworkGcPolicy2)
-    f = py.test.raises(Exception, cbuild.generate_graphs_for_llinterp)
+    with py.test.raises(Exception) as f:
+        cbuild.build_database()
     expected = "'no_collect' function can trigger collection: <function g at "
     assert str(f.value).startswith(expected)
 
@@ -163,11 +164,12 @@
     t.config.translation.gc = "minimark"
     cbuild = CStandaloneBuilder(t, entrypoint, t.config,
                                 gcpolicy=FrameworkGcPolicy2)
-    f = py.test.raises(Exception, cbuild.generate_graphs_for_llinterp)
+    with py.test.raises(Exception) as f:
+        cbuild.build_database()
     assert 'can cause the GC to be called' in str(f.value)
     assert 'trace_func' in str(f.value)
     assert 'MyStructure' in str(f.value)
- 
+
 class WriteBarrierTransformer(ShadowStackFrameworkGCTransformer):
     clean_sets = {}
     GC_PARAMS = {}
@@ -252,7 +254,7 @@
     t.config.translation.gc = "minimark"
     cbuild = CStandaloneBuilder(t, g, t.config,
                                 gcpolicy=FrameworkGcPolicy2)
-    db = cbuild.generate_graphs_for_llinterp()
+    db = cbuild.build_database()
 
     ff = graphof(t, f)
     #ff.show()
@@ -306,7 +308,7 @@
 def test_find_clean_setarrayitems():
     S = lltype.GcStruct('S')
     A = lltype.GcArray(lltype.Ptr(S))
-    
+
     def f():
         l = lltype.malloc(A, 3)
         l[0] = lltype.malloc(S)
@@ -327,7 +329,7 @@
 def test_find_clean_setarrayitems_2():
     S = lltype.GcStruct('S')
     A = lltype.GcArray(lltype.Ptr(S))
-    
+
     def f():
         l = lltype.malloc(A, 3)
         l[0] = lltype.malloc(S)
@@ -349,7 +351,7 @@
 def test_find_clean_setarrayitems_3():
     S = lltype.GcStruct('S')
     A = lltype.GcArray(lltype.Ptr(S))
-    
+
     def f():
         l = lltype.malloc(A, 3)
         l[0] = lltype.malloc(S)
diff --git a/rpython/memory/gctransform/test/test_transform.py b/rpython/memory/gctransform/test/test_transform.py
--- a/rpython/memory/gctransform/test/test_transform.py
+++ b/rpython/memory/gctransform/test/test_transform.py
@@ -16,7 +16,7 @@
         t = rtype(f, args_s)
         # XXX we shouldn't need an actual gcpolicy here.
         cbuild = CStandaloneBuilder(t, f, t.config, gcpolicy=self.gcpolicy)
-        cbuild.generate_graphs_for_llinterp()
+        cbuild.build_database()
         graph = cbuild.getentrypointptr()._obj.graph
         # arguments cannot be GC objects because nobody would put a
         # proper header on them
diff --git a/rpython/memory/gctransform/transform.py b/rpython/memory/gctransform/transform.py
--- a/rpython/memory/gctransform/transform.py
+++ b/rpython/memory/gctransform/transform.py
@@ -113,21 +113,14 @@
         self.seen_graphs.add(graph)
         self.minimal_transform.add(graph)
 
-    def prepare_inline_helpers(self, graphs):
+    def inline_helpers(self, graphs):
         from rpython.translator.backendopt.inline import iter_callsites
+        raise_analyzer = RaiseAnalyzer(self.translator)
         for graph in graphs:
-            self.graph_dependencies[graph] = {}
+            to_enum = []
             for called, block, i in iter_callsites(graph, None):
                 if called in self.graphs_to_inline:
-                    self.graph_dependencies[graph][called] = True
-        self.prepared = True
-
-    def inline_helpers(self, graph):
-        if not self.prepared:
-            raise Exception("Need to call prepare_inline_helpers first")
-        if self.inline:
-            raise_analyzer = RaiseAnalyzer(self.translator)
-            to_enum = self.graph_dependencies.get(graph, self.graphs_to_inline)
+                    to_enum.append(called)
             must_constfold = False
             for inline_graph in to_enum:
                 try:
@@ -378,6 +371,10 @@
         return hop.cast_result(rmodel.inputconst(lltype.Ptr(ARRAY_TYPEID_MAP),
                                         lltype.nullptr(ARRAY_TYPEID_MAP)))
 
+    def get_prebuilt_hash(self, obj):
+        return None
+
+
 class MinimalGCTransformer(BaseGCTransformer):
     def __init__(self, parenttransformer):
         BaseGCTransformer.__init__(self, parenttransformer.translator)
diff --git a/rpython/memory/test/test_transformed_gc.py b/rpython/memory/test/test_transformed_gc.py
--- a/rpython/memory/test/test_transformed_gc.py
+++ b/rpython/memory/test/test_transformed_gc.py
@@ -110,7 +110,7 @@
 
         cbuild = CStandaloneBuilder(t, entrypoint, config=t.config,
                                     gcpolicy=cls.gcpolicy)
-        db = cbuild.generate_graphs_for_llinterp()
+        db = cbuild.build_database()
         entrypointptr = cbuild.getentrypointptr()
         entrygraph = entrypointptr._obj.graph
         if option.view:
@@ -1071,7 +1071,7 @@
     def test_adr_of_nursery(self):
         run = self.runner("adr_of_nursery")
         res = run([])
-    
+
 
 class TestGenerationalNoFullCollectGC(GCTest):
     # test that nursery is doing its job and that no full collection
@@ -1131,7 +1131,7 @@
                          'large_object': 8*WORD,
                          'translated_to_c': False}
             root_stack_depth = 200
-    
+
     def define_ref_from_rawmalloced_to_regular(cls):
         import gc
         S = lltype.GcStruct('S', ('x', lltype.Signed))
@@ -1182,7 +1182,7 @@
         run = self.runner("write_barrier_direct")
         res = run([])
         assert res == 42
-    
+
 class TestMiniMarkGC(TestHybridGC):
     gcname = "minimark"
     GC_CAN_TEST_ID = True
@@ -1199,7 +1199,7 @@
                          'translated_to_c': False,
                          }
             root_stack_depth = 200
-    
+
     def define_no_clean_setarrayitems(cls):
         # The optimization find_clean_setarrayitems() in
         # gctransformer/framework.py does not work with card marking.
@@ -1224,7 +1224,7 @@
         run = self.runner("no_clean_setarrayitems")
         res = run([])
         assert res == 123
-    
+
     def define_nursery_hash_base(cls):
         class A:
             pass
@@ -1283,19 +1283,19 @@
                          'translated_to_c': False,
                          }
             root_stack_depth = 200
-    
+
     def define_malloc_array_of_gcptr(self):
         S = lltype.GcStruct('S', ('x', lltype.Signed))
         A = lltype.GcArray(lltype.Ptr(S))
         def f():
             lst = lltype.malloc(A, 5)
-            return (lst[0] == lltype.nullptr(S) 
+            return (lst[0] == lltype.nullptr(S)
                     and lst[1] == lltype.nullptr(S)
                     and lst[2] == lltype.nullptr(S)
                     and lst[3] == lltype.nullptr(S)
                     and lst[4] == lltype.nullptr(S))
         return f
-    
+
     def test_malloc_array_of_gcptr(self):
         run = self.runner('malloc_array_of_gcptr')
         res = run([])
@@ -1376,7 +1376,7 @@
     def define_gettypeid(cls):
         class A(object):
             pass
-        
+
         def fn():
             a = A()
             return rgc.get_typeid(a)
diff --git a/rpython/rtyper/extfunc.py b/rpython/rtyper/extfunc.py
--- a/rpython/rtyper/extfunc.py
+++ b/rpython/rtyper/extfunc.py
@@ -46,6 +46,12 @@
         impl = getattr(self, 'lltypeimpl', None)
         fakeimpl = getattr(self, 'lltypefakeimpl', self.instance)
         if impl:
+            if (rtyper.annotator.translator.config.translation.sandbox
+                    and not self.safe_not_sandboxed):
+                from rpython.translator.sandbox.rsandbox import (
+                    make_sandbox_trampoline)
+                impl = make_sandbox_trampoline(
+                    self.name, signature_args, s_result)
             if hasattr(self, 'lltypefakeimpl'):
                 # If we have both an llimpl and an llfakeimpl,
                 # we need a wrapper that selects the proper one and calls it
@@ -74,15 +80,10 @@
                             return original_impl(%s)
                 """ % (args, args, args)) in d
                 impl = func_with_new_name(d['ll_wrapper'], name + '_wrapper')
-            if rtyper.annotator.translator.config.translation.sandbox:
-                impl._dont_inline_ = True
             # store some attributes to the 'impl' function, where
             # the eventual call to rtyper.getcallable() will find them
             # and transfer them to the final lltype.functionptr().
-            impl._llfnobjattrs_ = {
-                '_name': self.name,
-                '_safe_not_sandboxed': self.safe_not_sandboxed,
-                }
+            impl._llfnobjattrs_ = {'_name': self.name}
             obj = rtyper.getannmixlevel().delayedfunction(
                 impl, signature_args, hop.s_result)
         else:
diff --git a/rpython/rtyper/rclass.py b/rpython/rtyper/rclass.py
--- a/rpython/rtyper/rclass.py
+++ b/rpython/rtyper/rclass.py
@@ -13,8 +13,9 @@
 from rpython.rtyper.lltypesystem.lltype import (
     Ptr, Struct, GcStruct, malloc, cast_pointer, castable, nullptr,
     RuntimeTypeInfo, getRuntimeTypeInfo, typeOf, Void, FuncType, Bool, Signed,
-    functionptr)
+    functionptr, attachRuntimeTypeInfo)
 from rpython.rtyper.lltypesystem.lloperation import llop
+from rpython.rtyper.llannotation import SomePtr
 from rpython.rtyper.lltypesystem import rstr
 from rpython.rtyper.rmodel import (
     Repr, getgcflavor, inputconst, warning, mangle)
@@ -590,10 +591,17 @@
                                        _callable=graph.func)
             else:
                 destrptr = None
-            OBJECT = OBJECT_BY_FLAVOR[LLFLAVOR[self.gcflavor]]
-            self.rtyper.attachRuntimeTypeInfoFunc(self.object_type,
-                                                  ll_runtime_type_info,
-                                                  OBJECT, destrptr)
+            self.rtyper.call_all_setups()  # compute ForwardReferences now
+            args_s = [SomePtr(Ptr(OBJECT))]
+            graph = self.rtyper.annotate_helper(ll_runtime_type_info, args_s)
+            s = self.rtyper.annotation(graph.getreturnvar())
+            if (not isinstance(s, SomePtr) or
+                s.ll_ptrtype != Ptr(RuntimeTypeInfo)):
+                raise TyperError("runtime type info function returns %r, "
+                                "expected Ptr(RuntimeTypeInfo)" % (s))
+            funcptr = self.rtyper.getcallable(graph)
+            attachRuntimeTypeInfo(self.object_type, funcptr, destrptr)
+
             vtable = self.rclass.getvtable()
             self.rtyper.set_type_for_typeptr(vtable, self.lowleveltype.TO)
 
diff --git a/rpython/rtyper/rtyper.py b/rpython/rtyper/rtyper.py
--- a/rpython/rtyper/rtyper.py
+++ b/rpython/rtyper/rtyper.py
@@ -1,14 +1,14 @@
 """
 RTyper: converts high-level operations into low-level operations in flow graphs.
 
-The main class, with code to walk blocks and dispatch individual operations
-to the care of the rtype_*() methods implemented in the other r* modules.
-For each high-level operation 'hop', the rtype_*() methods produce low-level
-operations that are collected in the 'llops' list defined here.  When necessary,
-conversions are inserted.
+The main class, with code to walk blocks and dispatch individual operations to
+the care of the rtype_*() methods implemented in the other r* modules.  For
+each high-level operation 'hop', the rtype_*() methods produce low-level
+operations that are collected in the 'llops' list defined here.  When
+necessary, conversions are inserted.
 
-This logic borrows a bit from rpython.annotator.annrpython, without the fixpoint
-computation part.
+This logic borrows a bit from rpython.annotator.annrpython, without the
+fixpoint computation part.
 """
 
 import os
@@ -16,19 +16,20 @@
 import py, math
 
 from rpython.annotator import model as annmodel, unaryop, binaryop
-from rpython.rtyper.llannotation import SomePtr, lltype_to_annotation
+from rpython.rtyper.llannotation import lltype_to_annotation
 from rpython.flowspace.model import Variable, Constant, SpaceOperation
-from rpython.rtyper.annlowlevel import annotate_lowlevel_helper, LowLevelAnnotatorPolicy
+from rpython.rtyper.annlowlevel import (
+        annotate_lowlevel_helper, LowLevelAnnotatorPolicy)
 from rpython.rtyper.error import TyperError
 from rpython.rtyper.exceptiondata import ExceptionData
 from rpython.rtyper.lltypesystem.lltype import (Signed, Void, LowLevelType,
-    Ptr, ContainerType, FuncType, typeOf, RuntimeTypeInfo,
-    attachRuntimeTypeInfo, Primitive, getfunctionptr)
-from rpython.rtyper.rmodel import Repr, inputconst, BrokenReprTyperError
+    ContainerType, typeOf, Primitive, getfunctionptr)
+from rpython.rtyper.rmodel import Repr, inputconst
 from rpython.rtyper import rclass
 from rpython.rtyper.rclass import RootClassRepr
 from rpython.tool.pairtype import pair
 from rpython.translator.unsimplify import insert_empty_block
+from rpython.translator.sandbox.rsandbox import make_sandbox_trampoline
 
 
 class RPythonTyper(object):
@@ -561,6 +562,17 @@
     def getcallable(self, graph):
         def getconcretetype(v):
             return self.bindingrepr(v).lowleveltype
+        if self.annotator.translator.config.translation.sandbox:
+            try:
+                name = graph.func._sandbox_external_name
+            except AttributeError:
+                pass
+            else:
+                args_s = [v.annotation for v in graph.getargs()]
+                s_result = graph.getreturnvar().annotation
+                sandboxed = make_sandbox_trampoline(name, args_s, s_result)
+                return self.getannmixlevel().delayedfunction(
+                        sandboxed, args_s, s_result)
 
         return getfunctionptr(graph, getconcretetype)
 
@@ -590,21 +602,6 @@
         graph = self.annotate_helper(ll_function, argtypes)
         return self.getcallable(graph)
 
-    def attachRuntimeTypeInfoFunc(self, GCSTRUCT, func, ARG_GCSTRUCT=None,
-                                  destrptr=None):
-        self.call_all_setups()  # compute ForwardReferences now
-        if ARG_GCSTRUCT is None:
-            ARG_GCSTRUCT = GCSTRUCT
-        args_s = [SomePtr(Ptr(ARG_GCSTRUCT))]
-        graph = self.annotate_helper(func, args_s)
-        s = self.annotation(graph.getreturnvar())
-        if (not isinstance(s, SomePtr) or
-            s.ll_ptrtype != Ptr(RuntimeTypeInfo)):
-            raise TyperError("runtime type info function %r returns %r, "
-                             "excepted Ptr(RuntimeTypeInfo)" % (func, s))
-        funcptr = self.getcallable(graph)
-        attachRuntimeTypeInfo(GCSTRUCT, funcptr, destrptr)
-
 # register operations from annotation model
 RPythonTyper._registeroperations(unaryop.UNARY_OPERATIONS, binaryop.BINARY_OPERATIONS)
 
diff --git a/rpython/rtyper/tool/test/test_rffi_platform.py b/rpython/rtyper/tool/test/test_rffi_platform.py
--- a/rpython/rtyper/tool/test/test_rffi_platform.py
+++ b/rpython/rtyper/tool/test/test_rffi_platform.py
@@ -277,10 +277,14 @@
     assert not rffi_platform.has("x", "#include <some/path/which/cannot/exist>")
 
 def test_has_0002():
+    if platform.name == 'msvc':
+        py.test.skip('no m.lib in msvc')
     assert rffi_platform.has("pow", "#include <math.h>", libraries=["m"])
 
 def test_has_0003():
     """multiple libraries"""
+    if platform.name == 'msvc':
+        py.test.skip('no m.lib in msvc')
     assert rffi_platform.has("pow", "#include <math.h>", libraries=["m", "c"])
 
 def test_has_0004():
diff --git a/rpython/translator/c/database.py b/rpython/translator/c/database.py
--- a/rpython/translator/c/database.py
+++ b/rpython/translator/c/database.py
@@ -1,3 +1,4 @@
+from collections import OrderedDict
 
 from rpython.rtyper.lltypesystem.lltype import (Primitive, Ptr, typeOf,
     RuntimeTypeInfo, Struct, Array, FuncType, Void, ContainerType, OpaqueType,
@@ -8,9 +9,9 @@
 from rpython.rtyper.lltypesystem import llgroup
 from rpython.tool.sourcetools import valid_identifier
 from rpython.translator.c.primitive import PrimitiveName, PrimitiveType
-from rpython.translator.c.node import StructDefNode, ArrayDefNode
-from rpython.translator.c.node import FixedSizeArrayDefNode, BareBoneArrayDefNode
-from rpython.translator.c.node import ContainerNodeFactory, ExtTypeOpaqueDefNode
+from rpython.translator.c.node import (
+    StructDefNode, ArrayDefNode, FixedSizeArrayDefNode, BareBoneArrayDefNode,
+    ContainerNodeFactory, ExtTypeOpaqueDefNode, FuncNode)
 from rpython.translator.c.support import cdecl, CNameManager
 from rpython.translator.c.support import log, barebonearray
 from rpython.translator.c.extfunc import do_the_getting
@@ -28,6 +29,7 @@
 
     def __init__(self, translator=None, standalone=False,
                  gcpolicyclass=None,
+                 exctransformer=None,
                  thread_enabled=False,
                  sandbox=False):
         self.translator = translator
@@ -36,6 +38,7 @@
         if gcpolicyclass is None:
             gcpolicyclass = gc.RefcountingGcPolicy
         self.gcpolicy = gcpolicyclass(self, thread_enabled)
+        self.exctransformer = exctransformer
 
         self.structdefnodes = {}
         self.pendingsetupnodes = []
@@ -45,7 +48,7 @@
         self.delayedfunctionptrs = []
         self.completedcontainers = 0
         self.containerstats = {}
-        self.helper2ptr = {}
+        self.helpers = OrderedDict()
 
         # late_initializations is for when the value you want to
         # assign to a constant object is something C doesn't think is
@@ -53,12 +56,8 @@
         self.late_initializations = []
         self.namespace = CNameManager()
 
-        if translator is None or translator.rtyper is None:
-            self.exctransformer = None
-        else:
-            self.exctransformer = translator.getexceptiontransformer()
         if translator is not None:
-            self.gctransformer = self.gcpolicy.gettransformer()
+            self.gctransformer = self.gcpolicy.gettransformer(translator)
         self.completed = False
 
         self.instrument_ncounter = 0
@@ -348,6 +347,8 @@
 
         assert not self.delayedfunctionptrs
         self.completed = True
+        if self.gctransformer is not None and self.gctransformer.inline:
+            self.gctransformer.inline_helpers(self.all_graphs())
         if show_progress:
             dump()
         log.database("Completed")
@@ -379,30 +380,10 @@
             produce(node)
         return result
 
-    def need_sandboxing(self, fnobj):
-        if not self.sandbox:
-            return False
-        if hasattr(fnobj, '_safe_not_sandboxed'):
-            return not fnobj._safe_not_sandboxed
-        elif getattr(getattr(fnobj, '_callable', None),
-                     '_sandbox_external_name', None):
-            return True
-        else:
-            return "if_external"
-
-    def prepare_inline_helpers(self):
-        all_nodes = self.globalcontainers()
-        funcnodes = [node for node in all_nodes if node.nodekind == 'func']
-        graphs = []
-        for node in funcnodes:
-            for graph in node.graphs_to_patch():
-                graphs.append(graph)
-        self.gctransformer.prepare_inline_helpers(graphs)
-
     def all_graphs(self):
         graphs = []
         for node in self.containerlist:
-            if node.nodekind == 'func':
+            if isinstance(node, FuncNode):
                 for graph in node.graphs_to_patch():
                     graphs.append(graph)
         return graphs
diff --git a/rpython/translator/c/external.py b/rpython/translator/c/external.py
deleted file mode 100644
--- a/rpython/translator/c/external.py
+++ /dev/null
@@ -1,54 +0,0 @@
-from rpython.rtyper.lltypesystem.lltype import typeOf, Void
-from rpython.translator.c.support import USESLOTS # set to False if necessary while refactoring
-from rpython.translator.c.support import cdecl, somelettersfrom
-
-class CExternalFunctionCodeGenerator(object):
-    if USESLOTS:
-        __slots__ = """db fnptr FUNCTYPE argtypenames resulttypename""".split()
-
-    def __init__(self, fnptr, db):
-        self.fnptr = fnptr
-        self.db = db
-        self.FUNCTYPE = typeOf(fnptr)
-        assert Void not in self.FUNCTYPE.ARGS
-        self.argtypenames = [db.gettype(T) for T in self.FUNCTYPE.ARGS]
-        self.resulttypename = db.gettype(self.FUNCTYPE.RESULT)
-
-    def graphs_to_patch(self):
-        return []
-
-    def name(self, cname):  #virtual
-        return cname
-
-    def argnames(self):
-        return ['%s%d' % (somelettersfrom(self.argtypenames[i]), i)
-                for i in range(len(self.argtypenames))]
-
-    def allconstantvalues(self):
-        return []
-
-    def implementation_begin(self):
-        pass
-
-    def cfunction_declarations(self):
-        if self.FUNCTYPE.RESULT is not Void:
-            yield '%s;' % cdecl(self.resulttypename, 'result')
-
-    def cfunction_body(self):
-        try:
-            convert_params = self.fnptr.convert_params
-        except AttributeError:
-            convert_params = lambda backend, args: [arg for _,arg in args]
-        call = '%s(%s)' % (self.fnptr._name, ', '.join(convert_params("c", zip(self.FUNCTYPE.ARGS, self.argnames()))))
-        if self.FUNCTYPE.RESULT is not Void:
-            yield 'result = %s;' % call
-            yield 'if (PyErr_Occurred()) RPyConvertExceptionFromCPython();'
-            yield 'return result;'
-        else:
-            yield '%s;' % call
-            yield 'if (PyErr_Occurred()) RPyConvertExceptionFromCPython();'
-
-    def implementation_end(self):
-        pass
-
-assert not USESLOTS or '__dict__' not in dir(CExternalFunctionCodeGenerator)
diff --git a/rpython/translator/c/extfunc.py b/rpython/translator/c/extfunc.py
--- a/rpython/translator/c/extfunc.py
+++ b/rpython/translator/c/extfunc.py
@@ -1,23 +1,23 @@
 import types
 
 from rpython.flowspace.model import FunctionGraph
-from rpython.rtyper.lltypesystem import lltype, rstr, rlist
+from rpython.annotator.listdef import s_list_of_strings
+from rpython.rtyper.lltypesystem import lltype, rlist
 from rpython.rtyper.lltypesystem.rstr import STR, mallocstr
 from rpython.translator.c.support import cdecl
 
 
 def find_list_of_str(rtyper):
-    for r in rtyper.reprs.itervalues():
-        if isinstance(r, rlist.ListRepr) and r.item_repr is rstr.string_repr:
-            return r.lowleveltype.TO
-    return None
+    r_strlist = rtyper.getrepr(s_list_of_strings)
+    rtyper.call_all_setups()
+    return r_strlist.lowleveltype.TO
+
 
 def predeclare_common_types(db, rtyper):
     # Common types
     yield ('RPyString', STR)
     LIST_OF_STR = find_list_of_str(rtyper)
-    if LIST_OF_STR is not None:
-        yield ('RPyListOfString', LIST_OF_STR)
+    yield ('RPyListOfString', LIST_OF_STR)
 
 def predeclare_utility_functions(db, rtyper):
     # Common utility functions
@@ -32,40 +32,38 @@
     # returned directly as results
 
     LIST_OF_STR = find_list_of_str(rtyper)
-    if LIST_OF_STR is not None:
-        p = lltype.Ptr(LIST_OF_STR)
+    p = lltype.Ptr(LIST_OF_STR)
 
-        def _RPyListOfString_New(length=lltype.Signed):
-            return LIST_OF_STR.ll_newlist(length)
+    def _RPyListOfString_New(length=lltype.Signed):
+        return LIST_OF_STR.ll_newlist(length)
 
-        def _RPyListOfString_SetItem(l=p,
-                                    index=lltype.Signed,
-                                    newstring=lltype.Ptr(STR)):
-            rlist.ll_setitem_nonneg(rlist.dum_nocheck, l, index, newstring)
+    def _RPyListOfString_SetItem(l=p,
+                                index=lltype.Signed,
+                                newstring=lltype.Ptr(STR)):
+        rlist.ll_setitem_nonneg(rlist.dum_nocheck, l, index, newstring)
 
-        def _RPyListOfString_GetItem(l=p,
-                                    index=lltype.Signed):
-            return rlist.ll_getitem_fast(l, index)
+    def _RPyListOfString_GetItem(l=p,
+                                index=lltype.Signed):
+        return rlist.ll_getitem_fast(l, index)
 
-        def _RPyListOfString_Length(l=p):
-            return rlist.ll_length(l)
+    def _RPyListOfString_Length(l=p):
+        return rlist.ll_length(l)
 
     for fname, f in locals().items():
         if isinstance(f, types.FunctionType):
             # XXX this is painful :(
-            if (LIST_OF_STR, fname) in db.helper2ptr:
-                yield (fname, db.helper2ptr[LIST_OF_STR, fname])
+            if fname in db.helpers:
+                yield (fname, db.helpers[fname])
             else:
                 # hack: the defaults give the type of the arguments
                 graph = rtyper.annotate_helper(f, f.func_defaults)
-                db.helper2ptr[LIST_OF_STR, fname] = graph
+                db.helpers[fname] = graph
                 yield (fname, graph)
 
 
-def predeclare_exception_data(db, rtyper):
+def predeclare_exception_data(exctransformer, rtyper):
     # Exception-related types and constants
     exceptiondata = rtyper.exceptiondata
-    exctransformer = db.exctransformer
 
     yield ('RPYTHON_EXCEPTION_VTABLE', exceptiondata.lltype_of_exception_type)
     yield ('RPYTHON_EXCEPTION',        exceptiondata.lltype_of_exception_value)
@@ -93,19 +91,19 @@
 def predeclare_all(db, rtyper):
     for fn in [predeclare_common_types,
                predeclare_utility_functions,
-               predeclare_exception_data,
                ]:
         for t in fn(db, rtyper):
             yield t
 
+    exctransformer = db.exctransformer
+    for t in predeclare_exception_data(exctransformer, rtyper):
+        yield t
+
 
 def get_all(db, rtyper):
-    for fn in [predeclare_common_types,
-               predeclare_utility_functions,
-               predeclare_exception_data,
-               ]:
-        for t in fn(db, rtyper):
-            yield t[1]
+    for name, fnptr in predeclare_all(db, rtyper):
+        yield fnptr
+
 
 # ____________________________________________________________
 
diff --git a/rpython/translator/c/funcgen.py b/rpython/translator/c/funcgen.py
--- a/rpython/translator/c/funcgen.py
+++ b/rpython/translator/c/funcgen.py
@@ -1,9 +1,8 @@
 import sys
-from rpython.translator.c.support import USESLOTS # set to False if necessary while refactoring
 from rpython.translator.c.support import cdecl
 from rpython.translator.c.support import llvalue_from_constant, gen_assignments
 from rpython.translator.c.support import c_string_constant, barebonearray
-from rpython.flowspace.model import Variable, Constant, copygraph
+from rpython.flowspace.model import Variable, Constant
 from rpython.rtyper.lltypesystem.lltype import (Ptr, Void, Bool, Signed, Unsigned,
     SignedLongLong, Float, UnsignedLongLong, Char, UniChar, ContainerType,
     Array, FixedSizeArray, ForwardReference, FuncType)
@@ -19,39 +18,30 @@
 
 KEEP_INLINED_GRAPHS = False
 
+def make_funcgen(graph, db, exception_policy, functionname):
+    graph._seen_by_the_backend = True
+    # apply the exception transformation
+    if db.exctransformer:
+        db.exctransformer.create_exception_handling(graph)
+    # apply the gc transformation
+    if db.gctransformer:
+        db.gctransformer.transform_graph(graph)
+    return FunctionCodeGenerator(graph, db, exception_policy, functionname)
+
 class FunctionCodeGenerator(object):
     """
     Collects information about a function which we have to generate
     from a flow graph.
     """
 
-    if USESLOTS:
-        __slots__ = """graph db gcpolicy
-                       exception_policy
-                       more_ll_values
-                       vars all_cached_consts
-                       illtypes
-                       functionname
-                       blocknum
-                       innerloops
-                       oldgraph""".split()
-
-    def __init__(self, graph, db, exception_policy=None, functionname=None):
-        graph._seen_by_the_backend = True
+    def __init__(self, graph, db, exception_policy, functionname):
         self.graph = graph
         self.db = db
         self.gcpolicy = db.gcpolicy
         self.exception_policy = exception_policy
         self.functionname = functionname
-        # apply the exception transformation
-        if self.db.exctransformer:
-            self.db.exctransformer.create_exception_handling(self.graph)
-        # apply the gc transformation
-        if self.db.gctransformer:
-            self.db.gctransformer.transform_graph(self.graph)
-        #self.graph.show()
+
         self.collect_var_and_types()
-
         for v in self.vars:
             T = v.concretetype
             # obscure: skip forward references and hope for the best
@@ -84,12 +74,6 @@
                     self.more_ll_values.append(link.llexitcase)
                 elif link.exitcase is not None:
                     mix.append(Constant(link.exitcase))
-        if self.exception_policy == "CPython":
-            v, exc_cleanup_ops = self.graph.exc_cleanup
-            mix.append(v)
-            for cleanupop in exc_cleanup_ops:
-                mix.extend(cleanupop.args)
-                mix.append(cleanupop.result)
 
         uniquemix = []
         seen = identity_dict()
@@ -99,20 +83,7 @@
                 seen[v] = True
         self.vars = uniquemix
 
-    def name(self, cname):  #virtual
-        return cname
-
-    def patch_graph(self, copy_graph):
-        graph = self.graph
-        if self.db.gctransformer and self.db.gctransformer.inline:
-            if copy_graph:
-                graph = copygraph(graph, shallow=True)
-            self.db.gctransformer.inline_helpers(graph)
-        return graph
-
     def implementation_begin(self):
-        self.oldgraph = self.graph
-        self.graph = self.patch_graph(copy_graph=True)
         SSI_to_SSA(self.graph)
         self.collect_var_and_types()
         self.blocknum = {}
@@ -138,8 +109,6 @@
         self.vars = None
         self.blocknum = None
         self.innerloops = None
-        self.graph = self.oldgraph
-        del self.oldgraph
 
     def argnames(self):
         return [LOCALVAR % v.name for v in self.graph.getargs()]
@@ -247,8 +216,6 @@
                         yield '}'
                     link = block.exits[0]
                     assert link.exitcase in (False, True)
-                    #yield 'assert(%s == %s);' % (self.expr(block.exitswitch),
-                    #                       self.genc.nameofvalue(link.exitcase, ct))
                     for op in self.gen_link(link):
                         yield op
                 elif TYPE in (Signed, Unsigned, SignedLongLong,
@@ -894,14 +861,11 @@
 
     def getdebugfunctionname(self):
         name = self.functionname
-        if not name:
-            return "?"
         if name.startswith('pypy_g_'):
             name = name[7:]
         return name
 
     def OP_DEBUG_RECORD_TRACEBACK(self, op):
-        #if self.functionname is None, we print "?" as the argument */
         return 'PYPY_DEBUG_RECORD_TRACEBACK("%s");' % (
             self.getdebugfunctionname(),)
 
@@ -941,5 +905,3 @@
                 cdecl(typename, ''),
                 self.expr(op.args[0]),
                 self.expr(op.result))
-
-assert not USESLOTS or '__dict__' not in dir(FunctionCodeGenerator)
diff --git a/rpython/translator/c/gc.py b/rpython/translator/c/gc.py
--- a/rpython/translator/c/gc.py
+++ b/rpython/translator/c/gc.py
@@ -1,8 +1,7 @@
 import sys
 from rpython.flowspace.model import Constant
-from rpython.rtyper.lltypesystem import lltype
-from rpython.rtyper.lltypesystem.lltype import (typeOf, RttiStruct,
-     RuntimeTypeInfo, top_container)
+from rpython.rtyper.lltypesystem.lltype import (RttiStruct,
+     RuntimeTypeInfo)
 from rpython.translator.c.node import ContainerNode
 from rpython.translator.c.support import cdecl
 from rpython.translator.tool.cbuild import ExternalCompilationInfo
@@ -18,23 +17,12 @@
             return defnode.db.gctransformer.HDR
         return None
 
-    def common_gcheader_initdata(self, defnode):
-        if defnode.db.gctransformer is not None:
-            raise NotImplementedError
-        return None
-
     def struct_gcheader_definition(self, defnode):
         return self.common_gcheader_definition(defnode)
 
-    def struct_gcheader_initdata(self, defnode):
-        return self.common_gcheader_initdata(defnode)
-
     def array_gcheader_definition(self, defnode):
         return self.common_gcheader_definition(defnode)
 
-    def array_gcheader_initdata(self, defnode):
-        return self.common_gcheader_initdata(defnode)
-
     def compilation_info(self):
         if not self.db:
             return ExternalCompilationInfo()
@@ -46,9 +34,6 @@
                               ]
             )
 
-    def get_prebuilt_hash(self, obj):
-        return None
-
     def need_no_typeptr(self):
         return False
 
@@ -109,16 +94,9 @@
 
 class RefcountingGcPolicy(BasicGcPolicy):
 
-    def gettransformer(self):
+    def gettransformer(self, translator):
         from rpython.memory.gctransform import refcounting
-        return refcounting.RefcountingGCTransformer(self.db.translator)
-
-    def common_gcheader_initdata(self, defnode):
-        if defnode.db.gctransformer is not None:
-            gct = defnode.db.gctransformer
-            top = top_container(defnode.obj)
-            return gct.gcheaderbuilder.header_of_object(top)._obj
-        return None
+        return refcounting.RefcountingGCTransformer(translator)
 
     # for structs
 
@@ -197,16 +175,9 @@
 
 class BoehmGcPolicy(BasicGcPolicy):
 
-    def gettransformer(self):
+    def gettransformer(self, translator):
         from rpython.memory.gctransform import boehm
-        return boehm.BoehmGCTransformer(self.db.translator)
-
-    def common_gcheader_initdata(self, defnode):
-        if defnode.db.gctransformer is not None:
-            hdr = lltype.malloc(defnode.db.gctransformer.HDR, immortal=True)
-            hdr.hash = lltype.identityhash_nocache(defnode.obj._as_ptr())
-            return hdr._obj
-        return None
+        return boehm.BoehmGCTransformer(translator)
 
     def array_setup(self, arraydefnode):
         pass
@@ -313,9 +284,9 @@
 
 class BasicFrameworkGcPolicy(BasicGcPolicy):
 
-    def gettransformer(self):
+    def gettransformer(self, translator):
         if hasattr(self, 'transformerclass'):    # for rpython/memory tests
-            return self.transformerclass(self.db.translator)
+            return self.transformerclass(translator)
         raise NotImplementedError
 
     def struct_setup(self, structdefnode, rtti):
@@ -362,24 +333,6 @@
             args = [funcgen.expr(v) for v in op.args]
             return '%s = %s; /* for moving GCs */' % (args[1], args[0])
 
-    def common_gcheader_initdata(self, defnode):
-        o = top_container(defnode.obj)
-        needs_hash = self.get_prebuilt_hash(o) is not None
-        hdr = defnode.db.gctransformer.gc_header_for(o, needs_hash)
-        return hdr._obj
-
-    def get_prebuilt_hash(self, obj):
-        # for prebuilt objects that need to have their hash stored and
-        # restored.  Note that only structures that are StructNodes all
-        # the way have their hash stored (and not e.g. structs with var-
-        # sized arrays at the end).  'obj' must be the top_container.
-        TYPE = typeOf(obj)
-        if not isinstance(TYPE, lltype.GcStruct):
-            return None
-        if TYPE._is_varsize():
-            return None
-        return getattr(obj, '_hash_cache_', None)
-
     def need_no_typeptr(self):
         config = self.db.translator.config
         return config.translation.gcremovetypeptr
@@ -440,15 +393,15 @@
 
 class ShadowStackFrameworkGcPolicy(BasicFrameworkGcPolicy):
 
-    def gettransformer(self):
+    def gettransformer(self, translator):
         from rpython.memory.gctransform import shadowstack
-        return shadowstack.ShadowStackFrameworkGCTransformer(self.db.translator)
+        return shadowstack.ShadowStackFrameworkGCTransformer(translator)
 
 class AsmGcRootFrameworkGcPolicy(BasicFrameworkGcPolicy):
 
-    def gettransformer(self):
+    def gettransformer(self, translator):
         from rpython.memory.gctransform import asmgcroot
-        return asmgcroot.AsmGcRootFrameworkGCTransformer(self.db.translator)
+        return asmgcroot.AsmGcRootFrameworkGCTransformer(translator)
 
     def GC_KEEPALIVE(self, funcgen, v):
         return 'pypy_asm_keepalive(%s);' % funcgen.expr(v)
diff --git a/rpython/translator/c/genc.py b/rpython/translator/c/genc.py
--- a/rpython/translator/c/genc.py
+++ b/rpython/translator/c/genc.py
@@ -126,8 +126,10 @@
             if not self.standalone:
                 raise NotImplementedError("--gcrootfinder=asmgcc requires standalone")
 
+        exctransformer = translator.getexceptiontransformer()
         db = LowLevelDatabase(translator, standalone=self.standalone,
                               gcpolicyclass=gcpolicyclass,
+                              exctransformer=exctransformer,
                               thread_enabled=self.config.translation.thread,
                               sandbox=self.config.translation.sandbox)
         self.db = db
@@ -193,22 +195,8 @@
     DEBUG_DEFINES = {'RPY_ASSERT': 1,
                      'RPY_LL_ASSERT': 1}
 
-    def generate_graphs_for_llinterp(self, db=None):
-        # prepare the graphs as when the source is generated, but without
-        # actually generating the source.
-        if db is None:
-            db = self.build_database()
-        graphs = db.all_graphs()
-        db.gctransformer.prepare_inline_helpers(graphs)
-        for node in db.containerlist:
-            if hasattr(node, 'funcgens'):
-                for funcgen in node.funcgens:
-                    funcgen.patch_graph(copy_graph=False)
-        return db
-
     def generate_source(self, db=None, defines={}, exe_name=None):
         assert self.c_source_filename is None
-
         if db is None:
             db = self.build_database()
         pf = self.getentrypointptr()
@@ -846,7 +834,6 @@
     #
     sg = SourceGenerator(database)
     sg.set_strategy(targetdir, split)
-    database.prepare_inline_helpers()
     sg.gen_readable_parts_of_source(f)
     headers_to_precompile = sg.headers_to_precompile[:]
     headers_to_precompile.insert(0, incfilename)
diff --git a/rpython/translator/c/node.py b/rpython/translator/c/node.py
--- a/rpython/translator/c/node.py
+++ b/rpython/translator/c/node.py
@@ -3,8 +3,7 @@
     Void, OpaqueType, Float, RuntimeTypeInfo, getRuntimeTypeInfo, Char,
     _subarray)
 from rpython.rtyper.lltypesystem import llmemory, llgroup
-from rpython.translator.c.funcgen import FunctionCodeGenerator
-from rpython.translator.c.external import CExternalFunctionCodeGenerator
+from rpython.translator.c.funcgen import make_funcgen
 from rpython.translator.c.support import USESLOTS # set to False if necessary while refactoring
 from rpython.translator.c.support import cdecl, forward_cdecl, somelettersfrom
 from rpython.translator.c.support import c_char_array_constant, barebonearray
@@ -540,7 +539,17 @@
 class StructNode(ContainerNode):
     nodekind = 'struct'
     if USESLOTS:
-        __slots__ = ()
+        __slots__ = ('gc_init',)
+
+    def __init__(self, db, T, obj):
+        ContainerNode.__init__(self, db, T, obj)
+        if needs_gcheader(T):
+            gct = self.db.gctransformer
+            if gct is not None:
+                self.gc_init = gct.gcheader_initdata(self)
+                db.getcontainernode(self.gc_init)
+            else:
+                self.gc_init = None
 
     def basename(self):
         T = self.getTYPE()
@@ -567,8 +576,7 @@
         data = []
 
         if needs_gcheader(T):
-            gc_init = self.db.gcpolicy.struct_gcheader_initdata(self)
-            data.append(('gcheader', gc_init))
+            data.append(('gcheader', self.gc_init))
 
         for name in defnode.fieldnames:
             data.append((name, getattr(self.obj, name)))
@@ -641,7 +649,7 @@
 
     def implementation(self):
         hash_typename = self.get_hash_typename()
-        hash = self.db.gcpolicy.get_prebuilt_hash(self.obj)
+        hash = self.db.gctransformer.get_prebuilt_hash(self.obj)
         assert hash is not None
         lines = list(self.initializationexpr())
         lines.insert(0, '%s = { {' % (
@@ -651,7 +659,8 @@
         return lines
 
 def gcstructnode_factory(db, T, obj):
-    if db.gcpolicy.get_prebuilt_hash(obj) is not None:
+    if (db.gctransformer and
+            db.gctransformer.get_prebuilt_hash(obj) is not None):
         cls = GcStructNodeWithHash
     else:
         cls = StructNode
@@ -661,7 +670,17 @@
 class ArrayNode(ContainerNode):
     nodekind = 'array'
     if USESLOTS:
-        __slots__ = ()
+        __slots__ = ('gc_init',)
+
+    def __init__(self, db, T, obj):
+        ContainerNode.__init__(self, db, T, obj)
+        if needs_gcheader(T):
+            gct = self.db.gctransformer
+            if gct is not None:
+                self.gc_init = gct.gcheader_initdata(self)
+                db.getcontainernode(self.gc_init)
+            else:
+                self.gc_init = None
 
     def getptrname(self):
         if barebonearray(self.getTYPE()):
@@ -681,8 +700,7 @@
         T = self.getTYPE()
         yield '{'
         if needs_gcheader(T):
-            gc_init = self.db.gcpolicy.array_gcheader_initdata(self)
-            lines = generic_initializationexpr(self.db, gc_init, 'gcheader',
+            lines = generic_initializationexpr(self.db, self.gc_init, 'gcheader',
                                                '%sgcheader' % (decoration,))
             for line in lines:
                 yield line
@@ -781,81 +799,64 @@
                 comma = ''
         expr += comma
         i = expr.find('\n')
-        if i<0: i = len(expr)
+        if i < 0:
+            i = len(expr)
         expr = '%s\t/* %s */%s' % (expr[:i], decoration, expr[i:])
         return expr.split('\n')
 
 # ____________________________________________________________
 
 
-class FuncNode(ContainerNode):
+class FuncNodeBase(ContainerNode):
     nodekind = 'func'
     eci_name = 'compilation_info'
     # there not so many node of this kind, slots should not
     # be necessary
-
-    def __init__(self, db, T, obj, forcename=None):
+    def __init__(self, db, T, obj, ptrname):
         Node.__init__(self, db)
         self.globalcontainer = True
         self.T = T
         self.obj = obj
-        callable = getattr(obj, '_callable', None)
-        if (callable is not None and
-            getattr(callable, 'c_name', None) is not None):
-            self.name = forcename or obj._callable.c_name
-        elif getattr(obj, 'external', None) == 'C' and not db.need_sandboxing(obj):
-            self.name = forcename or self.basename()
-        else:
-            self.name = (forcename or
-                         db.namespace.uniquename('g_' + self.basename()))
-        self.make_funcgens()
+        self.name = ptrname
         self.typename = db.gettype(T)  #, who_asks=self)
 
     def getptrname(self):
         return self.name
 
-    def make_funcgens(self):
-        self.funcgens = select_function_code_generators(self.obj, self.db, self.name)
-        if self.funcgens:
-            argnames = self.funcgens[0].argnames()  #Assume identical for all funcgens
-            self.implementationtypename = self.db.gettype(self.T, argnames=argnames)
-            self._funccodegen_owner = self.funcgens[0]
-        else:
-            self._funccodegen_owner = None
-
     def basename(self):
         return self.obj._name
 
+
+class FuncNode(FuncNodeBase):
+    def __init__(self, db, T, obj, ptrname):
+        FuncNodeBase.__init__(self, db, T, obj, ptrname)
+        exception_policy = getattr(obj, 'exception_policy', None)
+        self.funcgen = make_funcgen(obj.graph, db, exception_policy, ptrname)
+        argnames = self.funcgen.argnames()
+        self.implementationtypename = db.gettype(T, argnames=argnames)
+        self._funccodegen_owner = self.funcgen
+
     def enum_dependencies(self):
-        if not self.funcgens:
-            return []
-        return self.funcgens[0].allconstantvalues() #Assume identical for all funcgens
+        return self.funcgen.allconstantvalues()
 
     def forward_declaration(self):
         callable = getattr(self.obj, '_callable', None)
         is_exported = getattr(callable, 'exported_symbol', False)
-        for funcgen in self.funcgens:
-            yield '%s;' % (
-                forward_cdecl(self.implementationtypename,
-                    funcgen.name(self.name), self.db.standalone,
-                    is_exported=is_exported))
+        yield '%s;' % (
+            forward_cdecl(self.implementationtypename,
+                self.name, self.db.standalone, is_exported=is_exported))
+
+    def graphs_to_patch(self):
+        for i in self.funcgen.graphs_to_patch():
+            yield i
 
     def implementation(self):
-        for funcgen in self.funcgens:
-            for s in self.funcgen_implementation(funcgen):
-                yield s
-
-    def graphs_to_patch(self):
-        for funcgen in self.funcgens:
-            for i in funcgen.graphs_to_patch():
-                yield i
-
-    def funcgen_implementation(self, funcgen):
+        funcgen = self.funcgen
         funcgen.implementation_begin()
         # recompute implementationtypename as the argnames may have changed
         argnames = funcgen.argnames()
         implementationtypename = self.db.gettype(self.T, argnames=argnames)
-        yield '%s {' % cdecl(implementationtypename, funcgen.name(self.name))
+        yield '%s {' % cdecl(implementationtypename, self.name)
         #
         # declare the local variables
         #
@@ -866,7 +867,7 @@
         while start < len(localnames):
             # pack the local declarations over as few lines as possible
             total = lengths[start] + 8
-            end = start+1
+            end = start + 1
             while total + lengths[end] < 77:
                 total += lengths[end] + 1
                 end += 1
@@ -897,44 +898,55 @@
         del bodyiter
         funcgen.implementation_end()
 
-def sandbox_stub(fnobj, db):
-    # unexpected external function for --sandbox translation: replace it
-    # with a "Not Implemented" stub.  To support these functions, port them
-    # to the new style registry (e.g. rpython.module.ll_os.RegisterOs).
-    from rpython.translator.sandbox import rsandbox
-    graph = rsandbox.get_external_function_sandbox_graph(fnobj, db,
-                                                      force_stub=True)
-    return [FunctionCodeGenerator(graph, db)]
+class ExternalFuncNode(FuncNodeBase):
+    def __init__(self, db, T, obj, ptrname):
+        FuncNodeBase.__init__(self, db, T, obj, ptrname)
+        self._funccodegen_owner = None
 
-def sandbox_transform(fnobj, db):
-    # for --sandbox: replace a function like os_open_llimpl() with
-    # code that communicates with the external process to ask it to
-    # perform the operation.
-    from rpython.translator.sandbox import rsandbox
-    graph = rsandbox.get_external_function_sandbox_graph(fnobj, db)
-    return [FunctionCodeGenerator(graph, db)]
+    def enum_dependencies(self):
+        return []
 
-def select_function_code_generators(fnobj, db, functionname):
-    sandbox = db.need_sandboxing(fnobj)
-    if hasattr(fnobj, 'graph'):
-        if sandbox and sandbox != "if_external":
-            # apply the sandbox transformation
-            return sandbox_transform(fnobj, db)
-        exception_policy = getattr(fnobj, 'exception_policy', None)
-        return [FunctionCodeGenerator(fnobj.graph, db, exception_policy,
-                                      functionname)]
-    elif getattr(fnobj, 'external', None) is not None:
-        if sandbox:
-            return sandbox_stub(fnobj, db)
-        elif fnobj.external == 'C':
-            return []
-        else:
-            assert fnobj.external == 'CPython'
-            return [CExternalFunctionCodeGenerator(fnobj, db)]
-    elif hasattr(fnobj._callable, "c_name"):
-        return []    # this case should only be used for entrypoints
+    def forward_declaration(self):
+        return []
+
+    def implementation(self):
+        return []
+
+def new_funcnode(db, T, obj, forcename=None):
+    if db.sandbox:
+        if (getattr(obj, 'external', None) is not None and
+                not obj._safe_not_sandboxed):
+            from rpython.translator.sandbox import rsandbox
+            obj.__dict__['graph'] = rsandbox.get_sandbox_stub(
+                obj, db.translator.rtyper)
+            obj.__dict__.pop('_safe_not_sandboxed', None)
+            obj.__dict__.pop('external', None)
+    if forcename:
+        name = forcename
     else:
-        raise ValueError("don't know how to generate code for %r" % (fnobj,))
+        name = _select_name(db, obj)
+    if hasattr(obj, 'graph'):
+        return FuncNode(db, T, obj, name)
+    elif getattr(obj, 'external', None) is not None:
+        assert obj.external == 'C'
+        if db.sandbox:
+            assert obj._safe_not_sandboxed
+        return ExternalFuncNode(db, T, obj, name)
+    elif hasattr(obj._callable, "c_name"):
+        return ExternalFuncNode(db, T, obj, name)  # this case should only be used for entrypoints
+    else:
+        raise ValueError("don't know how to generate code for %r" % (obj,))
+
+
+def _select_name(db, obj):
+    try:
+        return obj._callable.c_name
+    except AttributeError:
+        pass
+    if getattr(obj, 'external', None) == 'C':
+        return obj._name
+    return db.namespace.uniquename('g_' + obj._name)
+
 
 class ExtType_OpaqueNode(ContainerNode):
     nodekind = 'rpyopaque'
@@ -1044,7 +1056,7 @@
     Array:        ArrayNode,
     GcArray:      ArrayNode,
     FixedSizeArray: FixedSizeArrayNode,
-    FuncType:     FuncNode,
+    FuncType:     new_funcnode,
     OpaqueType:   opaquenode_factory,
     llmemory._WeakRefType: weakrefnode_factory,
     llgroup.GroupType: GroupNode,
diff --git a/rpython/translator/c/test/test_database.py b/rpython/translator/c/test/test_database.py
--- a/rpython/translator/c/test/test_database.py
+++ b/rpython/translator/c/test/test_database.py
@@ -9,8 +9,6 @@
 
 
 def dump_on_stdout(database):
-    if database.gctransformer:
-        database.prepare_inline_helpers()
     print '/*********************************/'
     structdeflist = database.getstructdeflist()
     for node in structdeflist:
@@ -171,7 +169,7 @@
 
     F = FuncType([Signed], Signed)
     f = functionptr(F, "f", graph=graph)
-    db = LowLevelDatabase(t)
+    db = LowLevelDatabase(t, exctransformer=t.getexceptiontransformer())
     db.get(f)
     db.complete()
     dump_on_stdout(db)
@@ -186,7 +184,7 @@
         return p.x * p.y
     t, graph = makegraph(ll_f, [int])
 
-    db = LowLevelDatabase(t)
+    db = LowLevelDatabase(t, exctransformer=t.getexceptiontransformer())
     db.get(getfunctionptr(graph))
     db.complete()
     dump_on_stdout(db)
@@ -207,7 +205,7 @@
         return s.ptr1.x * s.ptr2.x
     t, graph = makegraph(ll_f, [int])
 
-    db = LowLevelDatabase(t)
+    db = LowLevelDatabase(t, exctransformer=t.getexceptiontransformer())
     db.get(getfunctionptr(graph))
     db.complete()
     dump_on_stdout(db)
diff --git a/rpython/translator/c/test/test_refcount.py b/rpython/translator/c/test/test_refcount.py
--- a/rpython/translator/c/test/test_refcount.py
+++ b/rpython/translator/c/test/test_refcount.py
@@ -106,37 +106,6 @@
         assert fn(1) == 4
         assert fn(0) == 5
 
-    def test_del_basic(self):
-        py.test.skip("xxx fix or kill")
-        S = lltype.GcStruct('S', ('x', lltype.Signed), rtti=True)
-        TRASH = lltype.GcStruct('TRASH', ('x', lltype.Signed))
-        GLOBAL = lltype.Struct('GLOBAL', ('x', lltype.Signed))
-        glob = lltype.malloc(GLOBAL, immortal=True)
-        def destructor(s):
-            glob.x = s.x + 1
-        def type_info_S(s):
-            return lltype.getRuntimeTypeInfo(S)
-
-        def g(n):
-            s = lltype.malloc(S)
-            s.x = n
-            # now 's' should go away
-        def entrypoint(n):
-            g(n)
-            # llop.gc__collect(lltype.Void)
-            return glob.x
-
-        t = TranslationContext()
-        t.buildannotator().build_types(entrypoint, [int])
-        rtyper = t.buildrtyper()
-        destrptr = rtyper.annotate_helper_fn(destructor, [lltype.Ptr(S)])
-        rtyper.attachRuntimeTypeInfoFunc(S, type_info_S, destrptr=destrptr)


More information about the pypy-commit mailing list