[pypy-svn] r77142 - in pypy/trunk/pypy: module/gc module/gc/test rlib rlib/test rpython rpython/memory rpython/memory/gc rpython/memory/gctransform translator/c/test

arigo at codespeak.net arigo at codespeak.net
Fri Sep 17 15:15:52 CEST 2010


Author: arigo
Date: Fri Sep 17 15:15:50 2010
New Revision: 77142

Added:
   pypy/trunk/pypy/module/gc/referents.py
      - copied unchanged from r77139, pypy/branch/gc-module/pypy/module/gc/referents.py
   pypy/trunk/pypy/module/gc/test/test_referents.py
      - copied unchanged from r77139, pypy/branch/gc-module/pypy/module/gc/test/test_referents.py
   pypy/trunk/pypy/rpython/memory/gc/inspect.py
      - copied unchanged from r77139, pypy/branch/gc-module/pypy/rpython/memory/gc/inspect.py
Modified:
   pypy/trunk/pypy/module/gc/__init__.py
   pypy/trunk/pypy/module/gc/interp_gc.py
   pypy/trunk/pypy/module/gc/test/test_gc.py
   pypy/trunk/pypy/rlib/rgc.py
   pypy/trunk/pypy/rlib/test/test_rgc.py
   pypy/trunk/pypy/rpython/memory/gc/base.py
   pypy/trunk/pypy/rpython/memory/gc/markcompact.py
   pypy/trunk/pypy/rpython/memory/gctransform/framework.py
   pypy/trunk/pypy/rpython/memory/gctypelayout.py
   pypy/trunk/pypy/rpython/rptr.py
   pypy/trunk/pypy/translator/c/test/test_newgc.py
Log:
Merge branch/gc-module.  Adds some standard gc functions like
gc.get_referrers(), and some custom ones too.


Modified: pypy/trunk/pypy/module/gc/__init__.py
==============================================================================
--- pypy/trunk/pypy/module/gc/__init__.py	(original)
+++ pypy/trunk/pypy/module/gc/__init__.py	Fri Sep 17 15:15:50 2010
@@ -10,13 +10,22 @@
         'collect': 'interp_gc.collect',
         'enable_finalizers': 'interp_gc.enable_finalizers',
         'disable_finalizers': 'interp_gc.disable_finalizers',
-        'estimate_heap_size': 'interp_gc.estimate_heap_size',
         'garbage' : 'space.newlist([])',
         #'dump_heap_stats': 'interp_gc.dump_heap_stats',
     }
 
     def __init__(self, space, w_name):
-        ts = space.config.translation.type_system
-        if ts == 'ootype':
-            del self.interpleveldefs['dump_heap_stats']
+        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_rpy_type_index': 'referents.get_rpy_type_index',
+                'get_objects': 'referents.get_objects',
+                'get_referents': 'referents.get_referents',
+                'get_referrers': 'referents.get_referrers',
+                'dump_rpy_heap': 'referents.dump_rpy_heap',
+                'GcRef': 'referents.W_GcRef',
+                })
         MixedModule.__init__(self, space, w_name)

Modified: pypy/trunk/pypy/module/gc/interp_gc.py
==============================================================================
--- pypy/trunk/pypy/module/gc/interp_gc.py	(original)
+++ pypy/trunk/pypy/module/gc/interp_gc.py	Fri Sep 17 15:15:50 2010
@@ -24,36 +24,6 @@
 
 # ____________________________________________________________
 
-import sys
-platform = sys.platform
-
-def estimate_heap_size(space):
-    # XXX should be done with the help of the GCs
-    if platform == "linux2":
-        import os
-        pid = os.getpid()
-        try:
-            fd = os.open("/proc/" + str(pid) + "/status", os.O_RDONLY, 0777)
-        except OSError:
-            pass
-        else:
-            try:
-                content = os.read(fd, 1000000)
-            finally:
-                os.close(fd)
-            lines = content.split("\n")
-            for line in lines:
-                if line.startswith("VmSize:"):
-                    start = line.find(" ") # try to ignore tabs
-                    assert start > 0
-                    stop = len(line) - 3
-                    assert stop > 0
-                    result = int(line[start:stop].strip(" ")) * 1024
-                    return space.wrap(result)
-    raise OperationError(space.w_RuntimeError,
-                         space.wrap("can't estimate the heap size"))
-estimate_heap_size.unwrap_spec = [ObjSpace]
-
 def dump_heap_stats(space, filename):
     tb = rgc._heap_stats()
     if not tb:

Modified: pypy/trunk/pypy/module/gc/test/test_gc.py
==============================================================================
--- pypy/trunk/pypy/module/gc/test/test_gc.py	(original)
+++ pypy/trunk/pypy/module/gc/test/test_gc.py	Fri Sep 17 15:15:50 2010
@@ -59,13 +59,6 @@
         raises(ValueError, gc.enable_finalizers)
         runtest(True)
 
-    def test_estimate_heap_size(self):
-        import sys, gc
-        if sys.platform == "linux2":
-            assert gc.estimate_heap_size() > 1024
-        else:
-            raises(RuntimeError, gc.estimate_heap_size)
-
     def test_enable(self):
         import gc
         assert gc.isenabled()

Modified: pypy/trunk/pypy/rlib/rgc.py
==============================================================================
--- pypy/trunk/pypy/rlib/rgc.py	(original)
+++ pypy/trunk/pypy/rlib/rgc.py	Fri Sep 17 15:15:50 2010
@@ -1,6 +1,7 @@
-import gc
+import gc, types
 from pypy.rpython.extregistry import ExtRegistryEntry
 from pypy.rlib.objectmodel import we_are_translated
+from pypy.rpython.lltypesystem import lltype, llmemory
 
 # ____________________________________________________________
 # General GC features
@@ -93,7 +94,7 @@
 
     def specialize_call(self, hop):
         from pypy.rpython.error import TyperError
-        from pypy.rpython.lltypesystem import lltype, llmemory, rtuple
+        from pypy.rpython.lltypesystem import rtuple
         from pypy.annotation import model as annmodel
         from pypy.rpython.memory.gc.marksweep import X_CLONE, X_CLONE_PTR
 
@@ -150,7 +151,6 @@
         return annmodel.s_None
 
     def specialize_call(self, hop):
-        from pypy.rpython.lltypesystem import lltype        
         hop.exception_cannot_occur()
         args_v = []
         if len(hop.args_s) == 1:
@@ -165,7 +165,6 @@
         return annmodel.s_None
 
     def specialize_call(self, hop):
-        from pypy.rpython.lltypesystem import lltype
         [v_nbytes] = hop.inputargs(lltype.Signed)
         hop.exception_cannot_occur()
         return hop.genop('gc_set_max_heap_size', [v_nbytes],
@@ -182,7 +181,6 @@
         return annmodel.SomeBool()
 
     def specialize_call(self, hop):
-        from pypy.rpython.lltypesystem import lltype
         hop.exception_cannot_occur()
         return hop.genop('gc_can_move', hop.args_v, resulttype=hop.r_result)
 
@@ -195,11 +193,9 @@
     def compute_result_annotation(self):
         from pypy.annotation import model as annmodel
         from pypy.rpython.memory.gc.base import ARRAY_TYPEID_MAP
-        from pypy.rpython.lltypesystem import lltype
         return annmodel.SomePtr(lltype.Ptr(ARRAY_TYPEID_MAP))
 
     def specialize_call(self, hop):
-        from pypy.rpython.lltypesystem import lltype
         from pypy.rpython.memory.gc.base import ARRAY_TYPEID_MAP
         hop.exception_is_here()
         return hop.genop('gc_heap_stats', [], resulttype=hop.r_result)
@@ -209,7 +205,6 @@
     When running directly, will pretend that gc is always
     moving (might be configurable in a future)
     """
-    from pypy.rpython.lltypesystem import lltype
     return lltype.nullptr(TP)
 
 class MallocNonMovingEntry(ExtRegistryEntry):
@@ -221,7 +216,6 @@
         return malloc(s_TP, s_n, s_zero=s_zero)
 
     def specialize_call(self, hop, i_zero=None):
-        from pypy.rpython.lltypesystem import lltype
         # XXX assume flavor and zero to be None by now
         assert hop.args_s[0].is_constant()
         vlist = [hop.inputarg(lltype.Void, arg=0)]
@@ -243,7 +237,6 @@
 
 def ll_arraycopy(source, dest, source_start, dest_start, length):
     from pypy.rpython.lltypesystem.lloperation import llop
-    from pypy.rpython.lltypesystem import lltype, llmemory
     from pypy.rlib.objectmodel import keepalive_until_here
 
     # supports non-overlapping copies only
@@ -279,7 +272,6 @@
 
 def ll_shrink_array(p, smallerlength):
     from pypy.rpython.lltypesystem.lloperation import llop
-    from pypy.rpython.lltypesystem import lltype, llmemory
     from pypy.rlib.objectmodel import keepalive_until_here
 
     if llop.shrink_array(lltype.Bool, p, smallerlength):
@@ -313,3 +305,221 @@
     func._dont_inline_ = True
     func._gc_no_collect_ = True
     return func
+
+# ____________________________________________________________
+
+def get_rpy_roots():
+    "NOT_RPYTHON"
+    # 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):
+    "NOT_RPYTHON"
+    x = gcref._x
+    if isinstance(x, list):
+        d = x
+    elif isinstance(x, dict):
+        d = x.keys() + x.values()
+    else:
+        d = []
+        if hasattr(x, '__dict__'):
+            d = x.__dict__.values()
+        if hasattr(type(x), '__slots__'):
+            for slot in type(x).__slots__:
+                try:
+                    d.append(getattr(x, slot))
+                except AttributeError:
+                    pass
+    # discard objects that are too random or that are _freeze_=True
+    return [_GcRef(x) for x in d if _keep_object(x)]
+
+def _keep_object(x):
+    if isinstance(x, type) or type(x) is types.ClassType:
+        return False      # don't keep any type
+    if isinstance(x, (list, dict, str)):
+        return True       # keep lists and dicts and strings
+    try:
+        return not x._freeze_()   # don't keep any frozen object
+    except AttributeError:
+        return type(x).__module__ != '__builtin__'   # keep non-builtins
+    except Exception:
+        return False      # don't keep objects whose _freeze_() method explodes
+
+def get_rpy_memory_usage(gcref):
+    "NOT_RPYTHON"
+    # approximate implementation using CPython's type info
+    Class = type(gcref._x)
+    size = Class.__basicsize__
+    if Class.__itemsize__ > 0:
+        size += Class.__itemsize__ * len(gcref._x)
+    return size
+
+def get_rpy_type_index(gcref):
+    "NOT_RPYTHON"
+    from pypy.rlib.rarithmetic import intmask
+    Class = gcref._x.__class__
+    return intmask(id(Class))
+
+def cast_gcref_to_int(gcref):
+    if we_are_translated():
+        return lltype.cast_ptr_to_int(gcref)
+    else:
+        return id(gcref._x)
+
+def dump_rpy_heap(fd):
+    "NOT_RPYTHON"
+    raise NotImplementedError
+
+NULL_GCREF = lltype.nullptr(llmemory.GCREF.TO)
+
+class _GcRef(object):
+    # implementation-specific: there should not be any after translation
+    __slots__ = ['_x']
+    def __init__(self, x):
+        self._x = x
+    def __hash__(self):
+        return object.__hash__(self._x)
+    def __eq__(self, other):
+        if isinstance(other, lltype._ptr):
+            assert other == NULL_GCREF, (
+                "comparing a _GcRef with a non-NULL lltype ptr")
+            return False
+        assert isinstance(other, _GcRef)
+        return self._x is other._x
+    def __ne__(self, other):
+        return not self.__eq__(other)
+    def __repr__(self):
+        return "_GcRef(%r)" % (self._x, )
+    def _freeze_(self):
+        raise Exception("instances of rlib.rgc._GcRef cannot be translated")
+
+def cast_instance_to_gcref(x):
+    # Before translation, casts an RPython instance into a _GcRef.
+    # After translation, it is a variant of cast_object_to_ptr(GCREF).
+    if we_are_translated():
+        from pypy.rpython import annlowlevel
+        x = annlowlevel.cast_instance_to_base_ptr(x)
+        return lltype.cast_opaque_ptr(llmemory.GCREF, x)
+    else:
+        return _GcRef(x)
+cast_instance_to_gcref._annspecialcase_ = 'specialize:argtype(0)'
+
+def try_cast_gcref_to_instance(Class, gcref):
+    # Before translation, unwraps the RPython instance contained in a _GcRef.
+    # After translation, it is a type-check performed by the GC.
+    if we_are_translated():
+        from pypy.rpython.annlowlevel import base_ptr_lltype
+        from pypy.rpython.annlowlevel import cast_base_ptr_to_instance
+        from pypy.rpython.lltypesystem import rclass
+        if _is_rpy_instance(gcref):
+            objptr = lltype.cast_opaque_ptr(base_ptr_lltype(), gcref)
+            if objptr.typeptr:   # may be NULL, e.g. in rdict's dummykeyobj
+                clsptr = _get_llcls_from_cls(Class)
+                if rclass.ll_isinstance(objptr, clsptr):
+                    return cast_base_ptr_to_instance(Class, objptr)
+        return None
+    else:
+        if isinstance(gcref._x, Class):
+            return gcref._x
+        return None
+try_cast_gcref_to_instance._annspecialcase_ = 'specialize:arg(0)'
+
+# ------------------- implementation -------------------
+
+_cache_s_list_of_gcrefs = None
+
+def s_list_of_gcrefs():
+    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, mutated=True, resized=False))
+    return _cache_s_list_of_gcrefs
+
+class Entry(ExtRegistryEntry):
+    _about_ = get_rpy_roots
+    def compute_result_annotation(self):
+        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)
+
+class Entry(ExtRegistryEntry):
+    _about_ = get_rpy_memory_usage
+    def compute_result_annotation(self, s_gcref):
+        from pypy.annotation import model as annmodel
+        return annmodel.SomeInteger()
+    def specialize_call(self, hop):
+        vlist = hop.inputargs(hop.args_r[0])
+        return hop.genop('gc_get_rpy_memory_usage', vlist,
+                         resulttype = hop.r_result)
+
+class Entry(ExtRegistryEntry):
+    _about_ = get_rpy_type_index
+    def compute_result_annotation(self, s_gcref):
+        from pypy.annotation import model as annmodel
+        return annmodel.SomeInteger()
+    def specialize_call(self, hop):
+        vlist = hop.inputargs(hop.args_r[0])
+        return hop.genop('gc_get_rpy_type_index', vlist,
+                         resulttype = hop.r_result)
+
+def _is_rpy_instance(gcref):
+    "NOT_RPYTHON"
+    raise NotImplementedError
+
+def _get_llcls_from_cls(Class):
+    "NOT_RPYTHON"
+    raise NotImplementedError
+
+class Entry(ExtRegistryEntry):
+    _about_ = _is_rpy_instance
+    def compute_result_annotation(self, s_gcref):
+        from pypy.annotation import model as annmodel
+        return annmodel.SomeBool()
+    def specialize_call(self, hop):
+        vlist = hop.inputargs(hop.args_r[0])
+        return hop.genop('gc_is_rpy_instance', vlist,
+                         resulttype = hop.r_result)
+
+class Entry(ExtRegistryEntry):
+    _about_ = _get_llcls_from_cls
+    def compute_result_annotation(self, s_Class):
+        from pypy.annotation import model as annmodel
+        from pypy.rpython.lltypesystem import rclass
+        assert s_Class.is_constant()
+        return annmodel.SomePtr(rclass.CLASSTYPE)
+    def specialize_call(self, hop):
+        from pypy.rpython.rclass import getclassrepr
+        from pypy.objspace.flow.model import Constant
+        from pypy.rpython.lltypesystem import rclass
+        Class = hop.args_s[0].const
+        classdef = hop.rtyper.annotator.bookkeeper.getuniqueclassdef(Class)
+        classrepr = getclassrepr(hop.rtyper, classdef)
+        vtable = classrepr.getvtable()
+        assert lltype.typeOf(vtable) == rclass.CLASSTYPE
+        return Constant(vtable, concretetype=rclass.CLASSTYPE)
+
+class Entry(ExtRegistryEntry):
+    _about_ = dump_rpy_heap
+    def compute_result_annotation(self, s_fd):
+        from pypy.annotation.model import s_None
+        return s_None
+    def specialize_call(self, hop):
+        vlist = hop.inputargs(lltype.Signed)
+        hop.exception_is_here()
+        return hop.genop('gc_dump_rpy_heap', vlist, resulttype = hop.r_result)

Modified: pypy/trunk/pypy/rlib/test/test_rgc.py
==============================================================================
--- pypy/trunk/pypy/rlib/test/test_rgc.py	(original)
+++ pypy/trunk/pypy/rlib/test/test_rgc.py	Fri Sep 17 15:15:50 2010
@@ -153,3 +153,29 @@
     assert len(s2.vars) == 3
     for i in range(3):
         assert s2.vars[i] == 50 + i
+
+
+def test_get_objects():
+    class X(object):
+        pass
+    x1 = X()
+    lst = rgc._get_objects()
+    assert rgc.cast_instance_to_gcref(x1) in lst
+
+def test_get_referents():
+    class X(object):
+        __slots__ = ['stuff']
+    x1 = X()
+    x1.stuff = X()
+    x2 = X()
+    lst = rgc._get_referents(rgc.cast_instance_to_gcref(x1))
+    lst2 = [rgc.try_cast_gcref_to_instance(X, x) for x in lst]
+    assert x1.stuff in lst2
+    assert x2 not in lst2
+
+def test_get_memory_usage():
+    class X(object):
+        pass
+    x1 = X()
+    n = rgc._get_memory_usage(rgc.cast_instance_to_gcref(x1))
+    assert n >= 8 and n <= 64

Modified: pypy/trunk/pypy/rpython/memory/gc/base.py
==============================================================================
--- pypy/trunk/pypy/rpython/memory/gc/base.py	(original)
+++ pypy/trunk/pypy/rpython/memory/gc/base.py	Fri Sep 17 15:15:50 2010
@@ -53,7 +53,8 @@
                             varsize_offset_to_length,
                             varsize_offsets_to_gcpointers_in_var_part,
                             weakpointer_offset,
-                            member_index):
+                            member_index,
+                            is_rpython_class):
         self.getfinalizer = getfinalizer
         self.is_varsize = is_varsize
         self.has_gcptr_in_varsize = has_gcptr_in_varsize
@@ -66,6 +67,7 @@
         self.varsize_offsets_to_gcpointers_in_var_part = varsize_offsets_to_gcpointers_in_var_part
         self.weakpointer_offset = weakpointer_offset
         self.member_index = member_index
+        self.is_rpython_class = is_rpython_class
 
     def get_member_index(self, type_id):
         return self.member_index(type_id)
@@ -101,6 +103,9 @@
     def get_size(self, obj):
         return self._get_size_for_typeid(obj, self.get_type_id(obj))
 
+    def get_size_incl_hash(self, obj):
+        return self.get_size(obj)
+
     def malloc(self, typeid, length=0, zero=False):
         """For testing.  The interface used by the gctransformer is
         the four malloc_[fixed,var]size[_clear]() functions.

Modified: pypy/trunk/pypy/rpython/memory/gc/markcompact.py
==============================================================================
--- pypy/trunk/pypy/rpython/memory/gc/markcompact.py	(original)
+++ pypy/trunk/pypy/rpython/memory/gc/markcompact.py	Fri Sep 17 15:15:50 2010
@@ -674,6 +674,13 @@
                 return llmemory.cast_adr_to_int(obj)  # not in an arena...
             return adr - self.space
 
+    def get_size_incl_hash(self, obj):
+        size = self.get_size(obj)
+        hdr = self.header(obj)
+        if hdr.tid & GCFLAG_HASHFIELD:
+            size += llmemory.sizeof(lltype.Signed)
+        return size
+
 # ____________________________________________________________
 
 class CannotAllocateGCArena(Exception):

Modified: pypy/trunk/pypy/rpython/memory/gctransform/framework.py
==============================================================================
--- pypy/trunk/pypy/rpython/memory/gctransform/framework.py	(original)
+++ pypy/trunk/pypy/rpython/memory/gctransform/framework.py	Fri Sep 17 15:15:50 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
@@ -139,6 +139,8 @@
     def __init__(self, translator):
         from pypy.rpython.memory.gc.base import choose_gc_from_config
         from pypy.rpython.memory.gc.base import ARRAY_TYPEID_MAP
+        from pypy.rpython.memory.gc import inspect
+
         super(FrameworkGCTransformer, self).__init__(translator, inline=True)
         if hasattr(self, 'GC_PARAMS'):
             # for tests: the GC choice can be specified as class attributes
@@ -388,6 +390,31 @@
         else:
             self.id_ptr = None
 
+        self.get_rpy_roots_ptr = getfn(inspect.get_rpy_roots,
+                                       [s_gc],
+                                       rgc.s_list_of_gcrefs(),
+                                       minimal_transform=False)
+        self.get_rpy_referents_ptr = getfn(inspect.get_rpy_referents,
+                                           [s_gc, s_gcref],
+                                           rgc.s_list_of_gcrefs(),
+                                           minimal_transform=False)
+        self.get_rpy_memory_usage_ptr = getfn(inspect.get_rpy_memory_usage,
+                                              [s_gc, s_gcref],
+                                              annmodel.SomeInteger(),
+                                              minimal_transform=False)
+        self.get_rpy_type_index_ptr = getfn(inspect.get_rpy_type_index,
+                                            [s_gc, s_gcref],
+                                            annmodel.SomeInteger(),
+                                            minimal_transform=False)
+        self.is_rpy_instance_ptr = getfn(inspect.is_rpy_instance,
+                                         [s_gc, s_gcref],
+                                         annmodel.SomeBool(),
+                                         minimal_transform=False)
+        self.dump_rpy_heap_ptr = getfn(inspect.dump_rpy_heap,
+                                       [s_gc, annmodel.SomeInteger()],
+                                       annmodel.s_None,
+                                       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 +910,53 @@
     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_gc_get_rpy_memory_usage(self, hop):
+        livevars = self.push_roots(hop)
+        [v_ptr] = hop.spaceop.args
+        hop.genop("direct_call",
+                  [self.get_rpy_memory_usage_ptr, self.c_const_gc, v_ptr],
+                  resultvar=hop.spaceop.result)
+        self.pop_roots(hop, livevars)
+
+    def gct_gc_get_rpy_type_index(self, hop):
+        livevars = self.push_roots(hop)
+        [v_ptr] = hop.spaceop.args
+        hop.genop("direct_call",
+                  [self.get_rpy_type_index_ptr, self.c_const_gc, v_ptr],
+                  resultvar=hop.spaceop.result)
+        self.pop_roots(hop, livevars)
+
+    def gct_gc_is_rpy_instance(self, hop):
+        livevars = self.push_roots(hop)
+        [v_ptr] = hop.spaceop.args
+        hop.genop("direct_call",
+                  [self.is_rpy_instance_ptr, self.c_const_gc, v_ptr],
+                  resultvar=hop.spaceop.result)
+        self.pop_roots(hop, livevars)
+
+    def gct_gc_dump_rpy_heap(self, hop):
+        livevars = self.push_roots(hop)
+        [v_fd] = hop.spaceop.args
+        hop.genop("direct_call",
+                  [self.dump_rpy_heap_ptr, self.c_const_gc, v_fd],
+                  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/trunk/pypy/rpython/memory/gctypelayout.py
==============================================================================
--- pypy/trunk/pypy/rpython/memory/gctypelayout.py	(original)
+++ pypy/trunk/pypy/rpython/memory/gctypelayout.py	Fri Sep 17 15:15:50 2010
@@ -101,6 +101,10 @@
         infobits = self.get(typeid).infobits
         return infobits & T_MEMBER_INDEX
 
+    def q_is_rpython_class(self, typeid):
+        infobits = self.get(typeid).infobits
+        return infobits & T_IS_RPYTHON_INSTANCE != 0
+
     def set_query_functions(self, gc):
         gc.set_query_functions(
             self.q_is_varsize,
@@ -114,7 +118,8 @@
             self.q_varsize_offset_to_length,
             self.q_varsize_offsets_to_gcpointers_in_var_part,
             self.q_weakpointer_offset,
-            self.q_member_index)
+            self.q_member_index,
+            self.q_is_rpython_class)
 
 
 # the lowest 16bits are used to store group member index
@@ -123,6 +128,7 @@
 T_HAS_GCPTR_IN_VARSIZE = 0x20000
 T_IS_GCARRAY_OF_GCPTR  = 0x40000
 T_IS_WEAKREF           = 0x80000
+T_IS_RPYTHON_INSTANCE  = 0x100000    # the type is a subclass of OBJECT
 T_KEY_MASK             = intmask(0xFF000000)
 T_KEY_VALUE            = intmask(0x7A000000)    # bug detection only
 
@@ -181,6 +187,8 @@
         varinfo.varitemsize = llmemory.sizeof(ARRAY.OF)
     if builder.is_weakref_type(TYPE):
         infobits |= T_IS_WEAKREF
+    if is_subclass_of_object(TYPE):
+        infobits |= T_IS_RPYTHON_INSTANCE
     info.infobits = infobits | T_KEY_VALUE
 
 # ____________________________________________________________
@@ -259,9 +267,7 @@
         else:
             # no vtable from lltype2vtable -- double-check to be sure
             # that it's not a subclass of OBJECT.
-            while isinstance(TYPE, lltype.GcStruct):
-                assert TYPE is not rclass.OBJECT
-                _, TYPE = TYPE._first_struct()
+            assert not is_subclass_of_object(TYPE)
 
     def get_info(self, type_id):
         res = llop.get_group_member(GCData.TYPE_INFO_PTR,
@@ -437,6 +443,13 @@
             for i in range(p._obj.getlength()):
                 zero_gc_pointers_inside(p[i], ITEM)
 
+def is_subclass_of_object(TYPE):
+    while isinstance(TYPE, lltype.GcStruct):
+        if TYPE is rclass.OBJECT:
+            return True
+        _, TYPE = TYPE._first_struct()
+    return False
+
 ########## weakrefs ##########
 # framework: weakref objects are small structures containing only an address
 

Modified: pypy/trunk/pypy/rpython/rptr.py
==============================================================================
--- pypy/trunk/pypy/rpython/rptr.py	(original)
+++ pypy/trunk/pypy/rpython/rptr.py	Fri Sep 17 15:15:50 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/trunk/pypy/translator/c/test/test_newgc.py
==============================================================================
--- pypy/trunk/pypy/translator/c/test/test_newgc.py	(original)
+++ pypy/trunk/pypy/translator/c/test/test_newgc.py	Fri Sep 17 15:15:50 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,202 @@
     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")
+
+    def define_is_rpy_instance(self):
+        class Foo:
+            pass
+        S = lltype.GcStruct('S', ('x', lltype.Signed))
+
+        def check(gcref, expected):
+            result = rgc._is_rpy_instance(gcref)
+            assert result == expected
+
+        def fn():
+            s = lltype.malloc(S)
+            gcref1 = lltype.cast_opaque_ptr(llmemory.GCREF, s)
+            check(gcref1, False)
+
+            f = Foo()
+            gcref3 = rgc.cast_instance_to_gcref(f)
+            check(gcref3, True)
+
+            return 0
+
+        return fn
+
+    def test_is_rpy_instance(self):
+        self.run("is_rpy_instance")
+
+    def define_try_cast_gcref_to_instance(self):
+        class Foo:
+            pass
+        class FooBar(Foo):
+            pass
+        class Biz(object):
+            pass
+        S = lltype.GcStruct('S', ('x', lltype.Signed))
+
+        def fn():
+            foo = Foo()
+            gcref1 = rgc.cast_instance_to_gcref(foo)
+            assert rgc.try_cast_gcref_to_instance(Foo,    gcref1) is foo
+            assert rgc.try_cast_gcref_to_instance(FooBar, gcref1) is None
+            assert rgc.try_cast_gcref_to_instance(Biz,    gcref1) is None
+
+            foobar = FooBar()
+            gcref2 = rgc.cast_instance_to_gcref(foobar)
+            assert rgc.try_cast_gcref_to_instance(Foo,    gcref2) is foobar
+            assert rgc.try_cast_gcref_to_instance(FooBar, gcref2) is foobar
+            assert rgc.try_cast_gcref_to_instance(Biz,    gcref2) is None
+
+            s = lltype.malloc(S)
+            gcref3 = lltype.cast_opaque_ptr(llmemory.GCREF, s)
+            assert rgc.try_cast_gcref_to_instance(Foo,    gcref3) is None
+            assert rgc.try_cast_gcref_to_instance(FooBar, gcref3) is None
+            assert rgc.try_cast_gcref_to_instance(Biz,    gcref3) is None
+
+            return 0
+
+        return fn
+
+    def test_try_cast_gcref_to_instance(self):
+        self.run("try_cast_gcref_to_instance")
+
+    def define_get_rpy_memory_usage(self):
+        U = lltype.GcStruct('U', ('x1', lltype.Signed),
+                                 ('x2', lltype.Signed),
+                                 ('x3', lltype.Signed),
+                                 ('x4', lltype.Signed),
+                                 ('x5', lltype.Signed),
+                                 ('x6', lltype.Signed),
+                                 ('x7', lltype.Signed),
+                                 ('x8', lltype.Signed))
+        S = lltype.GcStruct('S', ('u', lltype.Ptr(U)))
+        A = lltype.GcArray(lltype.Ptr(S))
+
+        def fn():
+            s = lltype.malloc(S)
+            s.u = lltype.malloc(U)
+            a = lltype.malloc(A, 1000)
+            gcref1 = lltype.cast_opaque_ptr(llmemory.GCREF, s)
+            int1 = rgc.get_rpy_memory_usage(gcref1)
+            assert 8 <= int1 <= 32
+            gcref2 = lltype.cast_opaque_ptr(llmemory.GCREF, s.u)
+            int2 = rgc.get_rpy_memory_usage(gcref2)
+            assert 4*9 <= int2 <= 8*12
+            gcref3 = lltype.cast_opaque_ptr(llmemory.GCREF, a)
+            int3 = rgc.get_rpy_memory_usage(gcref3)
+            assert 4*1001 <= int3 <= 8*1010
+            return 0
+
+        return fn
+
+    def test_get_rpy_memory_usage(self):
+        self.run("get_rpy_memory_usage")
+
+    def define_get_rpy_type_index(self):
+        U = lltype.GcStruct('U', ('x', lltype.Signed))
+        S = lltype.GcStruct('S', ('u', lltype.Ptr(U)))
+        A = lltype.GcArray(lltype.Ptr(S))
+
+        def fn():
+            s = lltype.malloc(S)
+            s.u = lltype.malloc(U)
+            a = lltype.malloc(A, 1000)
+            s2 = lltype.malloc(S)
+            gcref1 = lltype.cast_opaque_ptr(llmemory.GCREF, s)
+            int1 = rgc.get_rpy_type_index(gcref1)
+            gcref2 = lltype.cast_opaque_ptr(llmemory.GCREF, s.u)
+            int2 = rgc.get_rpy_type_index(gcref2)
+            gcref3 = lltype.cast_opaque_ptr(llmemory.GCREF, a)
+            int3 = rgc.get_rpy_type_index(gcref3)
+            gcref4 = lltype.cast_opaque_ptr(llmemory.GCREF, s2)
+            int4 = rgc.get_rpy_type_index(gcref4)
+            assert int1 != int2
+            assert int1 != int3
+            assert int2 != int3
+            assert int1 == int4
+            return 0
+
+        return fn
+
+    def test_get_rpy_type_index(self):
+        self.run("get_rpy_type_index")
+
+    filename_dump = str(udir.join('test_dump_rpy_heap'))
+    def define_dump_rpy_heap(self):
+        U = lltype.GcStruct('U', ('x', lltype.Signed))
+        S = lltype.GcStruct('S', ('u', lltype.Ptr(U)))
+        A = lltype.GcArray(lltype.Ptr(S))
+        filename = self.filename_dump
+
+        def fn():
+            s = lltype.malloc(S)
+            s.u = lltype.malloc(U)
+            a = lltype.malloc(A, 1000)
+            s2 = lltype.malloc(S)
+            #
+            fd = os.open(filename, os.O_WRONLY | os.O_CREAT, 0666)
+            rgc.dump_rpy_heap(fd)
+            os.close(fd)
+            return 0
+
+        return fn
+
+    def test_dump_rpy_heap(self):
+        self.run("dump_rpy_heap")
+        assert os.path.exists(self.filename_dump)
+        assert os.path.getsize(self.filename_dump) > 0       # minimal test
+
 
 class TestSemiSpaceGC(TestUsingFramework, snippet.SemiSpaceGCTestDefines):
     gcpolicy = "semispace"



More information about the Pypy-commit mailing list