Commits

andrewchambers committed 74b0728

added some failing tests

  • Participants
  • Parent commits 251da71
  • Branches incremental-gc

Comments (0)

Files changed (2)

File rpython/memory/gc/incminimark.py

 # 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
 
 
 
 
-TID_MASK            = (first_gcflag << 9) - 1
+TID_MASK            = (first_gcflag << 11) - 1
 
 
 FORWARDSTUB = lltype.GcStruct('forwarding_stub',
                 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:
             #
         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
 
     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:

File rpython/memory/gc/test/test_direct.py

         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