[pypy-svn] r78924 - in pypy/branch/rlist-jit/pypy: jit/codewriter jit/codewriter/test jit/metainterp/test rpython rpython/test

arigo at codespeak.net arigo at codespeak.net
Tue Nov 9 15:51:43 CET 2010


Author: arigo
Date: Tue Nov  9 15:51:41 2010
New Revision: 78924

Modified:
   pypy/branch/rlist-jit/pypy/jit/codewriter/jtransform.py
   pypy/branch/rlist-jit/pypy/jit/codewriter/test/test_list.py
   pypy/branch/rlist-jit/pypy/jit/codewriter/test/test_void_list.py
   pypy/branch/rlist-jit/pypy/jit/metainterp/test/test_list.py
   pypy/branch/rlist-jit/pypy/rpython/rlist.py
   pypy/branch/rlist-jit/pypy/rpython/test/test_rlist.py
Log:
Not really a complete clean-up, but good enough to make
one new test in jit/metainterp/test/test_list.py pass.


Modified: pypy/branch/rlist-jit/pypy/jit/codewriter/jtransform.py
==============================================================================
--- pypy/branch/rlist-jit/pypy/jit/codewriter/jtransform.py	(original)
+++ pypy/branch/rlist-jit/pypy/jit/codewriter/jtransform.py	Tue Nov  9 15:51:41 2010
@@ -924,21 +924,19 @@
         # base hints on the name of the ll function, which is a bit xxx-ish
         # but which is safe for now
         assert func.func_name.startswith('ll_')
+        # check that we have carefully placed the oopspec in
+        # pypy/rpython/rlist.py.  There should not be an oopspec on
+        # a ll_getitem or ll_setitem that expects a 'func' argument.
+        # The idea is that a ll_getitem/ll_setitem with dum_checkidx
+        # should get inlined by the JIT, so that we see the potential
+        # 'raise IndexError'.
+        assert 'func' not in func.func_code.co_varnames
         non_negative = '_nonneg' in func.func_name
         fast = '_fast' in func.func_name
-        if fast:
-            can_raise = False
-            non_negative = True
-        else:
-            tag = op.args[1].value
-            assert tag in (rlist.dum_nocheck, rlist.dum_checkidx)
-            can_raise = tag != rlist.dum_nocheck
-        return non_negative, can_raise
+        return non_negative or fast
 
     def _prepare_list_getset(self, op, descr, args, checkname):
-        non_negative, can_raise = self._get_list_nonneg_canraise_flags(op)
-        if can_raise:
-            raise NotSupported("list operation can raise")
+        non_negative = self._get_list_nonneg_canraise_flags(op)
         if non_negative:
             return args[1], []
         else:
@@ -950,9 +948,8 @@
             return v_posindex, [op0, op1]
 
     def _prepare_void_list_getset(self, op):
-        non_negative, can_raise = self._get_list_nonneg_canraise_flags(op)
-        if can_raise:
-            raise NotSupported("list operation can raise")
+        # sanity check:
+        self._get_list_nonneg_canraise_flags(op)
 
     def _get_initial_newlist_length(self, op, args):
         # normalize number of arguments to the 'newlist' function

Modified: pypy/branch/rlist-jit/pypy/jit/codewriter/test/test_list.py
==============================================================================
--- pypy/branch/rlist-jit/pypy/jit/codewriter/test/test_list.py	(original)
+++ pypy/branch/rlist-jit/pypy/jit/codewriter/test/test_list.py	Tue Nov  9 15:51:41 2010
@@ -56,9 +56,8 @@
     if '/' in oopspec_name:
         oopspec_name, property = oopspec_name.split('/')
         def force_flags(op):
-            if property == 'NONNEG':   return True, False
-            if property == 'NEG':      return False, False
-            if property == 'CANRAISE': return False, True
+            if property == 'NONNEG':   return True
+            if property == 'NEG':      return False
             raise ValueError(property)
         tr._get_list_nonneg_canraise_flags = force_flags
     op = SpaceOperation('direct_call',
@@ -122,9 +121,6 @@
                      check_neg_index %r0, <ArrayDescr>, %i0 -> %i1
                      getarrayitem_gc_i %r0, <ArrayDescr>, %i1 -> %i2
                  """)
-    builtin_test('list.getitem/CANRAISE',
-                 [varoftype(FIXEDLIST), varoftype(lltype.Signed)],
-                 lltype.Signed, NotSupported)
 
 def test_fixed_getitem_foldable():
     builtin_test('list.getitem_foldable/NONNEG',
@@ -139,9 +135,6 @@
                      check_neg_index %r0, <ArrayDescr>, %i0 -> %i1
                      getarrayitem_gc_pure_i %r0, <ArrayDescr>, %i1 -> %i2
                  """)
-    builtin_test('list.getitem_foldable/CANRAISE',
-                 [varoftype(FIXEDLIST), varoftype(lltype.Signed)],
-                 lltype.Signed, NotSupported)
 
 def test_fixed_setitem():
     builtin_test('list.setitem/NONNEG', [varoftype(FIXEDLIST),
@@ -158,10 +151,6 @@
                      check_neg_index %r0, <ArrayDescr>, %i0 -> %i1
                      setarrayitem_gc_i %r0, <ArrayDescr>, %i1, %i2
                  """)
-    builtin_test('list.setitem/CANRAISE', [varoftype(FIXEDLIST),
-                                           varoftype(lltype.Signed),
-                                           varoftype(lltype.Signed)],
-                 lltype.Void, NotSupported)
 
 def test_fixed_len():
     builtin_test('list.len', [varoftype(FIXEDLIST)], lltype.Signed,
@@ -206,9 +195,6 @@
         check_resizable_neg_index %r0, <FieldDescr length>, %i0 -> %i1
         getlistitem_gc_i %r0, <FieldDescr items>, <ArrayDescr>, %i1 -> %i2
                  """)
-    builtin_test('list.getitem/CANRAISE',
-                 [varoftype(VARLIST), varoftype(lltype.Signed)],
-                 lltype.Signed, NotSupported)
 
 def test_resizable_setitem():
     builtin_test('list.setitem/NONNEG', [varoftype(VARLIST),
@@ -225,10 +211,6 @@
         check_resizable_neg_index %r0, <FieldDescr length>, %i0 -> %i1
         setlistitem_gc_i %r0, <FieldDescr items>, <ArrayDescr>, %i1, %i2
                  """)
-    builtin_test('list.setitem/CANRAISE', [varoftype(VARLIST),
-                                           varoftype(lltype.Signed),
-                                           varoftype(lltype.Signed)],
-                 lltype.Void, NotSupported)
 
 def test_resizable_len():
     builtin_test('list.len', [varoftype(VARLIST)], lltype.Signed,

Modified: pypy/branch/rlist-jit/pypy/jit/codewriter/test/test_void_list.py
==============================================================================
--- pypy/branch/rlist-jit/pypy/jit/codewriter/test/test_void_list.py	(original)
+++ pypy/branch/rlist-jit/pypy/jit/codewriter/test/test_void_list.py	Tue Nov  9 15:51:41 2010
@@ -51,9 +51,6 @@
     builtin_test('list.getitem/NEG',
                  [varoftype(FIXEDLIST), varoftype(lltype.Signed)],
                  lltype.Void, "")
-    builtin_test('list.getitem/CANRAISE',
-                 [varoftype(FIXEDLIST), varoftype(lltype.Signed)],
-                 lltype.Void, NotSupported)
 
 def test_fixed_getitem_foldable():
     builtin_test('list.getitem_foldable/NONNEG',
@@ -62,9 +59,6 @@
     builtin_test('list.getitem_foldable/NEG',
                  [varoftype(FIXEDLIST), varoftype(lltype.Signed)],
                  lltype.Void, "")
-    builtin_test('list.getitem_foldable/CANRAISE',
-                 [varoftype(FIXEDLIST), varoftype(lltype.Signed)],
-                 lltype.Void, NotSupported)
 
 def test_fixed_setitem():
     builtin_test('list.setitem/NONNEG', [varoftype(FIXEDLIST),
@@ -75,10 +69,6 @@
                                       varoftype(lltype.Signed),
                                       varoftype(lltype.Void)],
                  lltype.Void, "")
-    builtin_test('list.setitem/CANRAISE', [varoftype(FIXEDLIST),
-                                           varoftype(lltype.Signed),
-                                           varoftype(lltype.Void)],
-                 lltype.Void, NotSupported)
 
 def test_fixed_len():
     builtin_test('list.len', [varoftype(FIXEDLIST)], lltype.Signed,
@@ -115,9 +105,6 @@
     builtin_test('list.getitem/NEG',
                  [varoftype(VARLIST), varoftype(lltype.Signed)],
                  lltype.Void, "")
-    builtin_test('list.getitem/CANRAISE',
-                 [varoftype(VARLIST), varoftype(lltype.Signed)],
-                 lltype.Void, NotSupported)
 
 def test_resizable_setitem():
     builtin_test('list.setitem/NONNEG', [varoftype(VARLIST),
@@ -128,10 +115,6 @@
                                       varoftype(lltype.Signed),
                                       varoftype(lltype.Void)],
                  lltype.Void, "")
-    builtin_test('list.setitem/CANRAISE', [varoftype(VARLIST),
-                                           varoftype(lltype.Signed),
-                                           varoftype(lltype.Void)],
-                 lltype.Void, NotSupported)
 
 def test_resizable_len():
     builtin_test('list.len', [varoftype(VARLIST)], lltype.Signed,

Modified: pypy/branch/rlist-jit/pypy/jit/metainterp/test/test_list.py
==============================================================================
--- pypy/branch/rlist-jit/pypy/jit/metainterp/test/test_list.py	(original)
+++ pypy/branch/rlist-jit/pypy/jit/metainterp/test/test_list.py	Tue Nov  9 15:51:41 2010
@@ -188,6 +188,26 @@
         assert res == f(4)
         self.check_loops(call=0, getfield_gc=0)
 
+    def test_fold_indexerror(self):
+        jitdriver = JitDriver(greens = [], reds = ['total', 'n', 'lst'])
+        def f(n):
+            lst = []
+            total = 0
+            while n > 0:
+                jitdriver.can_enter_jit(lst=lst, n=n, total=total)
+                jitdriver.jit_merge_point(lst=lst, n=n, total=total)
+                lst.append(n)
+                try:
+                    total += lst[n]
+                except IndexError:
+                    total += 1000
+                n -= 1
+            return total
+
+        res = self.meta_interp(f, [15], listops=True)
+        assert res == f(15)
+        self.check_loops(guard_exception=0)
+
 class TestOOtype(ListTests, OOJitMixin):
     pass
 

Modified: pypy/branch/rlist-jit/pypy/rpython/rlist.py
==============================================================================
--- pypy/branch/rlist-jit/pypy/rpython/rlist.py	(original)
+++ pypy/branch/rlist-jit/pypy/rpython/rlist.py	Tue Nov  9 15:51:41 2010
@@ -9,7 +9,7 @@
 from pypy.rpython import robject
 from pypy.rlib.objectmodel import malloc_zero_filled
 from pypy.rlib.debug import ll_assert
-from pypy.rlib.rarithmetic import ovfcheck, widen
+from pypy.rlib.rarithmetic import ovfcheck, widen, r_uint
 from pypy.rpython.annlowlevel import ADTInterface
 from pypy.rlib import rgc
 
@@ -241,17 +241,22 @@
 class __extend__(pairtype(AbstractBaseListRepr, IntegerRepr)):
 
     def rtype_getitem((r_lst, r_int), hop, checkidx=False):
+        v_lst, v_index = hop.inputargs(r_lst, Signed)
         if checkidx:
-            spec = dum_checkidx
+            hop.exception_is_here()
         else:
-            spec = dum_nocheck
-        v_func = hop.inputconst(Void, spec)
-        v_lst, v_index = hop.inputargs(r_lst, Signed)
+            hop.exception_cannot_occur()
         if hop.args_s[0].listdef.listitem.mutated or checkidx:
             if hop.args_s[1].nonneg:
                 llfn = ll_getitem_nonneg
             else:
                 llfn = ll_getitem
+            if checkidx:
+                spec = dum_checkidx
+            else:
+                spec = dum_nocheck
+            c_func_marker = hop.inputconst(Void, spec)
+            v_res = hop.gendirectcall(llfn, c_func_marker, v_lst, v_index)
         else:
             # this is the 'foldable' version, which is not used when
             # we check for IndexError
@@ -259,11 +264,7 @@
                 llfn = ll_getitem_foldable_nonneg
             else:
                 llfn = ll_getitem_foldable
-        if checkidx:
-            hop.exception_is_here()
-        else:
-            hop.exception_cannot_occur()
-        v_res = hop.gendirectcall(llfn, v_func, v_lst, v_index)
+            v_res = hop.gendirectcall(llfn, v_lst, v_index)
         return r_lst.recast(hop.llops, v_res)
 
     rtype_getitem_key = rtype_getitem
@@ -538,12 +539,14 @@
             dest.ll_setitem_fast(dest_start + i, item)
             i += 1
 ll_arraycopy._annenforceargs_ = [None, None, int, int, int]
+# no oopspec -- the function is inlined by the JIT
 
 def ll_copy(RESLIST, l):
     length = l.ll_length()
     new_lst = RESLIST.ll_newlist(length)
     ll_arraycopy(l, new_lst, 0, 0, length)
     return new_lst
+# no oopspec -- the function is inlined by the JIT
 
 def ll_len(l):
     return l.ll_length()
@@ -551,6 +554,7 @@
 def ll_list_is_true(l):
     # check if a list is True, allowing for None
     return bool(l) and l.ll_length() != 0
+# no oopspec -- the function is inlined by the JIT
 
 def ll_len_foldable(l):
     return l.ll_length()
@@ -558,6 +562,7 @@
 
 def ll_list_is_true_foldable(l):
     return bool(l) and ll_len_foldable(l) != 0
+# no oopspec -- the function is inlined by the JIT
 
 def ll_append(l, newitem):
     length = l.ll_length()
@@ -588,6 +593,7 @@
     ll_arraycopy(l1, l, 0, 0, len1)
     ll_arraycopy(l2, l, 0, len1, len2)
     return l
+# no oopspec -- the function is inlined by the JIT
 
 def ll_insert_nonneg(l, index, newitem):
     length = l.ll_length()
@@ -674,60 +680,69 @@
         l.ll_setitem_fast(length_1_i, tmp)
         i += 1
         length_1_i -= 1
+ll_reverse.oopspec = 'list.reverse(l)'
 
 def ll_getitem_nonneg(func, l, index):
     ll_assert(index >= 0, "unexpectedly negative list getitem index")
     if func is dum_checkidx:
         if index >= l.ll_length():
             raise IndexError
-    else:
-        ll_assert(index < l.ll_length(), "list getitem index out of bound")
     return l.ll_getitem_fast(index)
-ll_getitem_nonneg.oopspec = 'list.getitem(l, index)'
+# no oopspec -- the function is inlined by the JIT
 
 def ll_getitem(func, l, index):
-    length = l.ll_length()
-    if index < 0:
-        index += length
     if func is dum_checkidx:
-        if index < 0 or index >= length:
-            raise IndexError
+        length = l.ll_length()    # common case: 0 <= index < length
+        if r_uint(index) >= r_uint(length):
+            # Failed, so either (-length <= index < 0), or we have to raise
+            # IndexError.  Using r_uint, the condition can be rewritten as
+            # (-length-1 < index), which is (~length < index).
+            if r_uint(~length) < r_uint(index):
+                index += length
+            else:
+                raise IndexError
     else:
-        ll_assert(index >= 0, "negative list getitem index out of bound")
-        ll_assert(index < length, "list getitem index out of bound")
+        # We don't want checking, but still want to support index < 0.
+        # Only call ll_length() if needed.
+        if index < 0:
+            index += l.ll_length()
+            ll_assert(index >= 0, "negative list getitem index out of bound")
     return l.ll_getitem_fast(index)
-ll_getitem.oopspec = 'list.getitem(l, index)'
+# no oopspec -- the function is inlined by the JIT
 
-def ll_getitem_foldable_nonneg(func, l, index):
-    return ll_getitem_nonneg(func, l, index)
+def ll_getitem_foldable_nonneg(l, index):
+    ll_assert(index >= 0, "unexpectedly negative list getitem index")
+    return l.ll_getitem_fast(index)
 ll_getitem_foldable_nonneg.oopspec = 'list.getitem_foldable(l, index)'
 
-def ll_getitem_foldable(func, l, index):
-    return ll_getitem(func, l, index)
-ll_getitem_foldable.oopspec = 'list.getitem_foldable(l, index)'
+def ll_getitem_foldable(l, index):
+    if index < 0:
+        index += l.ll_length()
+    return ll_getitem_foldable_nonneg(l, index)
+# no oopspec -- the function is inlined by the JIT
 
 def ll_setitem_nonneg(func, l, index, newitem):
     ll_assert(index >= 0, "unexpectedly negative list setitem index")
     if func is dum_checkidx:
         if index >= l.ll_length():
             raise IndexError
-    else:
-        ll_assert(index < l.ll_length(), "list setitem index out of bound")
     l.ll_setitem_fast(index, newitem)
-ll_setitem_nonneg.oopspec = 'list.setitem(l, index, newitem)'
+# no oopspec -- the function is inlined by the JIT
 
 def ll_setitem(func, l, index, newitem):
-    length = l.ll_length()
-    if index < 0:
-        index += length
     if func is dum_checkidx:
-        if index < 0 or index >= length:
-            raise IndexError
+        length = l.ll_length()
+        if r_uint(index) >= r_uint(length):   # see comments in ll_getitem().
+            if r_uint(~length) < r_uint(index):
+                index += length
+            else:
+                raise IndexError
     else:
-        ll_assert(index >= 0, "negative list setitem index out of bound")
-        ll_assert(index < length, "list setitem index out of bound")
+        if index < 0:
+            index += l.ll_length()
+            ll_assert(index >= 0, "negative list getitem index out of bound")
     l.ll_setitem_fast(index, newitem)
-ll_setitem.oopspec = 'list.setitem(l, index, newitem)'
+# no oopspec -- the function is inlined by the JIT
 
 def ll_delitem_nonneg(func, l, index):
     ll_assert(index >= 0, "unexpectedly negative list delitem index")
@@ -756,7 +771,7 @@
     if i < 0:
         i += length
     if func is dum_checkidx:
-        if i < 0 or i >= length:
+        if r_uint(i) >= r_uint(length):
             raise IndexError
     else:
         ll_assert(i >= 0, "negative list delitem index out of bound")
@@ -799,6 +814,7 @@
         lst.ll_setitem_fast(j, c)
         i += 1
         j += 1
+# not inlined by the JIT -- contains a loop
 
 def ll_extend_with_str_slice_startstop(lst, s, getstrlen, getstritem,
                                        start, stop):
@@ -824,6 +840,7 @@
         lst.ll_setitem_fast(j, c)
         i += 1
         j += 1
+# not inlined by the JIT -- contains a loop
 
 def ll_extend_with_str_slice_minusone(lst, s, getstrlen, getstritem):
     len1 = lst.ll_length()
@@ -843,6 +860,7 @@
         lst.ll_setitem_fast(j, c)
         i += 1
         j += 1
+# not inlined by the JIT -- contains a loop
 
 def ll_extend_with_char_count(lst, char, count):
     if count <= 0:
@@ -859,6 +877,7 @@
     while j < newlength:
         lst.ll_setitem_fast(j, char)
         j += 1
+# not inlined by the JIT -- contains a loop
 
 def ll_listslice_startonly(RESLIST, l1, start):
     len1 = l1.ll_length()
@@ -869,6 +888,7 @@
     ll_arraycopy(l1, l, start, 0, newlength)
     return l
 ll_listslice_startonly._annenforceargs_ = (None, None, int)
+# no oopspec -- the function is inlined by the JIT
 
 def ll_listslice_startstop(RESLIST, l1, start, stop):
     length = l1.ll_length()
@@ -881,6 +901,7 @@
     l = RESLIST.ll_newlist(newlength)
     ll_arraycopy(l1, l, start, 0, newlength)
     return l
+# no oopspec -- the function is inlined by the JIT
 
 def ll_listslice_minusone(RESLIST, l1):
     newlength = l1.ll_length() - 1
@@ -888,6 +909,7 @@
     l = RESLIST.ll_newlist(newlength)
     ll_arraycopy(l1, l, 0, 0, newlength)
     return l
+# no oopspec -- the function is inlined by the JIT
 
 def ll_listdelslice_startonly(l, start):
     ll_assert(start >= 0, "del l[start:] with unexpectedly negative start")
@@ -958,6 +980,7 @@
                 return False
         j += 1
     return True
+# not inlined by the JIT -- contains a loop
 
 def ll_listcontains(lst, obj, eqfn):
     lng = lst.ll_length()
@@ -971,6 +994,7 @@
                 return True
         j += 1
     return False
+# not inlined by the JIT -- contains a loop
 
 def ll_listindex(lst, obj, eqfn):
     lng = lst.ll_length()
@@ -984,6 +1008,7 @@
                 return j
         j += 1
     raise ValueError # can't say 'list.index(x): x not in list'
+# not inlined by the JIT -- contains a loop
 
 def ll_listremove(lst, obj, eqfn):
     index = ll_listindex(lst, obj, eqfn) # raises ValueError if obj not in lst
@@ -1030,3 +1055,4 @@
             i += 1
         j += length
     return res
+# not inlined by the JIT -- contains a loop

Modified: pypy/branch/rlist-jit/pypy/rpython/test/test_rlist.py
==============================================================================
--- pypy/branch/rlist-jit/pypy/rpython/test/test_rlist.py	(original)
+++ pypy/branch/rlist-jit/pypy/rpython/test/test_rlist.py	Tue Nov  9 15:51:41 2010
@@ -1420,14 +1420,15 @@
             lst2 = [i]
             lst2.append(42)    # mutated list
             return lst1[i] + lst2[i]
-        _, _, graph = self.gengraph(f, [int])
+        from pypy.annotation import model as annmodel
+        _, _, graph = self.gengraph(f, [annmodel.SomeInteger(nonneg=True)])
         block = graph.startblock
         lst1_getitem_op = block.operations[-3]     # XXX graph fishing
         lst2_getitem_op = block.operations[-2]
         func1 = lst1_getitem_op.args[0].value._obj._callable
         func2 = lst2_getitem_op.args[0].value._obj._callable
         assert func1.oopspec == 'list.getitem_foldable(l, index)'
-        assert func2.oopspec == 'list.getitem(l, index)'
+        assert not hasattr(func2, 'oopspec')
 
 class TestOOtype(BaseTestRlist, OORtypeMixin):
     rlist = oo_rlist



More information about the Pypy-commit mailing list