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

cfbolz at codespeak.net cfbolz at codespeak.net
Thu Aug 11 20:36:15 CEST 2005


Author: cfbolz
Date: Thu Aug 11 20:36:14 2005
New Revision: 15975

Modified:
   pypy/dist/pypy/rpython/memory/gc.py
   pypy/dist/pypy/rpython/memory/test/test_gc.py
Log:
implemented a very naive, inefficient Mark and Sweep GC.


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 20:36:14 2005
@@ -1,5 +1,9 @@
+from pypy.rpython.memory.lladdress import raw_malloc, raw_free, NULL
+from pypy.rpython.memory.support import AddressLinkedList
 import struct
 
+INT_SIZE = struct.calcsize("i")
+
 class GCError(Exception):
     pass
 
@@ -15,3 +19,66 @@
     obj.__dict__ = {}
     obj.__class__ = FREED_OBJECT
 
+
+class MarkSweepGC(object):
+    _raw_allocate_ = True
+    def __init__(self, objectmodel, collect_every_bytes):
+        self.bytes_malloced = 0
+        self.collect_every_bytes = collect_every_bytes
+        #need to maintain a list of malloced objects, since we used the systems
+        #allocator and can't walk the heap
+        self.malloced_objects = AddressLinkedList()
+        self.objectmodel = objectmodel
+
+    def malloc(self, typeid, size):
+        if self.bytes_malloced > self.collect_every_bytes:
+            self.collect()
+        result = raw_malloc(size + 2 * INT_SIZE)
+        print "mallocing %s, size %s at %s" % (typeid, size, result)
+        print "real size: %s" % (size + 2 * INT_SIZE, )
+        result.signed[0] = 0
+        result.signed[1] = typeid
+        self.malloced_objects.append(result)
+        self.bytes_malloced += size + 2 * INT_SIZE
+        return result + 2 * INT_SIZE
+
+    def collect(self):
+        print "collecting"
+        self.bytes_malloced = 0
+        roots = self.objectmodel.get_roots()
+        objects = AddressLinkedList()
+        while 1:
+            curr = roots.pop()
+            print "root: ", curr
+            if curr == NULL:
+                break
+            # roots is a list of addresses to addresses:
+            objects.append(curr.address[0])
+        while 1:  #mark
+            curr = objects.pop()
+            print "root: ", curr
+            if curr == NULL:
+                break
+            gc_info = curr - 2 * INT_SIZE
+            if gc_info.signed[0] == 1:
+                continue
+            pointers = self.objectmodel.get_contained_pointers(
+                curr, gc_info.signed[1])
+            while 1:
+                pointer = pointers.pop()
+                if pointer == NULL:
+                    break
+                objects.append(pointer)
+            gc_info.signed[0] = 1
+        newmo = AddressLinkedList()
+        while 1:  #sweep
+            curr = self.malloced_objects.pop()
+            if curr == NULL:
+                break
+            if curr.signed[0] == 1:
+                curr.signed[0] = 0
+                newmo.append(curr)
+            else:
+                raw_free(curr)
+        free_non_gc_object(self.malloced_objects)
+        self.malloced_objects = newmo

Modified: pypy/dist/pypy/rpython/memory/test/test_gc.py
==============================================================================
--- pypy/dist/pypy/rpython/memory/test/test_gc.py	(original)
+++ pypy/dist/pypy/rpython/memory/test/test_gc.py	Thu Aug 11 20:36:14 2005
@@ -1,6 +1,10 @@
 import py
 
-from pypy.rpython.memory.gc import free_non_gc_object, GCError
+from pypy.rpython.memory.gc import free_non_gc_object, GCError, MarkSweepGC
+from pypy.rpython.memory.support import AddressLinkedList, INT_SIZE
+from pypy.rpython.memory.lladdress import raw_malloc, raw_free, NULL
+from pypy.rpython.memory.simulator import MemorySimulatorError
+
 
 def test_free_non_gc_object():
     class TestClass(object):
@@ -21,3 +25,68 @@
     py.test.raises(GCError, "t.method2()") 
     py.test.raises(GCError, "t.a")
     py.test.raises(AssertionError, "free_non_gc_object(TestClass2())")
+
+
+class PseudoObjectModel(object):
+    """Object model for testing purposes: you can specify roots and a
+    layout_mapping which is a dictionary of typeids to a list of offsets of
+    pointers in an object"""
+    def __init__(self, roots, layout_mapping):
+        self.roots = roots
+        self.layout_mapping = layout_mapping
+
+    def get_roots(self):
+        self.roots
+        ll = AddressLinkedList()
+        for root in self.roots:
+            ll.append(root)
+        return ll
+
+    def get_contained_pointers(self, addr, typeid):
+        if addr is NULL:
+            return AddressLinkedList()
+        layout = self.layout_mapping[typeid]
+        result = AddressLinkedList()
+        for offset in layout:
+            result.append(addr + offset)
+        return result
+
+class TestMarkSweepGC(object):
+    def test_simple(self):
+        variables = raw_malloc(4 * INT_SIZE)
+        roots = [variables + i * INT_SIZE for i in range(4)]
+        layout0 = [] #int
+        layout1 = [0, INT_SIZE] #(ptr, ptr)
+        om = PseudoObjectModel(roots, {0: layout0, 1: layout1})
+        gc = MarkSweepGC(om, 2 ** 16)
+        variables.address[0] = gc.malloc(0, INT_SIZE)
+        variables.address[1] = gc.malloc(0, INT_SIZE)
+        variables.address[2] = gc.malloc(0, INT_SIZE)
+        variables.address[3] = gc.malloc(0, INT_SIZE)
+        print "roots", roots
+        gc.collect() #does not crash
+        addr = gc.malloc(0, INT_SIZE)
+        addr.signed[0] = 1
+        print "roots", roots
+        gc.collect()
+        py.test.raises(MemorySimulatorError, "addr.signed[0]")
+        variables.address[0] = gc.malloc(1, 2 * INT_SIZE)
+        variables.address[0].address[0] = variables.address[1]
+        variables.address[0].address[1] = NULL
+        print "roots", roots
+        gc.collect() #does not crash
+        addr0 = gc.malloc(1, 2 * INT_SIZE)
+        addr0.address[1] = NULL
+        addr1 = gc.malloc(1, 2 * INT_SIZE)
+        addr1.address[0] = addr1.address[1] = NULL
+        addr0.address[0] = addr1
+        addr2 = variables.address[1]
+        print "addr0, addr1, addr2 =", addr0, addr1, addr2
+        variables.address[1] == NULL
+        variables.address[0].address[0] = NULL
+        print "roots", roots
+        gc.collect()
+        py.test.raises(MemorySimulatorError, "addr0.signed[0]")
+        py.test.raises(MemorySimulatorError, "addr1.signed[0]")
+        py.test.raises(MemorySimulatorError, "addr2.signed[0]")
+



More information about the Pypy-commit mailing list