[pypy-svn] r47644 - pypy/dist/pypy/rpython/memory/gc

arigo at codespeak.net arigo at codespeak.net
Sat Oct 20 16:14:22 CEST 2007


Author: arigo
Date: Sat Oct 20 16:14:22 2007
New Revision: 47644

Modified:
   pypy/dist/pypy/rpython/memory/gc/generation.py
   pypy/dist/pypy/rpython/memory/gc/semispace.py
Log:
Unify the two lists of objects that contain pointers to young objects.
Change the GCFLAG to allow for a version of the write_barrier() whose
fast path is (probably) faster.  The GCFLAG_NO_YOUNG_PTRS is chosen in
preference to a GCFLAG_YOUNG_PTRS, so that young objects start with the
flag cleared - i.e. we avoid an instruction to set the flag in malloc.
Warning, the correct handling of this flag is slightly delicate.  See
documented invariants.


Modified: pypy/dist/pypy/rpython/memory/gc/generation.py
==============================================================================
--- pypy/dist/pypy/rpython/memory/gc/generation.py	(original)
+++ pypy/dist/pypy/rpython/memory/gc/generation.py	Sat Oct 20 16:14:22 2007
@@ -5,10 +5,12 @@
 from pypy.rpython.lltypesystem import lltype, llmemory, llarena
 from pypy.rlib.objectmodel import free_non_gc_object, debug_assert
 
-nonnull_endmarker = llmemory.raw_malloc(llmemory.sizeof(lltype.Char))
-llmemory.raw_memclear(nonnull_endmarker, llmemory.sizeof(lltype.Char))
+# The following flag is never set on young objects, i.e. the ones living
+# in the nursery.  It is initially set on all prebuilt and old objects,
+# and gets cleared by the write_barrier() when we write in them a
+# pointer to a young object.
+GCFLAG_NO_YOUNG_PTRS = 2 << GCFLAGSHIFT
 
-GCFLAG_REMEMBERED = 2 << GCFLAGSHIFT
 
 class GenerationGC(SemiSpaceGC):
     """A basic generational GC: it's a SemiSpaceGC with an additional
@@ -18,6 +20,7 @@
     """
     inline_simple_malloc = True
     needs_write_barrier = True
+    default_gcflags = GCFLAG_NO_YOUNG_PTRS       # for old and static objects
 
     def __init__(self, AddressLinkedList,
                  nursery_size=128,
@@ -34,15 +37,20 @@
     def setup(self):
         SemiSpaceGC.setup(self)
         self.reset_nursery()
-        self.old_objects_pointing_to_young = nonnull_endmarker
-        # ^^^ the head of a linked list inside the old objects space
+        self.old_objects_pointing_to_young = NULL
+        # ^^^ the head of a linked list inside the old objects space; it
+        # may contain static prebuilt objects as well.  More precisely,
+        # it lists exactly the old and static objects whose
+        # GCFLAG_NO_YOUNG_PTRS bit is not set.  The 'forw' header field
+        # of such objects is abused for this linked list; it needs to be
+        # reset to its correct value when GCFLAG_NO_YOUNG_PTRS is set
+        # again at the start of a collection.
         self.young_objects_with_weakrefs = self.AddressLinkedList()
-        self.static_to_young_pointer = self.AddressLinkedList()
 
     def reset_nursery(self):
-        self.nursery      = llmemory.NULL
-        self.nursery_top  = llmemory.NULL
-        self.nursery_free = llmemory.NULL
+        self.nursery      = NULL
+        self.nursery_top  = NULL
+        self.nursery_free = NULL
 
     def is_in_nursery(self, addr):
         return self.nursery <= addr < self.nursery_top
@@ -62,7 +70,7 @@
         if raw_malloc_usage(totalsize) > self.nursery_top - result:
             result = self.collect_nursery()
         llarena.arena_reserve(result, totalsize)
-        self.init_gc_object(result, typeid)
+        self.init_young_gc_object(result, typeid)
         self.nursery_free = result + totalsize
         if contains_weakptr:
             self.young_objects_with_weakrefs.append(result + size_gc_header)
@@ -86,31 +94,31 @@
         if raw_malloc_usage(totalsize) > self.nursery_top - result:
             result = self.collect_nursery()
         llarena.arena_reserve(result, totalsize)
-        self.init_gc_object(result, typeid)
+        self.init_young_gc_object(result, typeid)
         (result + size_gc_header + offset_to_length).signed[0] = length
         self.nursery_free = result + llarena.round_up_for_allocation(totalsize)
         return llmemory.cast_adr_to_ptr(result+size_gc_header, llmemory.GCREF)
 
+    def init_young_gc_object(self, addr, typeid):
+        hdr = llmemory.cast_adr_to_ptr(addr, lltype.Ptr(self.HDR))
+        #hdr.forw = NULL   -- unneeded, the space is initially filled with zero
+        hdr.tid = typeid     # GCFLAG_NO_YOUNG_PTRS is never set on young objs
+
     def semispace_collect(self, size_changing=False):
-        self.reset_forwarding() # we are doing a full collection anyway
-        self.reset_static()
+        self.reset_young_gcflags() # we are doing a full collection anyway
         self.weakrefs_grow_older()
         self.reset_nursery()
         SemiSpaceGC.semispace_collect(self, size_changing)
 
-    def reset_forwarding(self):
+    def reset_young_gcflags(self):
         obj = self.old_objects_pointing_to_young
-        while obj != nonnull_endmarker:
-            hdr = self.header(obj)
-            obj = hdr.forw
-            hdr.forw = llmemory.NULL
-        self.old_objects_pointing_to_young = nonnull_endmarker
-
-    def reset_static(self):
-        while self.static_to_young_pointer.non_empty():
-            obj = self.static_to_young_pointer.pop()
+        while obj:
             hdr = self.header(obj)
-            hdr.tid &= ~GCFLAG_REMEMBERED
+            hdr.tid |= GCFLAG_NO_YOUNG_PTRS
+            nextobj = hdr.forw
+            self.init_forwarding(obj)
+            obj = nextobj
+        self.old_objects_pointing_to_young = NULL
 
     def weakrefs_grow_older(self):
         while self.young_objects_with_weakrefs.non_empty():
@@ -127,9 +135,10 @@
             # a nursery-only collection
             scan = self.free
             self.collect_oldrefs_to_nursery()
-            self.collect_static_to_nursery()
             self.collect_roots_in_nursery()
             self.scan_objects_just_copied_out_of_nursery(scan)
+            # at this point, all static and old objects have got their
+            # GCFLAG_NO_YOUNG_PTRS set again by trace_and_drag_out_of_nursery
             if self.young_objects_with_weakrefs.non_empty():
                 self.invalidate_young_weakrefs()
             self.notify_objects_just_moved()
@@ -151,21 +160,14 @@
     def collect_oldrefs_to_nursery(self):
         # Follow the old_objects_pointing_to_young list and move the
         # young objects they point to out of the nursery.  The 'forw'
-        # fields are reset to NULL along the way.
+        # fields are reset to their correct value along the way.
         obj = self.old_objects_pointing_to_young
-        while obj != nonnull_endmarker:
-            self.trace_and_drag_out_of_nursery(obj)
-            hdr = self.header(obj)
-            obj = hdr.forw
-            hdr.forw = llmemory.NULL
-        self.old_objects_pointing_to_young = nonnull_endmarker
-
-    def collect_static_to_nursery(self):
-        while self.static_to_young_pointer.non_empty():
-            obj = self.static_to_young_pointer.pop()
-            hdr = self.header(obj)
-            hdr.tid &= ~GCFLAG_REMEMBERED
+        while obj:
+            nextobj = self.header(obj).forw
+            self.init_forwarding(obj)
             self.trace_and_drag_out_of_nursery(obj)
+            obj = nextobj
+        self.old_objects_pointing_to_young = NULL
 
     def collect_roots_in_nursery(self):
         roots = self.get_roots(with_static=False)
@@ -189,6 +191,7 @@
         """obj must not be in the nursery.  This copies all the
         young objects it references out of the nursery.
         """
+        self.header(obj).tid |= GCFLAG_NO_YOUNG_PTRS
         typeid = self.get_type_id(obj)
         offsets = self.offsets_to_gc_pointers(typeid)
         i = 0
@@ -234,18 +237,16 @@
                     (obj + offset).address[0] = NULL
 
     def write_barrier(self, addr, addr_to, addr_struct):
-        if not self.is_in_nursery(addr_struct) and self.is_in_nursery(addr):
+        if self.header(addr_struct).tid & GCFLAG_NO_YOUNG_PTRS:
             self.remember_young_pointer(addr_struct, addr)
         addr_to.address[0] = addr
 
     def remember_young_pointer(self, addr_struct, addr):
-        oldhdr = self.header(addr_struct)
-        if oldhdr.forw == NULL:
+        debug_assert(not self.is_in_nursery(addr_struct),
+                     "nursery object with GCFLAG_NO_YOUNG_PTRS")
+        if self.is_in_nursery(addr):
+            oldhdr = self.header(addr_struct)
             oldhdr.forw = self.old_objects_pointing_to_young
             self.old_objects_pointing_to_young = addr_struct
-        elif (oldhdr.tid & (GCFLAG_IMMORTAL | GCFLAG_REMEMBERED) ==
-                 GCFLAG_IMMORTAL):
-            self.static_to_young_pointer.append(addr_struct)
-            oldhdr.tid |= GCFLAG_REMEMBERED
+            oldhdr.tid &= ~GCFLAG_NO_YOUNG_PTRS
     remember_young_pointer.dont_inline = True
-

Modified: pypy/dist/pypy/rpython/memory/gc/semispace.py
==============================================================================
--- pypy/dist/pypy/rpython/memory/gc/semispace.py	(original)
+++ pypy/dist/pypy/rpython/memory/gc/semispace.py	Sat Oct 20 16:14:22 2007
@@ -20,6 +20,7 @@
 class SemiSpaceGC(MovingGCBase):
     _alloc_flavor_ = "raw"
     inline_simple_malloc = True
+    default_gcflags = 0
 
     HDR = lltype.Struct('header', ('forw', llmemory.Address),
                                   ('tid', lltype.Signed))
@@ -285,13 +286,21 @@
     def init_gc_object(self, addr, typeid):
         hdr = llmemory.cast_adr_to_ptr(addr, lltype.Ptr(self.HDR))
         #hdr.forw = NULL   -- unneeded, the space is initially filled with zero
-        hdr.tid = typeid
+        hdr.tid = typeid | self.default_gcflags
 
     def init_gc_object_immortal(self, addr, typeid):
         # immortal objects always have forward to themselves
         hdr = llmemory.cast_adr_to_ptr(addr, lltype.Ptr(self.HDR))
-        hdr.forw = addr + self.gcheaderbuilder.size_gc_header
-        hdr.tid = typeid | GCFLAG_IMMORTAL
+        hdr.tid = typeid | self.default_gcflags | GCFLAG_IMMORTAL
+        self.init_forwarding(addr + self.gcheaderbuilder.size_gc_header)
+
+    def init_forwarding(self, obj):
+        hdr = self.header(obj)
+        if hdr.tid & GCFLAG_IMMORTAL:
+            hdr.forw = obj      # prebuilt objects point to themselves,
+                                # so that a collection does not move them
+        else:
+            hdr.forw = NULL
 
     def deal_with_objects_with_finalizers(self):
         # walk over list of objects with finalizers



More information about the Pypy-commit mailing list