[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