[pypy-svn] r16365 - in pypy/dist/pypy/translator: c c/src c/test tool

pedronis at codespeak.net pedronis at codespeak.net
Wed Aug 24 13:52:31 CEST 2005


Author: pedronis
Date: Wed Aug 24 13:52:27 2005
New Revision: 16365

Modified:
   pypy/dist/pypy/translator/c/database.py
   pypy/dist/pypy/translator/c/gc.py
   pypy/dist/pypy/translator/c/genc.py
   pypy/dist/pypy/translator/c/node.py
   pypy/dist/pypy/translator/c/src/exception.h
   pypy/dist/pypy/translator/c/src/mem.h
   pypy/dist/pypy/translator/c/test/test_boehm.py
   pypy/dist/pypy/translator/tool/cbuild.py
Log:
basic support for optionally using Boehm as the gc for RPython translated code

(cfbolz, pedronis)



Modified: pypy/dist/pypy/translator/c/database.py
==============================================================================
--- pypy/dist/pypy/translator/c/database.py	(original)
+++ pypy/dist/pypy/translator/c/database.py	Wed Aug 24 13:52:27 2005
@@ -8,7 +8,6 @@
 from pypy.translator.c.node import ContainerNodeFactory, ExtTypeOpaqueDefNode
 from pypy.translator.c.support import cdecl, CNameManager, ErrorValue
 from pypy.translator.c.pyobj import PyObjMaker
-from pypy.translator.c import gc
 
 # ____________________________________________________________
 
@@ -25,6 +24,7 @@
         if not standalone:
             self.pyobjmaker = PyObjMaker(self.namespace, self.get, translator)
         if gcpolicy is None:
+            from pypy.translator.c import gc
             gcpolicy = gc.RefcountingGcPolicy
         self.gcpolicy = gcpolicy(self)
 

Modified: pypy/dist/pypy/translator/c/gc.py
==============================================================================
--- pypy/dist/pypy/translator/c/gc.py	(original)
+++ pypy/dist/pypy/translator/c/gc.py	Wed Aug 24 13:52:27 2005
@@ -1,6 +1,8 @@
 from pypy.translator.c.support import cdecl
+from pypy.translator.c.node import ContainerNode
 from pypy.rpython.lltype import typeOf, Ptr, PyObject, ContainerType
-from pypy.rpython.lltype import getRuntimeTypeInfo
+from pypy.rpython.lltype import GcArray, GcStruct
+from pypy.rpython.lltype import RuntimeTypeInfo, getRuntimeTypeInfo
 
 PyObjPtr = Ptr(PyObject)
 
@@ -35,6 +37,44 @@
                 return self.pop_alive_nopyobj(expr, T)
         return ''
 
+    def push_alive_nopyobj(self, expr, T):
+        return ''
+
+    def pop_alive_nopyobj(self, expr, T):
+        return ''
+
+    def push_alive_op_result(self, opname, expr, T):
+        return ''
+
+    def gcheader_field_name(self, defnode):
+        return None
+
+    def common_gcheader_definition(self, defnode):
+        return []
+
+    def common_after_definition(self, defnode):
+        return []
+
+    def common_gcheader_initializationexpr(self, defnode):
+        return []
+
+    struct_gcheader_definition = common_gcheader_definition
+    struct_after_definition = common_after_definition
+    struct_gcheader_initialitionexpr = common_gcheader_initializationexpr
+
+    def prepare_nested_gcstruct(self, structdefnode, INNER):
+        pass
+
+    array_gcheader_definition = common_gcheader_definition
+    array_after_definition = common_after_definition
+    array_gcheader_initialitionexpr = common_gcheader_initializationexpr
+
+    def gc_libraries(self):
+        return []
+
+    def pre_pre_gc_code(self): # code that goes before include g_prerequisite.h
+        return []
+
     def pre_gc_code(self):
         return []
 
@@ -114,8 +154,6 @@
         for line in defnode.visitor_lines(prefix, self.generic_dealloc):
             yield line
 
-
-
     # for structs
 
     def prepare_nested_gcstruct(self, structdefnode, INNER):
@@ -208,12 +246,8 @@
     def rtti_type(self):
         return 'void (@)(void *)'   # void dealloc_xx(struct xx *)
 
-    def rtti_node(self, defnode, node):
-        node.typename = 'void (@)(void *)'
-        node.implementationtypename = 'void (@)(struct %s *)' % (
-            defnode.name,)
-        node.name = defnode.gcinfo.static_deallocator
-        node.ptrname = '((void (*)(void *)) %s)' % (node.name,)
+    def rtti_node_factory(self):
+        return RefcountingRuntimeTypeInfo_OpaqueNode
 
     # zero malloc impl
 
@@ -222,4 +256,126 @@
                                                 eresult,
                                                 err)
 
+class RefcountingRuntimeTypeInfo_OpaqueNode(ContainerNode):
+    globalcontainer = True
+    includes = ()
+    typename = 'void (@)(void *)'
+
+    def __init__(self, db, T, obj):
+        assert T == RuntimeTypeInfo
+        assert isinstance(obj.about, GcStruct)
+        self.db = db
+        self.T = T
+        self.obj = obj
+        defnode = db.gettypedefnode(obj.about)
+        self.implementationtypename = 'void (@)(struct %s *)' % (
+            defnode.name,)
+        self.name = defnode.gcinfo.static_deallocator
+        self.ptrname = '((void (*)(void *)) %s)' % (self.name,)
+
+    def enum_dependencies(self):
+        return []
+
+    def implementation(self):
+        return []
+
+
+
+class BoehmGcInfo:
+    finalizer = None
+
+class BoehmGcPolicy(BasicGcPolicy):
+
+    write_barrier = RefcountingGcPolicy.write_barrier.im_func
+
+    generic_dealloc = RefcountingGcPolicy.generic_dealloc.im_func
+
+    deallocator_lines = RefcountingGcPolicy.deallocator_lines.im_func
+
+    # for arrays
+
+    def array_setup(self, arraydefnode):
+        if isinstance(arraydefnode.LLTYPE, GcArray) and list(self.deallocator_lines(arraydefnode, '')):
+            gcinfo = arraydefnode.gcinfo = RefcountingInfo()
+            gcinfo.finalizer = self.db.namespace.uniquename('finalize_'+arraydefnode.barename)
+
+    def array_implementationcode(self, arraydefnode):
+        if arraydefnode.gcinfo:
+            gcinfo = arraydefnode.gcinfo
+            if gcinfo.finalizer:
+                yield 'void %s(GC_PTR obj, GC_PTR ignore) {' % (gcinfo.finalizer, arraydefnode.name)
+                yield '\tstruct %s *a = (struct %s *)obj;' % (arraydefnode.name, arraydefnode.name)
+                for line in self.deallocator_lines(arraydefnode, '(*a)'):
+                    yield '\t' + line
+                yield '}'
+
+    # for structs
+    def struct_setup(self, structdefnode, rtti):
+        if isinstance(structdefnode.LLTYPE, GcStruct) and list(self.deallocator_lines(structdefnode, '')):
+            gcinfo = structdefnode.gcinfo = RefcountingInfo()
+            gcinfo.finalizer = self.db.namespace.uniquename('finalize_'+structdefnode.barename)
+
+    def struct_implementationcode(self, structdefnode):
+        if structdefnode.gcinfo:
+            gcinfo = structdefnode.gcinfo
+            if gcinfo.finalizer:
+                yield 'void %s(GC_PTR obj, GC_PTR ignore) {' % (gcinfo.finalizer, structdefnode.name)
+                yield '\tstruct %s *p = (struct %s *)obj;' % (structdefnode.name, structdefnode.name)
+                for line in self.deallocator_lines(structdefnode, '(*p)'):
+                    yield '\t' + line
+                yield '}'
+
+    # for rtti node
+
+    def rtti_type(self):
+        return 'long @'
+
+    def rtti_node_factory(self):
+        return BoehmGcRuntimeTypeInfo_OpaqueNode
+
+    # zero malloc impl
+
+    def zero_malloc(self, TYPE, esize, eresult, err):
+        gcinfo = self.db.gettypedefnode(TYPE).gcinfo
+        if gcinfo and gcinfo.finalizer:
+            yield  'OP_BOEHM_ZERO_MALLOC_FINALIZER(%s, %s, %s, %s);' % (esize,
+                                                                        eresult,
+                                                                        gcinfo.finalizer,
+                                                                        err)
+        else:
+            yield  'OP_BOEHM_ZERO_MALLOC(%s, %s, %s);' % (esize,
+                                                          eresult,
+                                                          err)
+
+    def gc_libraries(self):
+        return ['gc'] # xxx on windows?
+
+    def pre_pre_gc_code(self):
+        yield '#include <gc.h>'
+        yield '#define USING_BOEHM_GC'
+
+    def gc_startup_code(self):
+        yield 'GC_INIT();'
+
+
+class BoehmGcRuntimeTypeInfo_OpaqueNode(ContainerNode):
+    globalcontainer = True
+    includes = ()
+    typename = 'long @'
+    implementationtypename = typename
+
+    def __init__(self, db, T, obj):
+        assert T == RuntimeTypeInfo
+        assert isinstance(obj.about, GcStruct)
+        self.db = db
+        self.T = T
+        self.obj = obj
+        defnode = db.gettypedefnode(obj.about)
+        self.name = self.db.namespace.uniquename('g_rtti_v_'+ defnode.barename)
+        self.ptrname = '&%s' % (self.name,)
+
+    def enum_dependencies(self):
+        return []
 
+    def implementation(self):
+        yield 'long %s = %d;' % (self.name, id(self.obj))

Modified: pypy/dist/pypy/translator/c/genc.py
==============================================================================
--- pypy/dist/pypy/translator/c/genc.py	(original)
+++ pypy/dist/pypy/translator/c/genc.py	Wed Aug 24 13:52:27 2005
@@ -16,15 +16,23 @@
     _compiled = False
     symboltable = None
     
-    def __init__(self, translator, gcpolicy=None):
+    def __init__(self, translator, gcpolicy=None, libraries=None):
         self.translator = translator
         self.gcpolicy = gcpolicy
-    
+
+        if libraries is None:
+            libraries = []
+        self.libraries = libraries        
+
     def generate_source(self):
         assert self.c_source_filename is None
         translator = self.translator
         pf = self.getentrypointptr()
         db = LowLevelDatabase(translator, standalone=self.standalone, gcpolicy=self.gcpolicy)
+
+        # we need a concrete gcpolicy to do this        
+        self.libraries += db.gcpolicy.gc_libraries()
+
         pfname = db.get(pf)
         db.complete()
 
@@ -59,7 +67,8 @@
         assert not self._compiled
         compile_c_module(self.c_source_filename, 
                          self.c_source_filename.purebasename,
-                         include_dirs = [autopath.this_dir])
+                         include_dirs = [autopath.this_dir],
+                         libraries=self.libraries)
         self._compiled = True
 
     def import_module(self):
@@ -95,7 +104,8 @@
         python_inc = sysconfig.get_python_inc()
         self.executable_name = build_executable([self.c_source_filename],
                                          include_dirs = [autopath.this_dir,
-                                                         python_inc])
+                                                         python_inc],
+                                         libraries=self.libraries)
         self._compiled = True
         return self.executable_name
 
@@ -226,6 +236,10 @@
     #
     for key, value in defines.items():
         print >> f, '#define %s %s' % (key, value)
+
+    for line in database.gcpolicy.pre_pre_gc_code():
+        print >> f, line
+
     print >> f, '#include "src/g_prerequisite.h"'
 
     for line in database.gcpolicy.pre_gc_code():

Modified: pypy/dist/pypy/translator/c/node.py
==============================================================================
--- pypy/dist/pypy/translator/c/node.py	(original)
+++ pypy/dist/pypy/translator/c/node.py	Wed Aug 24 13:52:27 2005
@@ -53,7 +53,10 @@
             assert isinstance(T, GC_CONTAINER)
             firstdefnode = db.gettypedefnode(T)
             firstfieldname = self.c_struct_field_name(STRUCT._names[0])
-            self.gcheader = '%s.%s' % (firstfieldname, firstdefnode.gcheader)
+            if firstdefnode.gcheader:
+                self.gcheader = '%s.%s' % (firstfieldname, firstdefnode.gcheader)
+            else:
+                self.gcheader = None
 
             # give the gcpolicy a chance to do sanity checking or special preparation for
             # this case
@@ -507,28 +510,6 @@
     else:
         raise ValueError, "don't know how to generate code for %r" % (fnobj,)
 
-# xxx move it completly to the gcpolicy
-class RuntimeTypeInfo_OpaqueNode(ContainerNode):
-    globalcontainer = True
-    includes = ()
-
-    def __init__(self, db, T, obj):
-        assert T == RuntimeTypeInfo
-        assert isinstance(obj.about, GcStruct)
-        self.db = db
-        self.T = T
-        self.obj = obj
-        defnode = db.gettypedefnode(obj.about)
-
-        self.db.gcpolicy.rtti_node(defnode, self)
-
-    def enum_dependencies(self):
-        return []
-
-    def implementation(self):
-        return []
-
-
 class ExtType_OpaqueNode(ContainerNode):
 
     def enum_dependencies(self):
@@ -551,7 +532,7 @@
 
 def opaquenode_factory(db, T, obj):
     if T == RuntimeTypeInfo:
-        return RuntimeTypeInfo_OpaqueNode(db, T, obj)
+        return db.gcpolicy.rtti_node_factory()(db, T, obj)
     if hasattr(T, '_exttypeinfo'):
         return ExtType_OpaqueNode(db, T, obj)
     raise Exception("don't know about %r" % (T,))

Modified: pypy/dist/pypy/translator/c/src/exception.h
==============================================================================
--- pypy/dist/pypy/translator/c/src/exception.h	(original)
+++ pypy/dist/pypy/translator/c/src/exception.h	Wed Aug 24 13:52:27 2005
@@ -71,11 +71,11 @@
 
 
 #define RPyRaiseSimpleException(exc, msg)		        \
-		/* XXX 1. uses officially bad fishing */	\
-		/* XXX 2. msg is ignored */			\
-		rpython_exc_type = (R##exc)->o_typeptr;		\
-		rpython_exc_value = (R##exc);			\
-		rpython_exc_value->refcount++
+	/* XXX 1. uses officially bad fishing */		\
+	/* XXX 2. msg is ignored */				\
+	rpython_exc_type = (R##exc)->o_typeptr;			\
+	rpython_exc_value = (R##exc);				\
+	PUSH_ALIVE(rpython_exc_value)
 
 /******************************************************************/
 #else    /* non-RPython version of exceptions, using CPython only */

Modified: pypy/dist/pypy/translator/c/src/mem.h
==============================================================================
--- pypy/dist/pypy/translator/c/src/mem.h	(original)
+++ pypy/dist/pypy/translator/c/src/mem.h	Wed Aug 24 13:52:27 2005
@@ -17,6 +17,8 @@
 
 #define OP_FREE(p)	{ PyObject_Free(p); COUNT_FREE; }
 
+/* XXX uses officially bad fishing */
+#define PUSH_ALIVE(obj) obj->refcount++
 
 /*------------------------------------------------------------*/
 #ifndef COUNT_OP_MALLOCS
@@ -42,3 +44,25 @@
 /*------------------------------------------------------------*/
 #endif /*COUNT_OP_MALLOCS*/
 /*------------------------------------------------------------*/
+
+/* for Boehm GC */
+
+#ifdef USING_BOEHM_GC
+
+#define OP_BOEHM_ZERO_MALLOC(size, r, err)   {                         \
+	r = (void*) GC_MALLOC(size);				       \
+	if (r == NULL) FAIL_EXCEPTION(err, PyExc_MemoryError, "out of memory");	\
+	memset((void*) r, 0, size);				       \
+  }
+
+#define OP_BOEHM_ZERO_MALLOC_FINALIZER(size, r, finalizer, err)   {    \
+	r = (void*) GC_MALLOC(size);				       \
+	if (r == NULL) FAIL_EXCEPTION(err, PyExc_MemoryError, "out of memory");	\
+	GC_REGISTER_FINALIZER(r, finalizer, NULL, NULL, NULL);         \
+	memset((void*) r, 0, size);				       \
+  }
+
+#undef PUSH_ALIVE
+#define PUSH_ALIVE(obj)
+
+#endif /* USING_BOEHM_GC */

Modified: pypy/dist/pypy/translator/c/test/test_boehm.py
==============================================================================
--- pypy/dist/pypy/translator/c/test/test_boehm.py	(original)
+++ pypy/dist/pypy/translator/c/test/test_boehm.py	Wed Aug 24 13:52:27 2005
@@ -1,41 +1,59 @@
+import py
+test_src = """
 from pypy.translator.translator import Translator
 from pypy.translator.tool.cbuild import skip_missing_compiler
 from pypy.translator.c.genc import CExtModuleBuilder
 
-class TestBoehmTestCase:
+def getcompiled(func):
+    from pypy.translator.c.gc import BoehmGcPolicy
+    t = Translator(func, simplifying=True)
+    # builds starting-types from func_defs 
+    argstypelist = []
+    if func.func_defaults:
+        for spec in func.func_defaults:
+            if isinstance(spec, tuple):
+                spec = spec[0] # use the first type only for the tests
+            argstypelist.append(spec)
+    a = t.annotate(argstypelist)
+    a.simplify()
+    t.specialize()
+    t.checkgraphs()
+    def compile():
+        cbuilder = CExtModuleBuilder(t, gcpolicy=BoehmGcPolicy)
+        c_source_filename = cbuilder.generate_source()
+        cbuilder.compile()
+        cbuilder.import_module()    
+        return cbuilder.get_entry_point()
+    return skip_missing_compiler(compile)
+
+
+def test_malloc_a_lot():
+    def malloc_a_lot():
+        i = 0
+        while i < 10:
+            i += 1
+            a = [1] * 10
+            j = 0
+            while j < 20:
+                j += 1
+                a.append(j)
+    fn = getcompiled(malloc_a_lot)
+    fn()
+
+def run_test(fn):
+    fn()
+    channel.send(None)
+
+run_test(test_malloc_a_lot)
+"""
+
+
+def test_boehm():
+    import py
+    gw = py.execnet.PopenGateway()
+    chan = gw.remote_exec(py.code.Source(test_src))
+    res = chan.receive()
+    assert not res
+    chan.close()
+
 
-    def getcompiled(self, func):
-        from pypy.translator.c.gc import BoehmGcPolicy
-        t = Translator(func, simplifying=True)
-        # builds starting-types from func_defs 
-        argstypelist = []
-        if func.func_defaults:
-            for spec in func.func_defaults:
-                if isinstance(spec, tuple):
-                    spec = spec[0] # use the first type only for the tests
-                argstypelist.append(spec)
-        a = t.annotate(argstypelist)
-        a.simplify()
-        t.specialize()
-        t.checkgraphs()
-        def compile():
-            cbuilder = CExtModuleBuilder(t, gcpolicy=BoehmGcPolicy)
-            c_source_filename = cbuilder.generate_source()
-            cbuilder.compile()
-            cbuilder.import_module()    
-            return cbuilder.get_entry_point()
-        return skip_missing_compiler(compile)
-
-
-    def DONTtest_malloc_a_lot(self):
-        def malloc_a_lot():
-            i = 0
-            while i < 10:
-                i += 1
-                a = [1] * 10
-                j = 0
-                while j < 20:
-                    j += 1
-                    a.append(j)
-        fn = self.getcompiled(malloc_a_lot)
-        fn()

Modified: pypy/dist/pypy/translator/tool/cbuild.py
==============================================================================
--- pypy/dist/pypy/translator/tool/cbuild.py	(original)
+++ pypy/dist/pypy/translator/tool/cbuild.py	Wed Aug 24 13:52:27 2005
@@ -36,7 +36,7 @@
         opt = '-O0'
     gcv['OPT'] = opt
 
-def compile_c_module(cfile, modname, include_dirs=None):
+def compile_c_module(cfile, modname, include_dirs=None, libraries=[]):
     #try:
     #    from distutils.log import set_threshold
     #    set_threshold(10000)
@@ -92,7 +92,8 @@
                             'ext_modules': [
                                 Extension(modname, [str(cfile)],
                                     include_dirs=include_dirs,
-                                    extra_compile_args=extra_compile_args)
+                                    extra_compile_args=extra_compile_args,
+                                    libraries=libraries,)
                                 ],
                             'script_name': 'setup.py',
                             'script_args': ['-q', 'build_ext', '--inplace'],



More information about the Pypy-commit mailing list