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

arigo at codespeak.net arigo at codespeak.net
Mon Sep 6 19:59:47 CEST 2010


Author: arigo
Date: Mon Sep  6 19:59:45 2010
New Revision: 76905

Modified:
   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/memory/gctypelayout.py
   pypy/branch/gc-module/pypy/translator/c/test/test_newgc.py
Log:
Implement translation of try_cast_gcref_to_instance()
using an internal helper, rgc._is_rpy_instance(),
whose answer is stored as a flag in the GC type layout.


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:59:45 2010
@@ -309,12 +309,14 @@
 # ____________________________________________________________
 
 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
@@ -346,6 +348,7 @@
         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__
@@ -385,14 +388,32 @@
 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).
-    return _GcRef(x)
+    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 isinstance(gcref._x, Class):
-        return gcref._x
-    return None
+    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)
+            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 -------------------
 
@@ -425,3 +446,39 @@
         vlist = hop.inputargs(hop.args_r[0])
         return hop.genop('gc_get_rpy_referents', 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)

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:59:45 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)
@@ -333,6 +335,12 @@
         self._do_append_rpy_referents(gcref, result)
         return result
 
+    # ----------
+
+    def is_rpy_instance(self, gcref):
+        typeid = self.get_type_id(llmemory.cast_ptr_to_adr(gcref))
+        return self.is_rpython_class(typeid)
+
 
 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:59:45 2010
@@ -396,6 +396,10 @@
                                            [s_gc, s_gcref],
                                            rgc.s_list_of_gcrefs(),
                                            minimal_transform=False)
+        self.is_rpy_instance_ptr = getfn(GCClass.is_rpy_instance.im_func,
+                                         [s_gc, s_gcref],
+                                         annmodel.SomeBool(),
+                                         minimal_transform=False)
 
         self.set_max_heap_size_ptr = getfn(GCClass.set_max_heap_size.im_func,
                                            [s_gc,
@@ -907,6 +911,14 @@
                   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_malloc_nonmovable_varsize(self, hop):
         TYPE = hop.spaceop.result.concretetype
         if self.gcdata.gc.can_malloc_nonmovable():

Modified: pypy/branch/gc-module/pypy/rpython/memory/gctypelayout.py
==============================================================================
--- pypy/branch/gc-module/pypy/rpython/memory/gctypelayout.py	(original)
+++ pypy/branch/gc-module/pypy/rpython/memory/gctypelayout.py	Mon Sep  6 19:59:45 2010
@@ -100,6 +100,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,
@@ -113,7 +117,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
@@ -122,6 +127,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          = 0xFF000000
 T_KEY_VALUE         = 0x7A000000    # bug detection only
 
@@ -180,6 +186,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
 
 # ____________________________________________________________
@@ -258,9 +266,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,
@@ -436,6 +442,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/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:59:45 2010
@@ -942,6 +942,66 @@
     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")
+
 
 class TestSemiSpaceGC(TestUsingFramework, snippet.SemiSpaceGCTestDefines):
     gcpolicy = "semispace"



More information about the Pypy-commit mailing list