[pypy-svn] r76902 - in pypy/branch/gc-module/pypy: annotation module/gc module/gc/test rlib rpython rpython/memory/gc rpython/memory/gctransform translator/c/test

arigo at codespeak.net arigo at codespeak.net
Mon Sep 6 19:06:54 CEST 2010


Author: arigo
Date: Mon Sep  6 19:06:52 2010
New Revision: 76902

Modified:
   pypy/branch/gc-module/pypy/annotation/binaryop.py
   pypy/branch/gc-module/pypy/module/gc/__init__.py
   pypy/branch/gc-module/pypy/module/gc/referents.py
   pypy/branch/gc-module/pypy/module/gc/test/test_referents.py
   pypy/branch/gc-module/pypy/rlib/rgc.py
   pypy/branch/gc-module/pypy/rpython/memory/gc/base.py
   pypy/branch/gc-module/pypy/rpython/memory/gctransform/framework.py
   pypy/branch/gc-module/pypy/rpython/rptr.py
   pypy/branch/gc-module/pypy/translator/c/test/test_newgc.py
Log:
Implement get_rpy_roots() and get_rpy_referents() in the GC.


Modified: pypy/branch/gc-module/pypy/annotation/binaryop.py
==============================================================================
--- pypy/branch/gc-module/pypy/annotation/binaryop.py	(original)
+++ pypy/branch/gc-module/pypy/annotation/binaryop.py	Mon Sep  6 19:06:52 2010
@@ -594,7 +594,9 @@
     getitem_idx_key = getitem_idx
 
     def setitem((lst1, int2), s_value):
-        getbookkeeper().count("list_setitem", int2)        
+        if lst1.listdef.listitem.s_value.contains(s_value):
+            return     # already up-to-date
+        getbookkeeper().count("list_setitem", int2)
         lst1.listdef.mutate()
         lst1.listdef.generalize(s_value)
     setitem.can_only_throw = [IndexError]

Modified: pypy/branch/gc-module/pypy/module/gc/__init__.py
==============================================================================
--- pypy/branch/gc-module/pypy/module/gc/__init__.py	(original)
+++ pypy/branch/gc-module/pypy/module/gc/__init__.py	Mon Sep  6 19:06:52 2010
@@ -18,6 +18,7 @@
         if (not space.config.translating or
             space.config.translation.gctransformer == "framework"):
             self.interpleveldefs.update({
+                'get_rpy_roots': 'referents.get_rpy_roots',
                 'get_rpy_referents': 'referents.get_rpy_referents',
                 'get_rpy_memory_usage': 'referents.get_rpy_memory_usage',
                 'get_objects': 'referents.get_objects',

Modified: pypy/branch/gc-module/pypy/module/gc/referents.py
==============================================================================
--- pypy/branch/gc-module/pypy/module/gc/referents.py	(original)
+++ pypy/branch/gc-module/pypy/module/gc/referents.py	Mon Sep  6 19:06:52 2010
@@ -32,6 +32,10 @@
         gcref = rgc.cast_instance_to_gcref(w_obj)
     return gcref
 
+def get_rpy_roots(space):
+    lst = rgc.get_rpy_roots()
+    return space.newlist([wrap(space, gcref) for gcref in lst if gcref])
+
 def get_rpy_referents(space, w_obj):
     """Return a list of all the referents, as reported by the GC.
     This is likely to contain a lot of GcRefs."""
@@ -74,11 +78,12 @@
     # be W_Roots
     pending_w = []   # <- list of W_Roots
     for gcref in roots:
-        w_obj = try_cast_gcref_to_w_root(gcref)
-        if w_obj is not None:
-            pending_w.append(w_obj)
-        else:
-            _list_w_obj_referents(gcref, pending_w)
+        if gcref:
+            w_obj = try_cast_gcref_to_w_root(gcref)
+            if w_obj is not None:
+                pending_w.append(w_obj)
+            else:
+                _list_w_obj_referents(gcref, pending_w)
     # continue by following every W_Root.  Note that this will force a hash
     # on every W_Root, which is kind of bad, but not on every RPython object,
     # which is really good.

Modified: pypy/branch/gc-module/pypy/module/gc/test/test_referents.py
==============================================================================
--- pypy/branch/gc-module/pypy/module/gc/test/test_referents.py	(original)
+++ pypy/branch/gc-module/pypy/module/gc/test/test_referents.py	Mon Sep  6 19:06:52 2010
@@ -6,9 +6,12 @@
         from pypy.rlib import rgc
         cls._backup = [rgc.get_rpy_roots]
         w = cls.space.wrap
-        cls.ALL_ROOTS = [w(4), w([2, 7])]
+        class RandomRPythonObject(object):
+            pass
+        cls.ALL_ROOTS = [w(4), w([2, 7]), RandomRPythonObject()]
         cls.w_ALL_ROOTS = cls.space.newlist(cls.ALL_ROOTS)
-        rgc.get_rpy_roots = lambda: map(rgc._GcRef, cls.ALL_ROOTS)
+        rgc.get_rpy_roots = lambda: (
+            map(rgc._GcRef, cls.ALL_ROOTS) + [rgc.NULL_GCREF]*17)
 
     def teardown_class(cls):
         from pypy.rlib import rgc
@@ -25,6 +28,14 @@
             if type(x) is gc.GcRef:
                 assert 0, "get_objects() returned a GcRef"
 
+    def test_get_rpy_roots(self):
+        import gc
+        lst = gc.get_rpy_roots()
+        assert lst[0] == 4
+        assert lst[1] == [2, 7]
+        assert type(lst[2]) is gc.GcRef
+        assert len(lst) == 3
+
     def test_get_rpy_referents(self):
         import gc
         y = 12345

Modified: pypy/branch/gc-module/pypy/rlib/rgc.py
==============================================================================
--- pypy/branch/gc-module/pypy/rlib/rgc.py	(original)
+++ pypy/branch/gc-module/pypy/rlib/rgc.py	Mon Sep  6 19:06:52 2010
@@ -311,6 +311,7 @@
 def get_rpy_roots():
     # Return the 'roots' from the GC.
     # This stub is not usable on top of CPython.
+    # The gc typically returns a list that ends with a few NULL_GCREFs.
     raise NotImplementedError
 
 def get_rpy_referents(gcref):
@@ -395,11 +396,17 @@
 
 # ------------------- implementation -------------------
 
+_cache_s_list_of_gcrefs = None
+
 def s_list_of_gcrefs():
-    from pypy.annotation import model as annmodel
-    from pypy.annotation.listdef import ListDef
-    s_gcref = annmodel.SomePtr(llmemory.GCREF)
-    return annmodel.SomeList(ListDef(None, s_gcref, resized=False))
+    global _cache_s_list_of_gcrefs
+    if _cache_s_list_of_gcrefs is None:
+        from pypy.annotation import model as annmodel
+        from pypy.annotation.listdef import ListDef
+        s_gcref = annmodel.SomePtr(llmemory.GCREF)
+        _cache_s_list_of_gcrefs = annmodel.SomeList(
+            ListDef(None, s_gcref, resized=False))
+    return _cache_s_list_of_gcrefs
 
 class Entry(ExtRegistryEntry):
     _about_ = get_rpy_roots
@@ -407,3 +414,14 @@
         return s_list_of_gcrefs()
     def specialize_call(self, hop):
         return hop.genop('gc_get_rpy_roots', [], resulttype = hop.r_result)
+
+class Entry(ExtRegistryEntry):
+    _about_ = get_rpy_referents
+    def compute_result_annotation(self, s_gcref):
+        from pypy.annotation import model as annmodel
+        assert annmodel.SomePtr(llmemory.GCREF).contains(s_gcref)
+        return s_list_of_gcrefs()
+    def specialize_call(self, hop):
+        vlist = hop.inputargs(hop.args_r[0])
+        return hop.genop('gc_get_rpy_referents', vlist,
+                         resulttype = hop.r_result)

Modified: pypy/branch/gc-module/pypy/rpython/memory/gc/base.py
==============================================================================
--- pypy/branch/gc-module/pypy/rpython/memory/gc/base.py	(original)
+++ pypy/branch/gc-module/pypy/rpython/memory/gc/base.py	Mon Sep  6 19:06:52 2010
@@ -255,6 +255,84 @@
         finally:
             self.finalizer_lock_count -= 1
 
+    # ---------- implementation of pypy.rlib.rgc.get_rpy_roots() ----------
+
+    def _counting_rpy_root(self, root):
+        self._count_rpy += 1
+
+    def _do_count_rpy_roots(self):
+        self._count_rpy = 0
+        self.root_walker.walk_roots(
+            GCBase._counting_rpy_root,
+            GCBase._counting_rpy_root,
+            GCBase._counting_rpy_root)
+        return self._count_rpy
+
+    def _append_rpy_root(self, root):
+        # Can use the gc list, but should not allocate!
+        # It is essential that the list is not resizable!
+        lst = self._list_rpy
+        index = self._count_rpy
+        if index >= len(lst):
+            raise ValueError
+        self._count_rpy = index + 1
+        lst[index] = llmemory.cast_adr_to_ptr(root.address[0], llmemory.GCREF)
+
+    def _do_append_rpy_roots(self, lst):
+        self._count_rpy = 0
+        self._list_rpy = lst
+        self.root_walker.walk_roots(
+            GCBase._append_rpy_root,
+            GCBase._append_rpy_root,
+            GCBase._append_rpy_root)
+        self._list_rpy = None
+
+    def get_rpy_roots(self):
+        count = self._do_count_rpy_roots()
+        extra = 16
+        while True:
+            result = [lltype.nullptr(llmemory.GCREF.TO)] * (count + extra)
+            try:
+                self._do_append_rpy_roots(result)
+            except ValueError:
+                extra *= 3
+            else:
+                return result
+
+    # ---------- implementation of pypy.rlib.rgc.get_rpy_referents() ----------
+
+    def _count_rpy_referent(self, pointer, _):
+        self._count_rpy += 1
+
+    def _do_count_rpy_referents(self, gcref):
+        self._count_rpy = 0
+        self.trace(llmemory.cast_ptr_to_adr(gcref),
+                   self._count_rpy_referent, None)
+        return self._count_rpy
+
+    def _append_rpy_referent(self, pointer, _):
+        # Can use the gc list, but should not allocate!
+        # It is essential that the list is not resizable!
+        lst = self._list_rpy
+        index = self._count_rpy
+        if index >= len(lst):
+            raise ValueError
+        self._count_rpy = index + 1
+        lst[index] = llmemory.cast_adr_to_ptr(pointer.address[0],
+                                              llmemory.GCREF)
+
+    def _do_append_rpy_referents(self, gcref, lst):
+        self._count_rpy = 0
+        self._list_rpy = lst
+        self.trace(llmemory.cast_ptr_to_adr(gcref),
+                   self._append_rpy_referent, None)
+
+    def get_rpy_referents(self, gcref):
+        count = self._do_count_rpy_referents(gcref)
+        result = [lltype.nullptr(llmemory.GCREF.TO)] * count
+        self._do_append_rpy_referents(gcref, result)
+        return result
+
 
 class MovingGCBase(GCBase):
     moving_gc = True

Modified: pypy/branch/gc-module/pypy/rpython/memory/gctransform/framework.py
==============================================================================
--- pypy/branch/gc-module/pypy/rpython/memory/gctransform/framework.py	(original)
+++ pypy/branch/gc-module/pypy/rpython/memory/gctransform/framework.py	Mon Sep  6 19:06:52 2010
@@ -7,7 +7,7 @@
 from pypy.rpython.memory.gc import marksweep
 from pypy.rpython.memory.gcheader import GCHeaderBuilder
 from pypy.rlib.rarithmetic import ovfcheck
-from pypy.rlib import rstack
+from pypy.rlib import rstack, rgc
 from pypy.rlib.debug import ll_assert
 from pypy.translator.backendopt import graphanalyze
 from pypy.translator.backendopt.support import var_needsgc
@@ -388,6 +388,15 @@
         else:
             self.id_ptr = None
 
+        self.get_rpy_roots_ptr = getfn(GCClass.get_rpy_roots.im_func,
+                                       [s_gc],
+                                       rgc.s_list_of_gcrefs(),
+                                       minimal_transform=False)
+        self.get_rpy_referents_ptr = getfn(GCClass.get_rpy_referents.im_func,
+                                           [s_gc, s_gcref],
+                                           rgc.s_list_of_gcrefs(),
+                                           minimal_transform=False)
+
         self.set_max_heap_size_ptr = getfn(GCClass.set_max_heap_size.im_func,
                                            [s_gc,
                                             annmodel.SomeInteger(nonneg=True)],
@@ -883,6 +892,21 @@
     def gct_gc_get_type_info_group(self, hop):
         return hop.cast_result(self.c_type_info_group)
 
+    def gct_gc_get_rpy_roots(self, hop):
+        livevars = self.push_roots(hop)
+        hop.genop("direct_call",
+                  [self.get_rpy_roots_ptr, self.c_const_gc],
+                  resultvar=hop.spaceop.result)
+        self.pop_roots(hop, livevars)
+
+    def gct_gc_get_rpy_referents(self, hop):
+        livevars = self.push_roots(hop)
+        [v_ptr] = hop.spaceop.args
+        hop.genop("direct_call",
+                  [self.get_rpy_referents_ptr, self.c_const_gc, v_ptr],
+                  resultvar=hop.spaceop.result)
+        self.pop_roots(hop, livevars)
+
     def gct_malloc_nonmovable_varsize(self, hop):
         TYPE = hop.spaceop.result.concretetype
         if self.gcdata.gc.can_malloc_nonmovable():

Modified: pypy/branch/gc-module/pypy/rpython/rptr.py
==============================================================================
--- pypy/branch/gc-module/pypy/rpython/rptr.py	(original)
+++ pypy/branch/gc-module/pypy/rpython/rptr.py	Mon Sep  6 19:06:52 2010
@@ -35,6 +35,9 @@
         id = lltype.cast_ptr_to_int(p)
         return ll_str.ll_int2hex(r_uint(id), True)
 
+    def get_ll_eq_function(self):
+        return None
+
     def rtype_getattr(self, hop):
         attr = hop.args_s[1].const
         if isinstance(hop.s_result, annmodel.SomeLLADTMeth):

Modified: pypy/branch/gc-module/pypy/translator/c/test/test_newgc.py
==============================================================================
--- pypy/branch/gc-module/pypy/translator/c/test/test_newgc.py	(original)
+++ pypy/branch/gc-module/pypy/translator/c/test/test_newgc.py	Mon Sep  6 19:06:52 2010
@@ -2,7 +2,7 @@
 import sys, os, inspect
 
 from pypy.objspace.flow.model import summary
-from pypy.rpython.lltypesystem import lltype
+from pypy.rpython.lltypesystem import lltype, llmemory
 from pypy.rpython.lltypesystem.lloperation import llop
 from pypy.rpython.memory.test import snippet
 from pypy.rlib import rgc
@@ -23,6 +23,7 @@
     GC_CAN_SHRINK_ARRAY = False
 
     _isolated_func = None
+    c_allfuncs = None
 
     @classmethod
     def _makefunc_str_int(cls, f):
@@ -891,6 +892,56 @@
     def test_arraycopy_writebarrier_ptr(self):
         self.run("arraycopy_writebarrier_ptr")
 
+    def define_get_rpy_roots(self):
+        U = lltype.GcStruct('U', ('x', lltype.Signed))
+        S = lltype.GcStruct('S', ('u', lltype.Ptr(U)))
+
+        def g(s):
+            lst = rgc.get_rpy_roots()
+            found = False
+            for x in lst:
+                if x == lltype.cast_opaque_ptr(llmemory.GCREF, s):
+                    found = True
+                if x == lltype.cast_opaque_ptr(llmemory.GCREF, s.u):
+                    os.write(2, "s.u should not be found!\n")
+                    assert False
+            return found == 1
+
+        def fn():
+            s = lltype.malloc(S)
+            s.u = lltype.malloc(U)
+            found = g(s)
+            if not found:
+                os.write(2, "not found!\n")
+                assert False
+            s.u.x = 42
+            return 0
+
+        return fn
+
+    def test_get_rpy_roots(self):
+        self.run("get_rpy_roots")
+
+    def define_get_rpy_referents(self):
+        U = lltype.GcStruct('U', ('x', lltype.Signed))
+        S = lltype.GcStruct('S', ('u', lltype.Ptr(U)))
+
+        def fn():
+            s = lltype.malloc(S)
+            s.u = lltype.malloc(U)
+            gcref1 = lltype.cast_opaque_ptr(llmemory.GCREF, s)
+            gcref2 = lltype.cast_opaque_ptr(llmemory.GCREF, s.u)
+            lst = rgc.get_rpy_referents(gcref1)
+            assert gcref2 in lst
+            assert gcref1 not in lst
+            s.u.x = 42
+            return 0
+
+        return fn
+
+    def test_get_rpy_referents(self):
+        self.run("get_rpy_referents")
+
 
 class TestSemiSpaceGC(TestUsingFramework, snippet.SemiSpaceGCTestDefines):
     gcpolicy = "semispace"



More information about the Pypy-commit mailing list