Author: Armin Rigo <[email protected]>
Branch: optresult-unroll
Changeset: r79500:6da38340bd1a
Date: 2015-09-07 12:11 +0200
http://bitbucket.org/pypy/pypy/changeset/6da38340bd1a/

Log:    Add and test cpu.check_is_object() and cpu.get_actual_typeid(), to
        constant-fold guard_is_object and guard_gc_type.

diff --git a/rpython/jit/backend/llgraph/runner.py 
b/rpython/jit/backend/llgraph/runner.py
--- a/rpython/jit/backend/llgraph/runner.py
+++ b/rpython/jit/backend/llgraph/runner.py
@@ -517,6 +517,22 @@
             self.descrs[key] = descr
             return descr
 
+    def check_is_object(self, gcptr):
+        """Check if the given, non-null gcptr refers to an rclass.OBJECT
+        or not at all (an unrelated GcStruct or a GcArray).  Only usable
+        in the llgraph backend, or after translation of a real backend."""
+        ptr = lltype.normalizeptr(gcptr._obj.container._as_ptr())
+        T = lltype.typeOf(ptr).TO
+        return heaptracker.has_gcstruct_a_vtable(T) or T is rclass.OBJECT
+
+    def get_actual_typeid(self, gcptr):
+        """Fetch the actual typeid of the given gcptr, as an integer.
+        Only usable in the llgraph backend, or after translation of a
+        real backend.  (Here in the llgraph backend, returns a
+        TypeIDSymbolic instead of a real integer.)"""
+        ptr = lltype.normalizeptr(gcptr._obj.container._as_ptr())
+        return TypeIDSymbolic(lltype.typeOf(ptr).TO)
+
     # ------------------------------------------------------------
 
     def maybe_on_top_of_llinterp(self, func, args, RESULT):
diff --git a/rpython/jit/backend/llsupport/gc.py 
b/rpython/jit/backend/llsupport/gc.py
--- a/rpython/jit/backend/llsupport/gc.py
+++ b/rpython/jit/backend/llsupport/gc.py
@@ -725,6 +725,24 @@
         infobits_offset += self._infobits_offset_plus
         return (infobits_offset, self._T_IS_RPYTHON_INSTANCE_BYTE)
 
+    def get_actual_typeid(self, gcptr):
+        # Read the whole GC header word.  The typeid is the lower half-word.
+        hdr = rffi.cast(self.HDRPTR, gcptr)
+        type_id = llop.extract_ushort(llgroup.HALFWORD, hdr.tid)
+        return llop.combine_ushort(lltype.Signed, type_id, 0)
+
+    def check_is_object(self, gcptr):
+        # read the typeid, fetch one byte of the field 'infobits' from
+        # the big typeinfo table, and check the flag 'T_IS_RPYTHON_INSTANCE'.
+        typeid = self.get_actual_typeid(gcptr)
+        #
+        base_type_info, shift_by, sizeof_ti = (
+            self.get_translated_info_for_typeinfo())
+        infobits_offset, IS_OBJECT_FLAG = (
+            self.get_translated_info_for_guard_is_object())
+        p = base_type_info + (typeid << shift_by) + infobits_offset
+        p = rffi.cast(rffi.CCHARP, p)
+        return (ord(p[0]) & IS_OBJECT_FLAG) != 0
 
 # ____________________________________________________________
 
diff --git a/rpython/jit/backend/llsupport/llmodel.py 
b/rpython/jit/backend/llsupport/llmodel.py
--- a/rpython/jit/backend/llsupport/llmodel.py
+++ b/rpython/jit/backend/llsupport/llmodel.py
@@ -480,8 +480,24 @@
         descrs = self.gc_ll_descr.getframedescrs(self)
         base_ofs = self.unpack_arraydescr(descrs.arraydescr)
         return base_ofs
+
     # ____________________________________________________________
 
+    def check_is_object(self, gcptr):
+        """Check if the given, non-null gcptr refers to an rclass.OBJECT
+        or not at all (an unrelated GcStruct or a GcArray).  Only usable
+        in the llgraph backend, or after translation of a real backend."""
+        assert self.supports_guard_gc_type
+        return self.gc_ll_descr.check_is_object(gcptr)
+
+    def get_actual_typeid(self, gcptr):
+        """Fetch the actual typeid of the given gcptr, as an integer.
+        Only usable in the llgraph backend, or after translation of a
+        real backend."""
+        assert self.supports_guard_gc_type
+        return self.gc_ll_descr.get_actual_typeid(gcptr)
+
+    # ____________________________________________________________
 
     def bh_arraylen_gc(self, array, arraydescr):
         assert isinstance(arraydescr, ArrayDescr)
diff --git a/rpython/jit/backend/llsupport/test/test_zrpy_gc_direct.py 
b/rpython/jit/backend/llsupport/test/test_zrpy_gc_direct.py
--- a/rpython/jit/backend/llsupport/test/test_zrpy_gc_direct.py
+++ b/rpython/jit/backend/llsupport/test/test_zrpy_gc_direct.py
@@ -117,6 +117,11 @@
                 print 'fail'
             else:
                 print '???'
+            #
+            if token is token2:    # guard_gc_type
+                print int(cpu.get_actual_typeid(p0) == typeid_B)
+            if token is token3:    # guard_is_object
+                print int(cpu.check_is_object(p0))
 
     call_initial_function(t, g)
 
@@ -129,14 +134,14 @@
                     'match\n'
                     'fail\n'
 
-                    'fail\n'
-                    'match\n'
-                    'fail\n'
-                    'fail\n'
+                    'fail\n'  '0\n'
+                    'match\n' '1\n'
+                    'fail\n'  '0\n'
+                    'fail\n'  '0\n'
 
-                    'match\n'
-                    'match\n'
-                    'fail\n'
+                    'match\n' '1\n'
+                    'match\n' '1\n'
+                    'fail\n'  '0\n'
 
                     'fail\n'
                     'match\n'
diff --git a/rpython/jit/backend/test/runner_test.py 
b/rpython/jit/backend/test/runner_test.py
--- a/rpython/jit/backend/test/runner_test.py
+++ b/rpython/jit/backend/test/runner_test.py
@@ -4888,6 +4888,9 @@
         c_typeid = ConstInt(descr.get_type_id())
         self.execute_operation(rop.GUARD_GC_TYPE, [t_box, c_typeid], 'void')
         assert not self.guard_failed
+        #
+        got_typeid = self.cpu.get_actual_typeid(t_box.getref_base())
+        assert got_typeid == c_typeid.getint()
 
     def test_passing_guard_gc_type_array(self):
         if not self.cpu.supports_guard_gc_type:
@@ -4897,6 +4900,9 @@
         c_typeid = ConstInt(arraydescr.get_type_id())
         self.execute_operation(rop.GUARD_GC_TYPE, [a_box, c_typeid], 'void')
         assert not self.guard_failed
+        #
+        got_typeid = self.cpu.get_actual_typeid(a_box.getref_base())
+        assert got_typeid == c_typeid.getint()
 
     def test_failing_guard_gc_type(self):
         if not self.cpu.supports_guard_gc_type:
@@ -4915,23 +4921,29 @@
                              ]:
             assert self.execute_operation(opname, args, 'void') == None
             assert self.guard_failed
+            #
+            got_typeid = self.cpu.get_actual_typeid(args[0].getref_base())
+            assert got_typeid != args[1].getint()
 
     def test_guard_is_object(self):
         if not self.cpu.supports_guard_gc_type:
             py.test.skip("guard_gc_type not available")
         t_box, _, _ = self.alloc_instance(self.T)
         self.execute_operation(rop.GUARD_IS_OBJECT, [t_box], 'void')
+        assert not self.guard_failed
+        assert self.cpu.check_is_object(t_box.getref_base())
         #
-        assert not self.guard_failed
         a_box, _ = self.alloc_array_of(rffi.SHORT, 342)
         self.execute_operation(rop.GUARD_IS_OBJECT, [a_box], 'void')
         assert self.guard_failed
+        assert not self.cpu.check_is_object(a_box.getref_base())
         #
         S = lltype.GcStruct('S')
         s = lltype.malloc(S, immortal=True, zero=True)
         s_box = InputArgRef(lltype.cast_opaque_ptr(llmemory.GCREF, s))
         self.execute_operation(rop.GUARD_IS_OBJECT, [s_box], 'void')
         assert self.guard_failed
+        assert not self.cpu.check_is_object(s_box.getref_base())
 
     def test_guard_subclass(self):
         if not self.cpu.supports_guard_gc_type:
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to