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

cfbolz at codespeak.net cfbolz at codespeak.net
Thu Aug 11 22:30:20 CEST 2005


Author: cfbolz
Date: Thu Aug 11 22:30:19 2005
New Revision: 15977

Added:
   pypy/dist/pypy/rpython/memory/gcwrapper.py
Modified:
   pypy/dist/pypy/rpython/llinterp.py
   pypy/dist/pypy/rpython/memory/gc.py
   pypy/dist/pypy/rpython/memory/gclltype.py
   pypy/dist/pypy/rpython/memory/test/test_llinterpsim.py
Log:
first stab at integrating garbage collection in the llinterpreter.
This is probably still quite flaky. At the moment only collectors that
don't need read/write barriers are supported and collectors that need
only the roots.

I cheat in some places: the offsets in objects to pointers to other
objects are found by using the searching through the lltype. this can
be computed in advance, but isn't at the moment.

This all is not very well tested yet :-(. I suspect that there are
some bugs. I need to check in to change computers.



Modified: pypy/dist/pypy/rpython/llinterp.py
==============================================================================
--- pypy/dist/pypy/rpython/llinterp.py	(original)
+++ pypy/dist/pypy/rpython/llinterp.py	Thu Aug 11 22:30:19 2005
@@ -19,6 +19,10 @@
     def __init__(self, flowgraphs, typer, lltype=lltype, prepare_graphs=None):
         if prepare_graphs is not None:
             prepare_graphs(flowgraphs)
+        if hasattr(lltype, "create_gc"):
+            self.gc = lltype.create_gc(self)
+        else:
+            self.gc = None
         self.flowgraphs = flowgraphs
         self.bindings = {}
         self.typer = typer
@@ -55,6 +59,17 @@
                     print "   ",
                 print operation
 
+    def find_roots(self):
+        print "find_roots"
+        frame = self.active_frame
+        roots = []
+        while frame is not None:
+            print frame.graph.name
+            frame.find_roots(roots)
+            frame = frame.f_back
+        return roots
+
+
 # implementations of ops from flow.operation
 from pypy.objspace.flow.operation import FunctionByName
 opimpls = FunctionByName.copy()
@@ -212,6 +227,16 @@
             #print "GOT A CPYTHON EXCEPTION:", e.__class__, e
             self.make_llexception(e)
 
+    def find_roots(self, roots):
+        print "find_roots in LLFrame", roots, self.curr_block.inputargs
+        for arg in self.curr_block.inputargs:
+            if (isinstance(arg, Variable) and
+                isinstance(self.getval(arg), self.llt._ptr)):
+                roots.append(self.getval(arg))
+        for op in self.curr_block.operations[:self.curr_operation_index]:
+            if isinstance(self.getval(op.result), self.llt._ptr):
+                roots.append(self.getval(op.result))
+
     # __________________________________________________________
     # misc LL operation implementations
 
@@ -249,7 +274,16 @@
         return frame.eval()
 
     def op_malloc(self, obj):
-        return self.llt.malloc(obj)
+        if self.llinterpreter.gc is not None:
+            return self.llinterpreter.gc.malloc(obj)
+        else:
+            return self.llt.malloc(obj)
+
+    def op_malloc_varsize(self, obj, size):
+        if self.llinterpreter.gc is not None:
+            return self.llinterpreter.gc.malloc(obj, size)
+        else:
+            return self.llt.malloc(obj, size)
 
     def op_getfield(self, obj, field):
         assert isinstance(obj, self.llt._ptr)
@@ -269,9 +303,6 @@
                 self.llt.Ptr(getattr(self.llt.typeOf(obj).TO, field)))
         return result
 
-    def op_malloc_varsize(self, obj, size):
-        return self.llt.malloc(obj, size)
-
     def op_getarraysubstruct(self, array, index):
         assert isinstance(array, self.llt._ptr)
         result = array[index]

Modified: pypy/dist/pypy/rpython/memory/gc.py
==============================================================================
--- pypy/dist/pypy/rpython/memory/gc.py	(original)
+++ pypy/dist/pypy/rpython/memory/gc.py	Thu Aug 11 22:30:19 2005
@@ -54,9 +54,11 @@
                 break
             # roots is a list of addresses to addresses:
             objects.append(curr.address[0])
+            gc_info = curr.address[0] - 2 * INT_SIZE
+            assert gc_info.signed[0] == 0
         while 1:  #mark
             curr = objects.pop()
-            print "root: ", curr
+            print "object: ", curr
             if curr == NULL:
                 break
             gc_info = curr - 2 * INT_SIZE

Modified: pypy/dist/pypy/rpython/memory/gclltype.py
==============================================================================
--- pypy/dist/pypy/rpython/memory/gclltype.py	(original)
+++ pypy/dist/pypy/rpython/memory/gclltype.py	Thu Aug 11 22:30:19 2005
@@ -21,7 +21,7 @@
 
 
 # the following names from lltype will probably have to be implemented yet:
-# opaqueptr, pyobjectptr, attachRuntimeTypeInfo, getRuntimeTypeInfo,
+# opaqueptr, attachRuntimeTypeInfo, getRuntimeTypeInfo,
 # runtime_type_info
 
 opaqueptr = attachRuntimeTypeInfo = notimplemented
@@ -34,3 +34,16 @@
     fgcc = FlowGraphConstantConverter(flowgraphs)
     fgcc.convert()
 
+def create_no_gc(llinterp):
+    return None
+
+def create_mark_sweep_gc(llinterp):
+    from pypy.rpython.memory.gcwrapper import GcWrapper, LLInterpObjectModel
+    from pypy.rpython.memory.gc import MarkSweepGC
+    om = LLInterpObjectModel(llinterp)
+    gc = MarkSweepGC(om, 4096)
+    wrapper = GcWrapper(llinterp, gc)
+    return wrapper
+
+create_gc = create_no_gc
+

Added: pypy/dist/pypy/rpython/memory/gcwrapper.py
==============================================================================
--- (empty file)
+++ pypy/dist/pypy/rpython/memory/gcwrapper.py	Thu Aug 11 22:30:19 2005
@@ -0,0 +1,102 @@
+from pypy.rpython import lltype
+from pypy.rpython.memory.support import AddressLinkedList, INT_SIZE
+from pypy.rpython.memory.lladdress import raw_malloc, raw_free, NULL
+from pypy.rpython.memory import lltypesimulation
+from pypy.rpython.memory.gc import MarkSweepGC
+
+class LLInterpObjectModel(object):
+    def __init__(self, llinterp):
+        self.type_to_typeid = {}
+        self.types = []
+        self.roots = []
+        self.pseudo_root_pointers = NULL
+        self.llinterp = llinterp
+
+    def update_changed_addresses(self):
+        for i, root in enumerate(self.roots):
+            if root._address != self.pseudo_root_pointers.address[i]:
+                print "address changed:", root._address, self.pseudo_root_pointers.address[i]
+            root.__dict__['_address'] = self.pseudo_root_pointers.address[i]
+
+    def get_typeid(self, TYPE):
+        if TYPE not in self.type_to_typeid:
+            index = len(self.types)
+            self.type_to_typeid[TYPE] = index
+            self.types.append(TYPE)
+        typeid = self.type_to_typeid[TYPE]
+        return typeid
+
+    def get_roots(self):
+        print "getting roots"
+        if self.pseudo_root_pointers != NULL:
+            raw_free(self.pseudo_root_pointers)
+        self.roots = self.llinterp.find_roots()
+        print "found:", self.roots
+        self.pseudo_root_pointers = raw_malloc(len(self.roots) * INT_SIZE)
+        ll = AddressLinkedList()
+        for i, root in enumerate(self.roots):
+            self.pseudo_root_pointers.address[i] = root._address
+            ll.append(self.pseudo_root_pointers + INT_SIZE * i)
+        return ll
+
+    def get_contained_pointers(self, addr, typeid):
+        TYPE = self.types[typeid]
+        if isinstance(TYPE, lltype.Struct):
+            offsets = self.get_contained_pointers_struct(addr, TYPE)
+        elif isinstance(TYPE, lltype.Array):
+            offsets = self.get_contained_pointers_array(addr, TYPE)
+        ll = AddressLinkedList()
+        for offset in offsets:
+            ll.append(addr + offset)
+        print "for the TYPE %s if found the follwing offsets: %s" % (TYPE, offsets)
+        return ll
+
+    def get_contained_pointers_struct(self, addr, TYPE, offset=0):
+        offsets = []
+        substructures = [(TYPE, offset)]
+        while len(substructures):
+            TYPE, offset = substructures.pop()
+            layout = lltypesimulation.get_layout(TYPE)
+            for name in TYPE._names:
+                FIELD = getattr(TYPE, name)
+                if isinstance(FIELD, lltype.Ptr) and FIELD._needsgc():
+                    offsets.append(offset + layout[name])
+                elif isinstance(FIELD, lltype.Struct):
+                    substructures.append((FIELD, layout[name] + offset))
+                elif isinstance(FIELD, lltype.Array):
+                    assert offset == 0 #can only inline into outermost struct
+                    baseaddr = addr + layout[name]
+                    offsets += self.get_contained_pointers_array(
+                        baseaddr, FIELD, layout[name])
+        return offsets
+
+    def get_contained_pointers_array(self, addr, TYPE, offset=0):
+        offsets = []
+        length = addr.signed[0]
+        itemsize = lltypesimulation.get_variable_size(TYPE)
+        if isinstance(TYPE.OF, lltype.Ptr) and TYPE.OF._needsgc():
+            for i in range(length):
+                offsets.append(offset + INT_SIZE + i * itemsize)
+        elif isinstance(TYPE.OF, lltype.GcStruct):
+            for i in range(length):
+                item_offset = INT_SIZE + i * itemsize
+                offsets += self.get_contained_pointers_array(
+                    TYPE.OF, addr + item_offset, offset + item_offset)
+        return offsets
+
+class GcWrapper(object):
+    def __init__(self, llinterp, gc):
+        self.llinterp = llinterp
+        self.objectmodel = gc.objectmodel
+        assert isinstance(self.objectmodel, LLInterpObjectModel)
+        self.gc = gc
+
+    def malloc(self, TYPE, size=0):
+        typeid = self.objectmodel.get_typeid(TYPE)
+        address = self.gc.malloc(typeid,
+                                 lltypesimulation.get_total_size(TYPE, size))
+        result = lltypesimulation.simulatorptr(lltype.Ptr(TYPE), address)
+        result._zero_initialize(size)
+        result._init_size(size)
+        self.objectmodel.update_changed_addresses()
+        return result

Modified: pypy/dist/pypy/rpython/memory/test/test_llinterpsim.py
==============================================================================
--- pypy/dist/pypy/rpython/memory/test/test_llinterpsim.py	(original)
+++ pypy/dist/pypy/rpython/memory/test/test_llinterpsim.py	Thu Aug 11 22:30:19 2005
@@ -386,22 +386,19 @@
     assert ''.join(res.chars) == '-123'
 
 
-#__________________________________________________________________
-# interactive playing
-
-if __name__ == '__main__':
-    try:
-        import rlcompleter2 as _rl2
-        _rl2.setup()
-    except ImportError:
-        pass
-
-    t, typer = gengraph(number_ops, [int])
-    interp = LLInterpreter(t.flowgraphs, typer)
-    res = interp.eval_function(number_ops, [3])
-    assert res == number_ops(3)
-    for name, value in globals().items():
-        if name not in _snap and name[0] != '_':
-            print "%20s: %s" %(name, value)
-
-
+def test_mark_sweep_gc():
+    from pypy.rpython.memory.lladdress import simulator
+    gclltype.create_gc = gclltype.create_mark_sweep_gc
+    curr = simulator.current_size
+    def malloc_a_lot():
+        i = 0
+        while i < 10:
+            i += 1
+            a = [1] * 10
+            j = 0
+            while j < 20:
+                j += 1
+                a.append(j)
+    res = interpret(malloc_a_lot, [])
+    assert simulator.current_size - curr < 16000
+    print "size before: %s, size after %s" % (curr, simulator.current_size)



More information about the Pypy-commit mailing list