[pypy-svn] r77093 - pypy/branch/gen2-gc/pypy/rpython/memory/gc

arigo at codespeak.net arigo at codespeak.net
Wed Sep 15 17:07:43 CEST 2010


Author: arigo
Date: Wed Sep 15 17:07:42 2010
New Revision: 77093

Modified:
   pypy/branch/gen2-gc/pypy/rpython/memory/gc/minimark.py
Log:
id().


Modified: pypy/branch/gen2-gc/pypy/rpython/memory/gc/minimark.py
==============================================================================
--- pypy/branch/gen2-gc/pypy/rpython/memory/gc/minimark.py	(original)
+++ pypy/branch/gen2-gc/pypy/rpython/memory/gc/minimark.py	Wed Sep 15 17:07:42 2010
@@ -106,12 +106,16 @@
 
     def setup(self):
         """Called at run-time to initialize the GC."""
+        MovingGCBase.setup(self)
         #
         assert self.nursery_size > 0, "XXX"
         #
         # A list of all raw_malloced objects (the objects too large)
         self.rawmalloced_objects = self.AddressStack()
         #
+        # Support for id()
+        self.young_objects_with_id = self.AddressDict()
+        #
         # the start of the nursery: we actually allocate a tiny bit more for
         # the nursery than really needed, to simplify pointer arithmetic
         # in malloc_fixedsize_clear().
@@ -256,6 +260,9 @@
         flags |= GCFLAG_NO_HEAP_PTRS | GCFLAG_NO_YOUNG_PTRS
         self.init_gc_object(addr, typeid16, flags)
 
+    def _can_never_move(self, obj):
+        return False      # approximate good enough answer for id()
+
     def is_in_nursery(self, addr):
         ll_assert(llmemory.cast_adr_to_int(addr) & 1 == 0,
                   "odd-valued (i.e. tagged) pointer unexpected here")
@@ -264,6 +271,10 @@
     def is_forwarded_marker(self, tid):
         return isinstance(tid, int) and tid == FORWARDED_MARKER
 
+    def get_forwarding_address(self, obj):
+        obj = llarena.getfakearenaaddress(obj)
+        return obj.address[0]
+
     def debug_check_object(self, obj):
         # after a minor or major collection, no object should be in the nursery
         ll_assert(not self.is_in_nursery(obj),
@@ -354,6 +365,11 @@
         # We proceed until 'old_objects_pointing_to_young' is empty.
         self.collect_oldrefs_to_nursery()
         #
+        # Update the id tracking of any object that was moved out of
+        # the nursery.
+        if self.young_objects_with_id.length() > 0:
+            self.update_young_objects_with_id()
+        #
         # Now all live nursery objects should be out, and the rest dies.
         # Fill the whole nursery with zero and reset the current nursery
         # pointer.
@@ -407,8 +423,7 @@
         #
         # If 'obj' was already forwarded, change it to its forwarding address.
         if self.is_forwarded_marker(self.header(obj).tid):
-            obj = llarena.getfakearenaaddress(obj)
-            root.address[0] = obj.address[0]
+            root.address[0] = self.get_forwarding_address(obj)
             #print '(already forwarded)'
             return
         #
@@ -465,6 +480,10 @@
         self.collect_roots()
         self.visit_all_objects()
         #
+        # Walk the 'objects_with_id' list and remove the ones that die,
+        # i.e. that don't have the GCFLAG_VISITED flag.
+        self.update_objects_with_id()
+        #
         # Walk all rawmalloced objects and free the ones that don't
         # have the GCFLAG_VISITED flag.
         self.free_unvisited_rawmalloc_objects()
@@ -556,6 +575,61 @@
         self.trace(obj, self._collect_ref, None)
 
 
+    # ----------
+    # id() support
+
+    def id(self, ptr):
+        """Implement id() of an object, given as a GCREF."""
+        obj = llmemory.cast_ptr_to_adr(ptr)
+        #
+        # Is it a tagged pointer?  For them, the result is odd-valued.
+        if not self.is_valid_gc_object(obj):
+            return llmemory.cast_adr_to_int(obj)
+        #
+        # Is the object still in the nursery?
+        if self.is_in_nursery(obj):
+            result = self.young_objects_with_id.get(obj)
+            if not result:
+                result = self._next_id()
+                self.young_objects_with_id.setitem(obj, result)
+        else:
+            result = self.objects_with_id.get(obj)
+            if not result:
+                # An 'obj' not in the nursery and not in 'objects_with_id'
+                # did not have its id() asked for and will not move any more,
+                # so we can just return its address as the result.
+                return llmemory.cast_adr_to_int(obj)
+        #
+        # If we reach here, 'result' is an odd number.  If we double it,
+        # we have a number of the form 4n+2, which cannot collide with
+        # tagged pointers nor with any real address.
+        return llmemory.cast_adr_to_int(result) * 2
+
+
+    def update_young_objects_with_id(self):
+        # Called during a minor collection.
+        self.young_objects_with_id.foreach(self._update_object_id,
+                                           self.objects_with_id)
+        self.young_objects_with_id.clear()
+        # NB. the clear() also makes the dictionary shrink back to its
+        # minimal size, which is actually a good idea: a large, mostly-empty
+        # table is bad for the next call to 'foreach'.
+
+    def _update_object_id(self, obj, id, new_objects_with_id):
+        if self.is_forwarded_marker(self.header(obj).tid):
+            newobj = self.get_forwarding_address(obj)
+            new_objects_with_id.setitem(newobj, id)
+        else:
+            self.id_free_list.append(id)
+
+    def _update_object_id_FAST(self, obj, id, new_objects_with_id):
+        # overrides the parent's version (a bit hackish)
+        if self.header(obj).tid & GCFLAG_VISITED:
+            new_objects_with_id.insertclean(obj, id)
+        else:
+            self.id_free_list.append(id)
+
+
 # ____________________________________________________________
 
 # For testing, a simple implementation of ArenaCollection.



More information about the Pypy-commit mailing list