[pypy-svn] r32880 - in pypy/dist/pypy/rpython/memory/gctransform2: . test

mwh at codespeak.net mwh at codespeak.net
Wed Oct 4 17:18:17 CEST 2006


Author: mwh
Date: Wed Oct  4 17:18:15 2006
New Revision: 32880

Added:
   pypy/dist/pypy/rpython/memory/gctransform2/boehm.py   (contents, props changed)
   pypy/dist/pypy/rpython/memory/gctransform2/framework.py   (contents, props changed)
   pypy/dist/pypy/rpython/memory/gctransform2/test/test_boehm.py   (contents, props changed)
   pypy/dist/pypy/rpython/memory/gctransform2/test/test_framework.py   (contents, props changed)
Modified:
   pypy/dist/pypy/rpython/memory/gctransform2/refcounting.py
Log:
really add boehm this time and add the framework transformer to gctransform2,
or at least enough of it to get the one explicit test of it to pass...


Added: pypy/dist/pypy/rpython/memory/gctransform2/boehm.py
==============================================================================
--- (empty file)
+++ pypy/dist/pypy/rpython/memory/gctransform2/boehm.py	Wed Oct  4 17:18:15 2006
@@ -0,0 +1,64 @@
+from pypy.rpython.memory.gctransform2.transform import GCTransformer
+from pypy.rpython.memory.gctransform2.support import type_contains_pyobjs, \
+     get_rtti, _static_deallocator_body_for_type, LLTransformerOp, ll_call_destructor
+from pypy.rpython.lltypesystem import lltype, llmemory
+from pypy.rpython.lltypesystem.lloperation import llop
+
+class BoehmGCTransformer(GCTransformer):
+    def __init__(self, translator, inline=False):
+        super(BoehmGCTransformer, self).__init__(translator, inline=inline)
+        self.finalizer_funcptrs = {}
+
+    def push_alive_nopyobj(self, var, llops):
+        pass
+
+    def pop_alive_nopyobj(self, var, llops):
+        pass
+
+    def gct_gc_protect(self, hop):
+        """ for boehm it is enough to do nothing"""
+        pass
+
+    def gct_gc_unprotect(self, op, livevars, block):
+        """ for boehm it is enough to do nothing"""
+        pass
+
+    def finalizer_funcptr_for_type(self, TYPE):
+        if TYPE in self.finalizer_funcptrs:
+            return self.finalizer_funcptrs[TYPE]
+
+        rtti = get_rtti(TYPE)
+        if rtti is not None and hasattr(rtti._obj, 'destructor_funcptr'):
+            destrptr = rtti._obj.destructor_funcptr
+            DESTR_ARG = lltype.typeOf(destrptr).TO.ARGS[0]
+        else:
+            destrptr = None
+            DESTR_ARG = None
+
+        if type_contains_pyobjs(TYPE):
+            if destrptr:
+                raise Exception("can't mix PyObjects and __del__ with Boehm")
+
+            static_body = '\n'.join(_static_deallocator_body_for_type('v', TYPE))
+            d = {'pop_alive': LLTransformerOp(self.pop_alive),
+                 'PTR_TYPE':lltype.Ptr(TYPE),
+                 'cast_adr_to_ptr': llmemory.cast_adr_to_ptr}
+            src = ("def ll_finalizer(addr):\n"
+                   "    v = cast_adr_to_ptr(addr, PTR_TYPE)\n"
+                   "%s\n")%(static_body,)
+            exec src in d
+            fptr = self.annotate_helper(d['ll_finalizer'], [llmemory.Address], lltype.Void)
+        elif destrptr:
+            EXC_INSTANCE_TYPE = self.translator.rtyper.exceptiondata.lltype_of_exception_value
+            def ll_finalizer(addr):
+                exc_instance = llop.gc_fetch_exception(EXC_INSTANCE_TYPE)
+                v = llmemory.cast_adr_to_ptr(addr, DESTR_ARG)
+                ll_call_destructor(destrptr, v)
+                llop.gc_restore_exception(lltype.Void, exc_instance)
+            fptr = self.annotate_helper(ll_finalizer, [llmemory.Address], lltype.Void)
+        else:
+            fptr = None
+
+        self.finalizer_funcptrs[TYPE] = fptr
+        return fptr
+

Added: pypy/dist/pypy/rpython/memory/gctransform2/framework.py
==============================================================================
--- (empty file)
+++ pypy/dist/pypy/rpython/memory/gctransform2/framework.py	Wed Oct  4 17:18:15 2006
@@ -0,0 +1,626 @@
+from pypy.rpython.memory.gctransform2.transform import GCTransformer, var_ispyobj
+from pypy.rpython.memory.gctransform2.support import find_gc_ptrs_in_type, \
+     get_rtti, ll_call_destructor, type_contains_pyobjs
+from pypy.rpython.lltypesystem import lltype, llmemory
+from pypy.rpython import rmodel
+from pypy.rpython.memory import gc, lladdress
+from pypy.rpython.memory.gcheader import GCHeaderBuilder
+from pypy.rpython.rarithmetic import ovfcheck
+from pypy.translator.backendopt import graphanalyze
+from pypy.annotation import model as annmodel
+from pypy.rpython import annlowlevel
+from pypy.rpython.rbuiltin import gen_cast
+import sys
+
+
+class CollectAnalyzer(graphanalyze.GraphAnalyzer):
+    def operation_is_true(self, op):
+        return op.opname in ("malloc", "malloc_varsize", "gc__collect",
+                             "gc_x_become")
+
+ADDRESS_VOID_FUNC = lltype.FuncType([llmemory.Address], lltype.Void)
+
+class FrameworkGCTransformer(GCTransformer):
+    use_stackless = False
+    extra_static_slots = 0
+    finished_tables = False
+
+    from pypy.rpython.memory.gc import MarkSweepGC as GCClass
+    GC_PARAMS = {'start_heap_size': 8*1024*1024 # XXX adjust
+                 }
+
+    def __init__(self, translator):
+        from pypy.rpython.memory.support import get_address_linked_list
+        super(FrameworkGCTransformer, self).__init__(translator, inline=False)
+        AddressLinkedList = get_address_linked_list()
+        GCClass = self.GCClass
+        self.finalizer_funcptrs = {}
+        self.FINALIZERTYPE = lltype.Ptr(ADDRESS_VOID_FUNC)
+        class GCData(object):
+            # types of the GC information tables
+            OFFSETS_TO_GC_PTR = lltype.Array(lltype.Signed)
+            TYPE_INFO = lltype.Struct("type_info",
+                ("isvarsize",   lltype.Bool),
+                ("finalyzer",   self.FINALIZERTYPE),
+                ("fixedsize",   lltype.Signed),
+                ("ofstoptrs",   lltype.Ptr(OFFSETS_TO_GC_PTR)),
+                ("varitemsize", lltype.Signed),
+                ("ofstovar",    lltype.Signed),
+                ("ofstolength", lltype.Signed),
+                ("varofstoptrs",lltype.Ptr(OFFSETS_TO_GC_PTR)),
+                )
+            TYPE_INFO_TABLE = lltype.Array(TYPE_INFO)
+
+        def q_is_varsize(typeid):
+            return gcdata.type_info_table[typeid].isvarsize
+
+        def q_finalyzer(typeid):
+            return gcdata.type_info_table[typeid].finalyzer
+
+        def q_offsets_to_gc_pointers(typeid):
+            return gcdata.type_info_table[typeid].ofstoptrs
+
+        def q_fixed_size(typeid):
+            return gcdata.type_info_table[typeid].fixedsize
+
+        def q_varsize_item_sizes(typeid):
+            return gcdata.type_info_table[typeid].varitemsize
+
+        def q_varsize_offset_to_variable_part(typeid):
+            return gcdata.type_info_table[typeid].ofstovar
+
+        def q_varsize_offset_to_length(typeid):
+            return gcdata.type_info_table[typeid].ofstolength
+
+        def q_varsize_offsets_to_gcpointers_in_var_part(typeid):
+            return gcdata.type_info_table[typeid].varofstoptrs
+
+        gcdata = GCData()
+        # set up dummy a table, to be overwritten with the real one in finish()
+        gcdata.type_info_table = lltype.malloc(GCData.TYPE_INFO_TABLE, 0,
+                                               immortal=True)
+        gcdata.static_roots = lltype.malloc(lltype.Array(llmemory.Address), 0,
+                                            immortal=True)
+        # initialize the following two fields with a random non-NULL address,
+        # to make the annotator happy.  The fields are patched in finish()
+        # to point to a real array (not 'static_roots', another one).
+        a_random_address = llmemory.cast_ptr_to_adr(gcdata.type_info_table)
+        gcdata.static_root_start = a_random_address   # patched in finish()
+        gcdata.static_root_end = a_random_address     # patched in finish()
+        self.gcdata = gcdata
+        self.type_info_list = []
+        self.id_of_type = {}      # {LLTYPE: type_id}
+        self.seen_roots = {}
+        self.static_gc_roots = []
+        self.addresses_of_static_ptrs_in_nongc = []
+        self.offsettable_cache = {}
+        self.malloc_fnptr_cache = {}
+
+        sizeofaddr = llmemory.sizeof(llmemory.Address)
+
+        StackRootIterator = self.build_stack_root_iterator()
+        gcdata.gc = GCClass(AddressLinkedList, get_roots=StackRootIterator, **self.GC_PARAMS)
+
+        def frameworkgc_setup():
+            # run-time initialization code
+            StackRootIterator.setup_root_stack()
+            gcdata.gc.setup()
+            gcdata.gc.set_query_functions(
+                q_is_varsize,
+                q_finalyzer,
+                q_offsets_to_gc_pointers,
+                q_fixed_size,
+                q_varsize_item_sizes,
+                q_varsize_offset_to_variable_part,
+                q_varsize_offset_to_length,
+                q_varsize_offsets_to_gcpointers_in_var_part)
+
+        bk = self.translator.annotator.bookkeeper
+
+        # the point of this little dance is to not annotate
+        # self.gcdata.type_info_table as a constant.
+        data_classdef = bk.getuniqueclassdef(GCData)
+        data_classdef.generalize_attr(
+            'type_info_table',
+            annmodel.SomePtr(lltype.Ptr(GCData.TYPE_INFO_TABLE)))
+        data_classdef.generalize_attr(
+            'static_roots',
+            annmodel.SomePtr(lltype.Ptr(lltype.Array(llmemory.Address))))
+        data_classdef.generalize_attr(
+            'static_root_start',
+            annmodel.SomeAddress())
+        data_classdef.generalize_attr(
+            'static_root_end',
+            annmodel.SomeAddress())
+
+        annhelper = annlowlevel.MixLevelHelperAnnotator(self.translator.rtyper)
+
+        def getfn(ll_function, args_s, s_result, inline=False,
+                  minimal_transform=True):
+            graph = annhelper.getgraph(ll_function, args_s, s_result)
+            if minimal_transform:
+                self.need_minimal_transform(graph)
+            if inline:
+                self.graphs_to_inline[graph] = True
+            return annhelper.graph2const(graph)
+
+        self.frameworkgc_setup_ptr = getfn(frameworkgc_setup, [],
+                                           annmodel.s_None)
+        if StackRootIterator.push_root is None:
+            self.push_root_ptr = None
+        else:
+            self.push_root_ptr = getfn(StackRootIterator.push_root,
+                                       [annmodel.SomeAddress()],
+                                       annmodel.s_None,
+                                       inline = True)
+        if StackRootIterator.pop_root is None:
+            self.pop_root_ptr = None
+        else:
+            self.pop_root_ptr = getfn(StackRootIterator.pop_root, [],
+                                      annmodel.s_None,
+                                      inline = True)
+
+        classdef = bk.getuniqueclassdef(GCClass)
+        s_gc = annmodel.SomeInstance(classdef)
+        s_gcref = annmodel.SomePtr(llmemory.GCREF)
+        self.malloc_fixedsize_ptr = getfn(
+            GCClass.malloc_fixedsize.im_func,
+            [s_gc, annmodel.SomeInteger(nonneg=True),
+             annmodel.SomeInteger(nonneg=True),
+             annmodel.SomeBool(), annmodel.SomeBool()], s_gcref,
+            inline = False)
+        self.malloc_fixedsize_clear_ptr = getfn(
+            GCClass.malloc_fixedsize_clear.im_func,
+            [s_gc, annmodel.SomeInteger(nonneg=True),
+             annmodel.SomeInteger(nonneg=True),
+             annmodel.SomeBool(), annmodel.SomeBool()], s_gcref,
+            inline = False)
+##         self.malloc_varsize_ptr = getfn(
+##             GCClass.malloc_varsize.im_func,
+##             [s_gc] + [annmodel.SomeInteger(nonneg=True) for i in range(5)]
+##             + [annmodel.SomeBool(), annmodel.SomeBool()], s_gcref)
+        self.malloc_varsize_clear_ptr = getfn(
+            GCClass.malloc_varsize_clear.im_func,
+            [s_gc] + [annmodel.SomeInteger(nonneg=True) for i in range(5)]
+            + [annmodel.SomeBool(), annmodel.SomeBool()], s_gcref)
+        self.collect_ptr = getfn(GCClass.collect.im_func,
+            [s_gc], annmodel.s_None)
+
+        self.statistics_ptr = getfn(GCClass.statistics.im_func,
+                                    [s_gc, annmodel.SomeInteger()],
+                                    annmodel.SomeInteger())
+
+        # experimental gc_x_* operations
+        s_x_pool  = annmodel.SomePtr(gc.X_POOL_PTR)
+        s_x_clone = annmodel.SomePtr(gc.X_CLONE_PTR)
+        # the x_*() methods use some regular mallocs that must be
+        # transformed in the normal way
+        self.x_swap_pool_ptr = getfn(GCClass.x_swap_pool.im_func,
+                                     [s_gc, s_x_pool],
+                                     s_x_pool,
+                                     minimal_transform = False)
+        self.x_clone_ptr = getfn(GCClass.x_clone.im_func,
+                                 [s_gc, s_x_clone],
+                                 annmodel.s_None,
+                                 minimal_transform = False)
+
+        self.x_become_ptr = getfn(
+            GCClass.x_become.im_func,
+            [s_gc, annmodel.SomeAddress(), annmodel.SomeAddress()],
+            annmodel.s_None)
+
+        annhelper.finish()   # at this point, annotate all mix-level helpers
+        annhelper.backend_optimize()
+
+        self.collect_analyzer = CollectAnalyzer(self.translator)
+        self.collect_analyzer.analyze_all()
+
+        s_gc = self.translator.annotator.bookkeeper.valueoftype(GCClass)
+        r_gc = self.translator.rtyper.getrepr(s_gc)
+        self.c_const_gc = rmodel.inputconst(r_gc, self.gcdata.gc)
+
+        HDR = self._gc_HDR = self.gcdata.gc.gcheaderbuilder.HDR
+        self._gc_fields = fields = []
+        for fldname in HDR._names:
+            FLDTYPE = getattr(HDR, fldname)
+            fields.append(('_' + fldname, FLDTYPE))
+
+    def build_stack_root_iterator(self):
+        gcdata = self.gcdata
+        sizeofaddr = llmemory.sizeof(llmemory.Address)
+        rootstacksize = sizeofaddr * 163840    # XXX adjust
+
+        class StackRootIterator:
+            _alloc_flavor_ = 'raw'
+            def setup_root_stack():
+                stackbase = lladdress.raw_malloc(rootstacksize)
+                lladdress.raw_memclear(stackbase, rootstacksize)
+                gcdata.root_stack_top  = stackbase
+                gcdata.root_stack_base = stackbase
+                i = 0
+                while i < len(gcdata.static_roots):
+                    StackRootIterator.push_root(gcdata.static_roots[i])
+                    i += 1
+            setup_root_stack = staticmethod(setup_root_stack)
+
+            def push_root(addr):
+                top = gcdata.root_stack_top
+                top.address[0] = addr
+                gcdata.root_stack_top = top + sizeofaddr
+            push_root = staticmethod(push_root)
+
+            def pop_root():
+                gcdata.root_stack_top -= sizeofaddr
+            pop_root = staticmethod(pop_root)
+
+            def __init__(self):
+                self.stack_current = gcdata.root_stack_top
+                self.static_current = gcdata.static_root_start
+
+            def pop(self):
+                while self.static_current != gcdata.static_root_end:
+                    result = self.static_current
+                    self.static_current += sizeofaddr
+                    if result.address[0].address[0] != llmemory.NULL:
+                        return result.address[0]
+                while self.stack_current != gcdata.root_stack_base:
+                    self.stack_current -= sizeofaddr
+                    if self.stack_current.address[0] != llmemory.NULL:
+                        return self.stack_current
+                return llmemory.NULL
+
+        return StackRootIterator
+
+    def get_type_id(self, TYPE):
+        try:
+            return self.id_of_type[TYPE]
+        except KeyError:
+            assert not self.finished_tables
+            assert isinstance(TYPE, (lltype.GcStruct, lltype.GcArray))
+            # Record the new type_id description as a small dict for now.
+            # It will be turned into a Struct("type_info") in finish()
+            type_id = len(self.type_info_list)
+            info = {}
+            self.type_info_list.append(info)
+            self.id_of_type[TYPE] = type_id
+            offsets = offsets_to_gc_pointers(TYPE)
+            info["ofstoptrs"] = self.offsets2table(offsets, TYPE)
+            info["finalyzer"] = self.finalizer_funcptr_for_type(TYPE)
+            if not TYPE._is_varsize():
+                info["isvarsize"] = False
+                info["fixedsize"] = llmemory.sizeof(TYPE)
+                info["ofstolength"] = -1
+            else:
+                info["isvarsize"] = True
+                info["fixedsize"] = llmemory.sizeof(TYPE, 0)
+                if isinstance(TYPE, lltype.Struct):
+                    ARRAY = TYPE._flds[TYPE._arrayfld]
+                    ofs1 = llmemory.offsetof(TYPE, TYPE._arrayfld)
+                    info["ofstolength"] = ofs1 + llmemory.ArrayLengthOffset(ARRAY)
+                    if ARRAY.OF != lltype.Void:
+                        info["ofstovar"] = ofs1 + llmemory.itemoffsetof(ARRAY, 0)
+                    else:
+                        info["fixedsize"] = ofs1 + llmemory.sizeof(lltype.Signed)
+                    if ARRAY._hints.get('isrpystring'):
+                        info["fixedsize"] = llmemory.sizeof(TYPE, 1)
+                else:
+                    ARRAY = TYPE
+                    info["ofstolength"] = llmemory.ArrayLengthOffset(ARRAY)
+                    if ARRAY.OF != lltype.Void:
+                        info["ofstovar"] = llmemory.itemoffsetof(TYPE, 0)
+                    else:
+                        info["fixedsize"] = llmemory.ArrayLengthOffset(ARRAY) + llmemory.sizeof(lltype.Signed)
+                assert isinstance(ARRAY, lltype.Array)
+                if ARRAY.OF != lltype.Void:
+                    offsets = offsets_to_gc_pointers(ARRAY.OF)
+                    info["varofstoptrs"] = self.offsets2table(offsets, ARRAY.OF)
+                    info["varitemsize"] = llmemory.sizeof(ARRAY.OF)
+                else:
+                    info["varofstoptrs"] = self.offsets2table((), lltype.Void)
+                    info["varitemsize"] = llmemory.sizeof(ARRAY.OF)
+            return type_id
+
+    def finalizer_funcptr_for_type(self, TYPE):
+        if TYPE in self.finalizer_funcptrs:
+            return self.finalizer_funcptrs[TYPE]
+
+        rtti = get_rtti(TYPE)
+        if rtti is not None and hasattr(rtti._obj, 'destructor_funcptr'):
+            destrptr = rtti._obj.destructor_funcptr
+            DESTR_ARG = lltype.typeOf(destrptr).TO.ARGS[0]
+        else:
+            destrptr = None
+            DESTR_ARG = None
+
+        assert not type_contains_pyobjs(TYPE), "not implemented"
+        if destrptr:
+            def ll_finalizer(addr):
+                v = llmemory.cast_adr_to_ptr(addr, DESTR_ARG)
+                ll_call_destructor(destrptr, v)
+            fptr = self.annotate_helper(ll_finalizer, [llmemory.Address], lltype.Void)
+        else:
+            fptr = lltype.nullptr(ADDRESS_VOID_FUNC)
+
+        self.finalizer_funcptrs[TYPE] = fptr
+        return fptr
+
+    def consider_constant(self, TYPE, value):
+        if value is not lltype.top_container(value):
+            return
+        if id(value) in self.seen_roots:
+            return
+        self.seen_roots[id(value)] = True
+
+        if isinstance(TYPE, (lltype.GcStruct, lltype.GcArray)):
+            typeid = self.get_type_id(TYPE)
+            hdrbuilder = self.gcdata.gc.gcheaderbuilder
+            hdr = hdrbuilder.new_header(value)
+            adr = llmemory.cast_ptr_to_adr(hdr)
+            self.gcdata.gc.init_gc_object(adr, typeid)
+
+        if find_gc_ptrs_in_type(TYPE):
+            adr = llmemory.cast_ptr_to_adr(value._as_ptr())
+            if isinstance(TYPE, (lltype.GcStruct, lltype.GcArray)):
+                self.static_gc_roots.append(adr)
+            else:
+                for a in gc_pointers_inside(value, adr):
+                    self.addresses_of_static_ptrs_in_nongc.append(a)
+
+    def gc_fields(self):
+        return self._gc_fields
+
+    def gc_field_values_for(self, obj):
+        hdr = self.gcdata.gc.gcheaderbuilder.header_of_object(obj)
+        HDR = self._gc_HDR
+        return [getattr(hdr, fldname) for fldname in HDR._names]
+
+    def offsets2table(self, offsets, TYPE):
+        try:
+            return self.offsettable_cache[TYPE]
+        except KeyError:
+            cachedarray = lltype.malloc(self.gcdata.OFFSETS_TO_GC_PTR,
+                                        len(offsets), immortal=True)
+            for i, value in enumerate(offsets):
+                cachedarray[i] = value
+            self.offsettable_cache[TYPE] = cachedarray
+            return cachedarray
+
+    def finish_tables(self):
+        self.finished_tables = True
+        table = lltype.malloc(self.gcdata.TYPE_INFO_TABLE,
+                              len(self.type_info_list), immortal=True)
+        for tableentry, newcontent in zip(table, self.type_info_list):
+            for key, value in newcontent.items():
+                setattr(tableentry, key, value)
+        self.offsettable_cache = None
+
+        # replace the type_info_table pointer in gcdata -- at this point,
+        # the database is in principle complete, so it has already seen
+        # the old (empty) array.  We need to force it to consider the new
+        # array now.  It's a bit hackish as the old empty array will also
+        # be generated in the C source, but that's a rather minor problem.
+
+        # XXX because we call inputconst already in replace_malloc, we can't
+        # modify the instance, we have to modify the 'rtyped instance'
+        # instead.  horrors.  is there a better way?
+
+        s_gcdata = self.translator.annotator.bookkeeper.immutablevalue(
+            self.gcdata)
+        r_gcdata = self.translator.rtyper.getrepr(s_gcdata)
+        ll_instance = rmodel.inputconst(r_gcdata, self.gcdata).value
+        ll_instance.inst_type_info_table = table
+        #self.gcdata.type_info_table = table
+
+        ll_static_roots = lltype.malloc(lltype.Array(llmemory.Address),
+                                        len(self.static_gc_roots) +
+                                            self.extra_static_slots,
+                                        immortal=True)
+        for i in range(len(self.static_gc_roots)):
+            adr = self.static_gc_roots[i]
+            ll_static_roots[i] = adr
+        ll_instance.inst_static_roots = ll_static_roots
+
+        ll_static_roots_inside = lltype.malloc(lltype.Array(llmemory.Address),
+                                               len(self.addresses_of_static_ptrs_in_nongc),
+                                               immortal=True)
+        for i in range(len(self.addresses_of_static_ptrs_in_nongc)):
+            ll_static_roots_inside[i] = self.addresses_of_static_ptrs_in_nongc[i]
+        ll_instance.inst_static_root_start = llmemory.cast_ptr_to_adr(ll_static_roots_inside) + llmemory.ArrayItemsOffset(lltype.Array(llmemory.Address))
+        ll_instance.inst_static_root_end = ll_instance.inst_static_root_start + llmemory.sizeof(llmemory.Address) * len(ll_static_roots_inside)
+
+        newgcdependencies = []
+        newgcdependencies.append(table)
+        newgcdependencies.append(ll_static_roots)
+        newgcdependencies.append(ll_static_roots_inside)
+        return newgcdependencies
+
+    def gct_direct_call(self, hop):
+        if self.collect_analyzer.analyze(hop.spaceop):
+            self.push_roots(hop)
+            self.default(hop)
+            self.pop_roots(hop)
+        else:
+            self.default(hop)
+
+    gct_indirect_call = gct_direct_call
+
+    def gct_malloc(self, hop):
+        op = hop.spaceop
+
+        if op.opname.startswith('flavored_'):
+            flavor = op.args[0].value
+            TYPE = op.args[1].value
+        else:
+            flavor = 'gc'
+            TYPE = op.args[0].value
+
+        if not flavor.startswith('gc'):
+            self.default(hop)
+            return
+
+        c_can_collect = rmodel.inputconst(lltype.Bool,
+                                          flavor != 'gc_nocollect')
+        PTRTYPE = op.result.concretetype
+        assert PTRTYPE.TO == TYPE
+        type_id = self.get_type_id(TYPE)
+
+        c_type_id = rmodel.inputconst(lltype.Signed, type_id)
+        info = self.type_info_list[type_id]
+        c_size = rmodel.inputconst(lltype.Signed, info["fixedsize"])
+        if not op.opname.endswith('_varsize'):
+            #malloc_ptr = self.malloc_fixedsize_ptr
+            if op.opname.startswith('zero'):
+                malloc_ptr = self.malloc_fixedsize_clear_ptr
+            else:
+                malloc_ptr = self.malloc_fixedsize_ptr
+            args = [self.c_const_gc, c_type_id, c_size, c_can_collect]
+        else:
+            v_length = op.args[-1]
+            c_ofstolength = rmodel.inputconst(lltype.Signed, info['ofstolength'])
+            c_varitemsize = rmodel.inputconst(lltype.Signed, info['varitemsize'])
+            malloc_ptr = self.malloc_varsize_clear_ptr
+##             if op.opname.startswith('zero'):
+##                 malloc_ptr = self.malloc_varsize_clear_ptr
+##             else:
+##                 malloc_ptr = self.malloc_varsize_clear_ptr
+            args = [self.c_const_gc, c_type_id, v_length, c_size,
+                    c_varitemsize, c_ofstolength, c_can_collect]
+        c_has_finalizer = rmodel.inputconst(
+            lltype.Bool, bool(self.finalizer_funcptr_for_type(TYPE)))
+        args.append(c_has_finalizer)
+        
+        self.push_roots(hop)
+        v_result = hop.genop("direct_call", [malloc_ptr] + args,
+                             resulttype=llmemory.GCREF)
+        self.pop_roots(hop)
+        hop.cast_result(v_result)
+        if malloc_ptr == self.malloc_fixedsize_ptr:
+            gen_zero_gc_pointers(TYPE, op.result, hop.llops)
+
+    gct_zero_malloc = gct_malloc
+    gct_malloc_varsize = gct_malloc
+    gct_zero_malloc_varsize = gct_malloc
+    gct_flavored_malloc = gct_malloc
+    gct_flavored_malloc_varsize = gct_malloc
+
+    def gct_gc__collect(self, hop):
+        op = hop.spaceop
+        self.push_roots(hop)
+        hop.genop("direct_call", [self.collect_ptr, self.c_const_gc],
+                  resultvar=op.result)
+        self.pop_roots(hop)
+        return ops
+
+    def gct_gc_x_swap_pool(self, hop):
+        op = hop.spaceop
+        [v_malloced] = op.args
+        hop.genop("direct_call",
+                  [self.x_swap_pool_ptr, self.c_const_gc, v_malloced],
+                  resultvar=op.result)
+
+    def gct_gc_x_clone(self, hop):
+        op = hop.spaceop
+        [v_clonedata] = op.args
+        hop.genop("direct_call",
+                  [self.x_clone_ptr, self.c_const_gc, v_clonedata],
+                  resultvar=op.result)
+
+    def gct_gc_x_size_header(self, hop):
+        op = hop.spaceop
+        c_result = rmodel.inputconst(lltype.Signed,
+                                     self.gcdata.gc.size_gc_header())
+        hop.genop("same_as",
+                  [c_result],
+                  resultvar=op.result)
+
+    def gct_gc_x_become(self, hop):
+        op = hop.spaceop
+        [v_target, v_source] = op.args
+        self.push_roots(hop)
+        hop.genop("direct_call",
+                  [self.x_become_ptr, self.c_const_gc, v_target, v_source],
+                  resultvar=op.result)
+        self.pop_roots(hop)
+
+    def push_alive_nopyobj(self, var, llops):
+        pass
+
+    def pop_alive_nopyobj(self, var, llops):
+        pass
+
+    def push_roots(self, hop):
+        if self.push_root_ptr is None:
+            return
+        livevars = [var for var in self.livevars if not var_ispyobj(var)]
+        for var in livevars:
+            v_adr = gen_cast(hop.llops, llmemory.Address, var)
+            hop.genop("direct_call", [self.push_root_ptr, v_adr])
+
+    def pop_roots(self, hop):
+        if self.pop_root_ptr is None:
+            return
+        livevars = [var for var in self.livevars if not var_ispyobj(var)]
+        for var in livevars[::-1]:
+            # XXX specific to non-moving collectors
+            hop.genop("direct_call", [self.pop_root_ptr])
+            #hop.genop("gc_reload_possibly_moved", [var])
+
+# XXX copied and modified from lltypelayout.py
+def offsets_to_gc_pointers(TYPE):
+    offsets = []
+    if isinstance(TYPE, lltype.Struct):
+        for name in TYPE._names:
+            FIELD = getattr(TYPE, name)
+            if isinstance(FIELD, lltype.Array):
+                continue    # skip inlined array
+            baseofs = llmemory.offsetof(TYPE, name)
+            suboffsets = offsets_to_gc_pointers(FIELD)
+            for s in suboffsets:
+                try:
+                    knownzero = s == 0
+                except TypeError:
+                    knownzero = False
+                if knownzero:
+                    offsets.append(baseofs)
+                else:
+                    offsets.append(baseofs + s)
+        # sanity check
+        #ex = lltype.Ptr(TYPE)._example()
+        #adr = llmemory.cast_ptr_to_adr(ex)
+        #for off in offsets:
+        #    (adr + off)
+    elif isinstance(TYPE, lltype.Ptr) and TYPE.TO._gckind == 'gc':
+        offsets.append(0)
+    return offsets
+
+def gen_zero_gc_pointers(TYPE, v, llops):
+    assert isinstance(TYPE, lltype.Struct)
+    for name in TYPE._names:
+        FIELD = getattr(TYPE, name)
+        if isinstance(FIELD, lltype.Ptr) and FIELD._needsgc():
+            c_name = rmodel.inputconst(lltype.Void, name)
+            c_null = rmodel.inputconst(FIELD, lltype.nullptr(FIELD.TO))
+            llops.genop('bare_setfield', [v, c_name, c_null])
+        elif isinstance(FIELD, lltype.Struct):
+            c_name = rmodel.inputconst(lltype.Void, name)
+            v1 = llops.genop('getsubstruct', [v, c_name],
+                             resulttype = lltype.Ptr(FIELD))
+            gen_zero_gc_pointers(FIELD, v1, llops)
+
+def gc_pointers_inside(v, adr):
+    t = lltype.typeOf(v)
+    if isinstance(t, lltype.Struct):
+        for n, t2 in t._flds.iteritems():
+            if isinstance(t2, lltype.Ptr) and t2.TO._gckind == 'gc':
+                yield adr + llmemory.offsetof(t, n)
+            elif isinstance(t2, (lltype.Array, lltype.Struct)):
+                for a in gc_pointers_inside(getattr(v, n), adr + llmemory.offsetof(t, n)):
+                    yield a
+    elif isinstance(t, lltype.Array):
+        if isinstance(t.OF, lltype.Ptr) and t2._needsgc():
+            for i in range(len(v.items)):
+                yield adr + llmemory.itemoffsetof(t, i)
+        elif isinstance(t.OF, lltype.Struct):
+            for i in range(len(v.items)):
+                for a in gc_pointers_inside(v.items[i], adr + llmemory.itemoffsetof(t, i)):
+                    yield a

Modified: pypy/dist/pypy/rpython/memory/gctransform2/refcounting.py
==============================================================================
--- pypy/dist/pypy/rpython/memory/gctransform2/refcounting.py	(original)
+++ pypy/dist/pypy/rpython/memory/gctransform2/refcounting.py	Wed Oct  4 17:18:15 2006
@@ -8,7 +8,6 @@
 from pypy.rpython import rmodel
 from pypy.rpython.memory import lladdress
 from pypy.rpython.memory.gcheader import GCHeaderBuilder
-#from pypy.rpython.extregistry import ExtRegistryEntry
 from pypy.rpython.rarithmetic import ovfcheck
 from pypy.rpython.rbuiltin import gen_cast
 import sys

Added: pypy/dist/pypy/rpython/memory/gctransform2/test/test_boehm.py
==============================================================================
--- (empty file)
+++ pypy/dist/pypy/rpython/memory/gctransform2/test/test_boehm.py	Wed Oct  4 17:18:15 2006
@@ -0,0 +1,70 @@
+from pypy.rpython.memory.gctransform2.boehm import BoehmGCTransformer
+from pypy.rpython.memory.gctransform2.test.test_transform import rtype_and_transform, getops
+from pypy.rpython.memory.gctransform2.test.test_refcounting import make_deallocator
+from pypy.rpython.lltypesystem import lltype
+from pypy.translator.translator import graphof
+from pypy import conftest
+import py
+
+def make_boehm_finalizer(TYPE):
+    return make_deallocator(TYPE, attr="finalizer_funcptr_for_type",
+                            cls=BoehmGCTransformer)
+
+def test_boehm_simple():
+    class C:
+        pass
+    def f():
+        c = C()
+        c.x = 1
+        return c.x
+    t, transformer = rtype_and_transform(
+        f, [], BoehmGCTransformer, check=False)
+    ops = getops(graphof(t, f))
+    assert len(ops.get('direct_call', [])) <= 1
+    gcs = [k for k in ops if k.startswith('gc')]
+    assert len(gcs) == 0
+
+def test_boehm_finalizer_simple():
+    S = lltype.GcStruct("S", ('x', lltype.Signed))
+    f, t = make_boehm_finalizer(S)
+    assert f is None
+
+def test_boehm_finalizer_pyobj():
+    S = lltype.GcStruct("S", ('x', lltype.Ptr(lltype.PyObject)))
+    f, t = make_boehm_finalizer(S)
+    assert f is not None
+
+def test_boehm_finalizer___del__():
+    S = lltype.GcStruct("S", ('x', lltype.Signed))
+    def f(s):
+        s.x = 1
+    def type_info_S(p):
+        return lltype.getRuntimeTypeInfo(S)
+    qp = lltype.functionptr(lltype.FuncType([lltype.Ptr(S)],
+                                            lltype.Ptr(lltype.RuntimeTypeInfo)),
+                            "type_info_S",
+                            _callable=type_info_S)
+    dp = lltype.functionptr(lltype.FuncType([lltype.Ptr(S)],
+                                            lltype.Void),
+                            "destructor_funcptr",
+                            _callable=f)
+    pinf = lltype.attachRuntimeTypeInfo(S, qp, destrptr=dp)
+    f, t = make_boehm_finalizer(S)
+    assert f is not None
+
+def test_boehm_finalizer_nomix___del___and_pyobj():
+    S = lltype.GcStruct("S", ('x', lltype.Signed), ('y', lltype.Ptr(lltype.PyObject)))
+    def f(s):
+        s.x = 1
+    def type_info_S(p):
+        return lltype.getRuntimeTypeInfo(S)
+    qp = lltype.functionptr(lltype.FuncType([lltype.Ptr(S)],
+                                            lltype.Ptr(lltype.RuntimeTypeInfo)),
+                            "type_info_S",
+                            _callable=type_info_S)
+    dp = lltype.functionptr(lltype.FuncType([lltype.Ptr(S)],
+                                            lltype.Void),
+                            "destructor_funcptr",
+                            _callable=f)
+    pinf = lltype.attachRuntimeTypeInfo(S, qp, destrptr=dp)
+    py.test.raises(Exception, "make_boehm_finalizer(S)")

Added: pypy/dist/pypy/rpython/memory/gctransform2/test/test_framework.py
==============================================================================
--- (empty file)
+++ pypy/dist/pypy/rpython/memory/gctransform2/test/test_framework.py	Wed Oct  4 17:18:15 2006
@@ -0,0 +1,45 @@
+from pypy.rpython.memory.gctransform2.test.test_transform import rtype
+from pypy.rpython.memory.gctransform2.framework import FrameworkGCTransformer
+from pypy.rpython.lltypesystem import lltype
+from pypy.translator.c.gc import FrameworkGcPolicy
+from pypy.translator.translator import TranslationContext, graphof
+from pypy import conftest
+
+import py
+
+class FrameworkGcPolicy2(FrameworkGcPolicy):
+    transformerclass = FrameworkGCTransformer
+
+def test_framework_simple():
+    def g(x):
+        return x + 1
+    class A(object):
+        pass
+    def entrypoint(argv):
+        a = A()
+        a.b = g(1)
+        return str(a.b)
+
+    from pypy.rpython.llinterp import LLInterpreter
+    from pypy.translator.c.genc import CStandaloneBuilder
+    from pypy.translator.c import gc
+    from pypy.annotation.listdef import s_list_of_strings
+
+    t = rtype(entrypoint, [s_list_of_strings])
+    cbuild = CStandaloneBuilder(t, entrypoint, FrameworkGcPolicy2)
+    db = cbuild.generate_graphs_for_llinterp()
+    entrypointptr = cbuild.getentrypointptr()
+    entrygraph = entrypointptr._obj.graph
+
+    r_list_of_strings = t.rtyper.getrepr(s_list_of_strings)
+    ll_argv = r_list_of_strings.convert_const([])
+
+    llinterp = LLInterpreter(t.rtyper)
+
+    # FIIIIISH
+    setupgraph = db.gctransformer.frameworkgc_setup_ptr.value._obj.graph
+    llinterp.eval_graph(setupgraph, [])
+
+    res = llinterp.eval_graph(entrygraph, [ll_argv])
+
+    assert ''.join(res.chars) == "2"



More information about the Pypy-commit mailing list