[pypy-commit] pypy incremental-gc: added some failing tests
andrewchambers
noreply at buildbot.pypy.org
Thu Aug 22 03:35:53 CEST 2013
Author: Andrew Chambers <andrewchamberss at gmail.com>
Branch: incremental-gc
Changeset: r66284:74b07286c87d
Date: 2013-08-22 13:35 +1200
http://bitbucket.org/pypy/pypy/changeset/74b07286c87d/
Log: added some failing tests
diff --git a/rpython/memory/gc/incminimark.py b/rpython/memory/gc/incminimark.py
--- a/rpython/memory/gc/incminimark.py
+++ b/rpython/memory/gc/incminimark.py
@@ -130,13 +130,24 @@
# by the incremental collection
GCFLAG_GRAY = first_gcflag << 8
-# The following flag is just an alias for the gray flag. It
-# is only used by major collections, it is set on objects
-# which are allocated during the sweeping and finalization states
-# it has different meaning outside of the sweeping state.
-# This flag should not be reset by any minor collection operation
-GCFLAG_NOSWEEP = first_gcflag << 8
+# This flag allows sweeping to be incrementalised.
+# it is set when an object would be swept, but isnt
+# because this flag was not set. The point of this
+# flag is to make sure an object has survived through
+# at least one major collection so we are sure
+# it is unreachable. It is needed because a write
+# barrier has no way of knowing which objects are truly
+# unvisited, or they were simply already reset by
+# a sweep.
+GCFLAG_CANSWEEP = first_gcflag << 9
+# Flag indicates object is old. It is needed by the
+# write barrier code so that we can track when a young
+# reference is written into a black object.
+# we must make a shadow and prevent such an object from being freed by
+# the next minor collection so that we dont get dead objects in
+# objects_to_trace during marking.
+GCFLAG_OLD = first_gcflag << 10
# States for the incremental GC
@@ -155,7 +166,7 @@
-TID_MASK = (first_gcflag << 9) - 1
+TID_MASK = (first_gcflag << 11) - 1
FORWARDSTUB = lltype.GcStruct('forwarding_stub',
@@ -1636,6 +1647,11 @@
self._visit_young_rawmalloced_object(obj)
return
#
+
+ # Do this after check we are old to avoid cache misses like
+ # In the comment above.
+ self.header(obj).tid |= GCFLAG_OLD
+
size_gc_header = self.gcheaderbuilder.size_gc_header
if self.header(obj).tid & GCFLAG_HAS_SHADOW == 0:
#
@@ -1708,7 +1724,7 @@
hdr = self.header(obj)
if hdr.tid & GCFLAG_VISITED:
return
- hdr.tid |= GCFLAG_VISITED
+ hdr.tid |= (GCFLAG_VISITED|GCFLAG_OLD)
#
# we just made 'obj' old, so we need to add it to the correct lists
added_somewhere = False
@@ -1931,6 +1947,7 @@
def free_rawmalloced_object_if_unvisited(self, obj):
if self.header(obj).tid & GCFLAG_VISITED:
+ self.header(obj).tid |= GCFLAG_OLD
self.header(obj).tid &= ~(GCFLAG_VISITED|GCFLAG_GRAY) # survives
self.old_rawmalloced_objects.append(obj)
else:
diff --git a/rpython/memory/gc/test/test_direct.py b/rpython/memory/gc/test/test_direct.py
--- a/rpython/memory/gc/test/test_direct.py
+++ b/rpython/memory/gc/test/test_direct.py
@@ -640,24 +640,149 @@
newobj1 = self.malloc(S)
newobj2 = self.malloc(S)
newobj1.x = 1337
- #newobj2.x = 1338
+ newobj2.x = 1338
self.write(oldobj,'next',newobj1)
self.gc.debug_gc_step_until(incminimark.STATE_SCANNING)
#should not be cleared even though it was allocated while sweeping
assert newobj1.x == 1337
- #assert newobj2.x == 1338
+ # XXX find appropriate exception type
+ assert py.test.raises(RuntimeError,"newobj2.x")
- def test_new_marking_write_sweeping(self):
-
- assert False
+ #def test_new_marking_write_sweeping(self):
+ #
+ # assert False
- def test_finalizing_new_object(self):
+ #def test_finalizing_new_object(self):
# Must test an object with a finalizer
# being added just before finalizers start being called
# must test this new objects finalizer is not called
# XXX maybe cant do this in test_direct and need test_transformed
- assert False
+ # assert False
+ def test_young_gray_collected(self):
+ from rpython.memory.gc import incminimark
+
+ # Test the write barrier triggers on a young object
+ # but doesnt crash when that object is collected
+
+ for i in range(2):
+ curobj = self.malloc(S)
+ curobj.x = i
+ self.stackroots.append(curobj)
+
+
+ self.gc.debug_gc_step_until(incminimark.STATE_MARKING)
+
+ #process one object
+ self.gc.debug_gc_step()
+
+ oldobj = self.stackroots[-1]
+
+ newobj = self.malloc(S)
+ newobj.x = 5
+ # make newobj gray
+ self.write(oldobj,'next',newobj)
+ #the barrier should have made the object gray
+ newhdr = self.gc.header(llmemory.cast_ptr_to_adr(newobj))
+ assert newhdr.tid & incminimark.GCFLAG_GRAY
+
+ # make newobj unreachable again
+ self.write(oldobj,'next',oldobj)
+
+ #complete collection
+ self.gc.debug_gc_step_until(incminimark.STATE_SCANNING)
+ self.gc.debug_check_consistency()
+
+ # object cant be collected in this case, must be made old.
+ assert newobj.x == 5
+
+ self.gc.debug_gc_step_until(incminimark.STATE_SCANNING)
+
+ # now object is collected
+ assert py.test.raises(RuntimeError,"newobj.x")
+
+ # Test trying to be a bit comprehensive about
+ # states and types of objects
+ def test_allocate_states(self):
+ from rpython.memory.gc import incminimark
+ largeobj_size = self.gc.nonlarge_max + 1
+
+ assert self.gc.gc_state == incminimark.STATE_SCANNING
+ assert self.gc.get_total_memory_used() == 0
+
+ for i in range(5):
+ curobj = self.malloc(S)
+ curobj.x = i
+ self.stackroots.append(curobj)
+ assert self.gc.is_in_nursery(llmemory.cast_ptr_to_adr(curobj))
+
+ reachableroot = curobj
+
+ for i in range(5):
+ curobj = self.malloc(VAR, largeobj_size)
+ self.stackroots.append(curobj)
+ assert not self.gc.is_in_nursery(llmemory.cast_ptr_to_adr(curobj))
+
+ assert self.gc.gc_state == incminimark.STATE_SCANNING
+
+
+ nallocated = {}
+
+ reachable = []
+ unreachable = []
+
+ while True:
+
+ if self.gc.gc_state not in nallocated:
+ nallocated[self.gc.gc_state] = 0
+
+ if nallocated[self.gc.gc_state] < 1:
+ unreachableobj = self.malloc(S)
+ reachableobj = self.malloc(S)
+ assert self.gc.is_in_nursery(llmemory.cast_ptr_to_adr(reachableobj))
+ reachableviayoungobj = self.malloc(S)
+ self.write(reachableobj,'next',reachableviayoungobj)
+ unreachableobj.x = 150
+ reachableobj.x = 150
+ reachableviayoungobj.x = 150
+
+ self.write(reachableroot,'next',reachableobj)
+ reachableroot = reachableobj
+
+ unreachable.append(unreachableobj)
+ reachable.append(reachableobj)
+ reachable.append(reachableviayoungobj)
+
+ nallocated[self.gc.gc_state] += 1
+
+ if self.gc.gc_state == incminimark.STATE_SCANNING:
+ pass
+ elif self.gc.gc_state == incminimark.STATE_MARKING:
+ pass
+ elif self.gc.gc_state == incminimark.STATE_SWEEPING_RAWMALLOC:
+ pass
+ elif self.gc.gc_state == incminimark.STATE_SWEEPING_ARENA:
+ pass
+ elif self.gc.gc_state == incminimark.STATE_FINALIZING:
+ # ASSUMPTION finalizing is atomic
+ #
+ #complete collection
+ self.gc.debug_gc_step()
+ assert self.gc.gc_state == incminimark.STATE_SCANNING
+ break
+ else:
+ raise Exception("unreachable")
+
+ self.gc.debug_gc_step()
+
+ #complete the next collection cycle
+ self.gc.debug_gc_step_until(incminimark.STATE_SCANNING)
+
+ for obj in reachable:
+ assert obj.x == 150
+
+ for obj in unreachable:
+ assert py.test.raises(RuntimeError,"obj.x")
class TestIncrementalMiniMarkGCFull(TestMiniMarkGCFull):
from rpython.memory.gc.incminimark import IncrementalMiniMarkGC as GCClass
More information about the pypy-commit
mailing list