[pypy-commit] pypy optresult-unroll: Implement and test guard_subclass.

arigo noreply at buildbot.pypy.org
Fri Sep 4 15:06:36 CEST 2015


Author: Armin Rigo <arigo at tunes.org>
Branch: optresult-unroll
Changeset: r79419:17252241ecf0
Date: 2015-09-04 14:09 +0100
http://bitbucket.org/pypy/pypy/changeset/17252241ecf0/

Log:	Implement and test guard_subclass.

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
@@ -693,6 +693,17 @@
             expected_typeid >>= 2
         return expected_typeid
 
+    def get_translated_info_for_typeinfo(self):
+        from rpython.memory.gctypelayout import GCData
+        type_info_group = llop.gc_get_type_info_group(llmemory.Address)
+        type_info_group = rffi.cast(lltype.Signed, type_info_group)
+        if WORD == 4:
+            shift_by = 2
+        elif WORD == 8:
+            shift_by = 0
+        sizeof_ti = rffi.sizeof(GCData.TYPE_INFO)
+        return (type_info_group, shift_by, sizeof_ti)
+
     def _setup_guard_is_object(self):
         from rpython.memory.gctypelayout import GCData, T_IS_RPYTHON_INSTANCE
         self._infobits_offset, _ = symbolic.get_field_token(GCData.TYPE_INFO,
@@ -700,16 +711,8 @@
         self._T_IS_RPYTHON_INSTANCE = T_IS_RPYTHON_INSTANCE
 
     def get_translated_info_for_guard_is_object(self):
-        type_info_group = llop.gc_get_type_info_group(llmemory.Address)
-        type_info_group = rffi.cast(lltype.Signed, type_info_group)
         infobits_offset = rffi.cast(lltype.Signed, self._infobits_offset)
-        if WORD == 4:
-            shift_by = 2
-        elif WORD == 8:
-            shift_by = 0
-        return (type_info_group + infobits_offset,
-                shift_by,
-                self._T_IS_RPYTHON_INSTANCE)
+        return (infobits_offset, self._T_IS_RPYTHON_INSTANCE)
 
 
 # ____________________________________________________________
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
@@ -54,6 +54,8 @@
             self.vtable_offset, _ = symbolic.get_field_token(rclass.OBJECT,
                                                              'typeptr',
                                                         translate_support_code)
+        self.subclassrange_min_offset, _ = symbolic.get_field_token(
+            rclass.OBJECT_VTABLE, 'subclassrange_min', translate_support_code)
         if translate_support_code:
             self._setup_exception_handling_translated()
         else:
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
@@ -72,14 +72,24 @@
     """, namespace={'finaldescr': finaldescr,
                     'faildescr': faildescr})
 
+    loop4 = parse("""
+    [p0]
+    guard_subclass(p0, ConstInt(vtable_B), descr=faildescr) []
+    finish(descr=finaldescr)
+    """, namespace={'finaldescr': finaldescr,
+                    'faildescr': faildescr,
+                    'vtable_B': vtable_B})
+
     def g():
         cpu.setup_once()
         token1 = JitCellToken()
         token2 = JitCellToken()
         token3 = JitCellToken()
+        token4 = JitCellToken()
         cpu.compile_loop(loop1.inputargs, loop1.operations, token1)
         cpu.compile_loop(loop2.inputargs, loop2.operations, token2)
         cpu.compile_loop(loop3.inputargs, loop3.operations, token3)
+        cpu.compile_loop(loop4.inputargs, loop4.operations, token4)
 
         for token, p0 in [
                 (token1, rffi.cast(llmemory.GCREF, A())),
@@ -94,6 +104,10 @@
                 (token3, rffi.cast(llmemory.GCREF, A())),
                 (token3, rffi.cast(llmemory.GCREF, B())),
                 (token3, rffi.cast(llmemory.GCREF, [44, 45])),
+
+                (token4, rffi.cast(llmemory.GCREF, A())),
+                (token4, rffi.cast(llmemory.GCREF, B())),
+                (token4, rffi.cast(llmemory.GCREF, C())),
                 ]:
             frame = execute_token(token, p0)
             descr = cpu.get_latest_descr(frame)
@@ -122,7 +136,11 @@
 
                     'match\n'
                     'match\n'
-                    'fail\n')
+                    'fail\n'
+
+                    'fail\n'
+                    'match\n'
+                    'match\n')
 
 
 def test_guards_translated_with_gctypeptr():
diff --git a/rpython/jit/backend/x86/assembler.py b/rpython/jit/backend/x86/assembler.py
--- a/rpython/jit/backend/x86/assembler.py
+++ b/rpython/jit/backend/x86/assembler.py
@@ -11,6 +11,7 @@
 from rpython.rtyper.lltypesystem import lltype, rffi, rstr, llmemory
 from rpython.rtyper.lltypesystem.lloperation import llop
 from rpython.rtyper.annlowlevel import llhelper, cast_instance_to_gcref
+from rpython.rtyper import rclass
 from rpython.rlib.jit import AsmInfo
 from rpython.jit.backend.model import CompiledLoopToken
 from rpython.jit.backend.x86.regalloc import (RegAlloc, get_ebp_ofs,
@@ -1786,17 +1787,58 @@
         [loc_object, loc_typeid] = locs
         # idea: read the typeid, fetch the field 'infobits' from the big
         # typeinfo table, and check the flag 'T_IS_RPYTHON_INSTANCE'.
-        base_type_info, shift_by, IS_OBJECT_FLAG = (
-            self.cpu.gc_ll_descr.get_translated_info_for_guard_is_object())
         if IS_X86_32:
             self.mc.MOVZX16(loc_typeid, mem(loc_object, 0))
         else:
             self.mc.MOV32(loc_typeid, mem(loc_object, 0))
-        loc_infobits = addr_add(imm(base_type_info), loc_typeid, scale=shift_by)
+        #
+        base_type_info, shift_by, sizeof_ti = (
+            self.cpu.gc_ll_descr.get_translated_info_for_typeinfo())
+        infobits_offset, IS_OBJECT_FLAG = (
+            self.cpu.gc_ll_descr.get_translated_info_for_guard_is_object())
+        loc_infobits = addr_add(imm(base_type_info), loc_typeid,
+                                scale=shift_by, offset=infobits_offset)
         self.mc.TEST(loc_infobits, imm(IS_OBJECT_FLAG))
         #
         self.implement_guard(guard_token, 'Z')
 
+    def genop_guard_guard_subclass(self, op, guard_op,
+                                   guard_token, locs, ign_2):
+        assert self.cpu.supports_guard_gc_type
+        [loc_object, loc_check_against_class, loc_tmp] = locs
+        assert isinstance(loc_object, RegLoc)
+        assert isinstance(loc_tmp, RegLoc)
+        offset = self.cpu.vtable_offset
+        offset2 = self.cpu.subclassrange_min_offset
+        if offset is not None:
+            # read this field to get the vtable pointer
+            self.mc.MOV_rm(loc_tmp.value, (loc_object.value, offset))
+            # read the vtable's subclassrange_min field
+            self.mc.MOV_rm(loc_tmp.value, (loc_tmp.value, offset2))
+        else:
+            # read the typeid
+            if IS_X86_32:
+                self.mc.MOVZX16(loc_tmp, mem(loc_object, 0))
+            else:
+                self.mc.MOV32(loc_tmp, mem(loc_object, 0))
+            # read the vtable's subclassrange_min field, as a single
+            # step with the correct offset
+            base_type_info, shift_by, sizeof_ti = (
+                self.cpu.gc_ll_descr.get_translated_info_for_typeinfo())
+            self.mc.MOV(loc_tmp, addr_add(imm(base_type_info), loc_tmp,
+                                          scale = shift_by,
+                                          offset = sizeof_ti + offset2))
+        # get the two bounds to check against
+        vtable_ptr = loc_check_against_class.getint()
+        vtable_ptr = rffi.cast(rclass.CLASSTYPE, vtable_ptr)
+        check_min = vtable_ptr.subclassrange_min
+        check_max = vtable_ptr.subclassrange_max
+        # check by doing the unsigned comparison (tmp - min) < (max - min)
+        self.mc.SUB_ri(loc_tmp.value, check_min)
+        self.mc.CMP_ri(loc_tmp.value, check_max - check_min)
+        # the guard fails if we get a "not below" result
+        self.implement_guard(guard_token, 'NB')
+
     def implement_guard_recovery(self, guard_opnum, faildescr, failargs,
                                  fail_locs, frame_depth):
         exc = (guard_opnum == rop.GUARD_EXCEPTION or
diff --git a/rpython/jit/backend/x86/regalloc.py b/rpython/jit/backend/x86/regalloc.py
--- a/rpython/jit/backend/x86/regalloc.py
+++ b/rpython/jit/backend/x86/regalloc.py
@@ -438,7 +438,12 @@
         self.perform_guard(op, [x, y], None)
 
     def consider_guard_subclass(self, op):
-        assert 0 # xxx
+        x = self.make_sure_var_in_reg(op.getarg(0))
+        y = self.loc(op.getarg(1))
+        tmp_box = TempVar()
+        z = self.rm.force_allocate_reg(tmp_box)
+        self.rm.possibly_free_var(tmp_box)
+        self.perform_guard(op, [x, y, z], None)
 
     def _consider_binop_part(self, op, symm=False):
         x = op.getarg(0)


More information about the pypy-commit mailing list