[pypy-svn] r53704 - in pypy/branch/hybrid-gc/pypy/rpython/memory: gc test

arigo at codespeak.net arigo at codespeak.net
Fri Apr 11 21:46:26 CEST 2008


Author: arigo
Date: Fri Apr 11 21:46:25 2008
New Revision: 53704

Modified:
   pypy/branch/hybrid-gc/pypy/rpython/memory/gc/hybrid.py
   pypy/branch/hybrid-gc/pypy/rpython/memory/test/test_gc.py
Log:
Test and fix.


Modified: pypy/branch/hybrid-gc/pypy/rpython/memory/gc/hybrid.py
==============================================================================
--- pypy/branch/hybrid-gc/pypy/rpython/memory/gc/hybrid.py	(original)
+++ pypy/branch/hybrid-gc/pypy/rpython/memory/gc/hybrid.py	Fri Apr 11 21:46:25 2008
@@ -6,7 +6,7 @@
 from pypy.rlib.debug import ll_assert
 from pypy.rlib.rarithmetic import ovfcheck
 
-GCFLAG_MARK = GenerationGC.first_unused_gcflag << 0
+GCFLAG_UNVISITED = GenerationGC.first_unused_gcflag << 0
 
 
 class HybridGC(GenerationGC):
@@ -29,6 +29,7 @@
         self.nonlarge_max = large_object - 1
         assert self.nonlarge_max <= self.lb_young_var_basesize
         self.large_objects_collect_trigger = self.space_size
+        self.pending_external_object_list = self.AddressDeque()
 
     def setup(self):
         self.large_objects_list = self.AddressDeque()
@@ -92,7 +93,7 @@
             raise MemoryError()
         if raw_malloc_usage(totalsize) > self.nonlarge_max:
             result = self.malloc_varsize_marknsweep(totalsize)
-            flags = self.GCFLAGS_FOR_NEW_EXTERNAL_OBJECTS
+            flags = self.GCFLAGS_FOR_NEW_EXTERNAL_OBJECTS | GCFLAG_UNVISITED
         else:
             result = self.malloc_varsize_collecting_nursery(totalsize)
             flags = self.GCFLAGS_FOR_NEW_YOUNG_OBJECTS
@@ -129,32 +130,51 @@
         self.large_objects_list.append(result + size_gc_header)
         return result
 
+    # ___________________________________________________________________
     # the following methods are hook into SemiSpaceGC.semispace_collect()
 
     def starting_full_collect(self):
-        # This hook is not really necessary but it's a nice place
-        # to put the following comment:
-        # No object should have a GCFLAG_MARK at this point
-        # (except some prebuilt objects but they are ignored).
-        pass
+        # At the start of a collection, all raw_malloc'ed objects should
+        # have the GCFLAG_UNVISITED bit set.  No other object ever has
+        # this bit set.
+        ll_assert(not self.pending_external_object_list.non_empty(),
+                  "pending_external_object_list should be empty at start")
 
     def visit_external_object(self, obj):
-        # leave a GCFLAG_MARK on all external objects visited (some
-        # prebuilt objects will also get the flag, but it doesn't matter)
-        self.header(obj).tid |= GCFLAG_MARK
+        hdr = self.header(obj)
+        if hdr.tid & GCFLAG_UNVISITED:
+            # This is a not-visited-yet raw_malloced object.
+            hdr.tid -= GCFLAG_UNVISITED
+            self.pending_external_object_list.append(obj)
+
+    def scan_copied(self, scan):
+        # Alternate between scanning the regular objects we just moved
+        # and scanning the raw_malloc'ed object we just visited.
+        progress = True
+        while progress:
+            newscan = GenerationGC.scan_copied(self, scan)
+            progress = newscan != scan
+            scan = newscan
+            while self.pending_external_object_list.non_empty():
+                obj = self.pending_external_object_list.popleft()
+                self.trace_and_copy(obj)
+                progress = True
+        return scan
 
     def finished_full_collect(self):
+        ll_assert(not self.pending_external_object_list.non_empty(),
+                  "pending_external_object_list should be empty at end")
         # free all mark-n-sweep-managed objects that have not been marked
         large_objects = self.large_objects_list
         remaining_large_objects = self.AddressDeque()
         while large_objects.non_empty():
             obj = large_objects.popleft()
-            if self.header(obj).tid & GCFLAG_MARK:
-                self.header(obj).tid -= GCFLAG_MARK
-                remaining_large_objects.append(obj)
-            else:
+            if self.header(obj).tid & GCFLAG_UNVISITED:
                 addr = obj - self.gcheaderbuilder.size_gc_header
                 llmemory.raw_free(addr)
+            else:
+                self.header(obj).tid |= GCFLAG_UNVISITED
+                remaining_large_objects.append(obj)
         large_objects.delete()
         self.large_objects_list = remaining_large_objects
         # As we just collected, it's fine to raw_malloc'ate up to space_size

Modified: pypy/branch/hybrid-gc/pypy/rpython/memory/test/test_gc.py
==============================================================================
--- pypy/branch/hybrid-gc/pypy/rpython/memory/test/test_gc.py	(original)
+++ pypy/branch/hybrid-gc/pypy/rpython/memory/test/test_gc.py	Fri Apr 11 21:46:25 2008
@@ -417,3 +417,14 @@
 
 class TestHybridGC(TestGenerationalGC):
     from pypy.rpython.memory.gc.hybrid import HybridGC as GCClass
+
+    def test_ref_from_rawmalloced_to_regular(self):
+        import gc
+        def concat(j):
+            lst = []
+            for i in range(j):
+                lst.append(str(i))
+            gc.collect()
+            return len("".join(lst))
+        res = self.interpret(concat, [100])
+        assert res == concat(100)



More information about the Pypy-commit mailing list