Carl Friedrich Bolz avatar Carl Friedrich Bolz committed 27316db Merge

merge foldable-getarrayitem-indexerror: constant-fold reads out of constant
applevel tuples

Comments (0)

Files changed (5)

pypy/doc/whatsnew-head.rst

 speeds up list.append() and list.pop().
 
 .. branch: curses_fixes
+
+.. branch: foldable-getarrayitem-indexerror
+Constant-fold reading out of constant tuples in PyPy.
+

pypy/module/pypyjit/test_pypy_c/test_containers.py

         opnames = log.opnames(loop.allops())
         assert opnames.count('new_with_vtable') == 0
 
+    def test_constfold_tuple(self):
+        code = """if 1:
+        tup = tuple(range(10000))
+        l = [1, 2, 3, 4, 5, 6, "a"]
+        def main(n):
+            while n > 0:
+                sub = tup[1]  # ID: getitem
+                l[1] = n # kill cache of tup[1]
+                n -= sub
+        """
+        log = self.run(code, [1000])
+        loop, = log.loops_by_filename(self.filepath)
+        ops = loop.ops_by_id('getitem', include_guard_not_invalidated=False)
+        assert log.opnames(ops) == []
+
+
     def test_specialised_tuple(self):
         def main(n):
             import pypyjit

rpython/jit/metainterp/test/test_immutable.py

         self.check_operations_history(getfield_gc=0, getfield_gc_pure=1,
                             getarrayitem_gc=0, getarrayitem_gc_pure=1)
 
+    def test_array_index_error(self):
+        class X(object):
+            _immutable_fields_ = ["y[*]"]
+
+            def __init__(self, x):
+                self.y = x
+
+            def get(self, index):
+                try:
+                    return self.y[index]
+                except IndexError:
+                    return -41
+
+        def f(index):
+            l = [1, 2, 3, 4]
+            l[2] = 30
+            a = escape(X(l))
+            return a.get(index)
+        res = self.interp_operations(f, [2], listops=True)
+        assert res == 30
+        self.check_operations_history(getfield_gc=0, getfield_gc_pure=1,
+                            getarrayitem_gc=0, getarrayitem_gc_pure=1)
 
     def test_array_in_immutable(self):
         class X(object):

rpython/rtyper/rlist.py

         v_lst, v_index = hop.inputargs(r_lst, Signed)
         if checkidx:
             hop.exception_is_here()
+            spec = dum_checkidx
         else:
+            spec = dum_nocheck
             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)
+        if hop.args_s[0].listdef.listitem.mutated:
+            basegetitem = ll_getitem_fast
         else:
-            # this is the 'foldable' version, which is not used when
-            # we check for IndexError
-            if hop.args_s[1].nonneg:
-                llfn = ll_getitem_foldable_nonneg
-            else:
-                llfn = ll_getitem_foldable
-            v_res = hop.gendirectcall(llfn, v_lst, v_index)
+            basegetitem = ll_getitem_foldable_nonneg
+
+        if hop.args_s[1].nonneg:
+            llfn = ll_getitem_nonneg
+        else:
+            llfn = ll_getitem
+        c_func_marker = hop.inputconst(Void, spec)
+        c_basegetitem = hop.inputconst(Void, basegetitem)
+        v_res = hop.gendirectcall(llfn, c_func_marker, c_basegetitem, v_lst, v_index)
         return r_lst.recast(hop.llops, v_res)
 
     rtype_getitem_key = rtype_getitem
         i += 1
         length_1_i -= 1
 
-def ll_getitem_nonneg(func, l, index):
+def ll_getitem_nonneg(func, basegetitem, l, index):
     ll_assert(index >= 0, "unexpectedly negative list getitem index")
     if func is dum_checkidx:
         if index >= l.ll_length():
             raise IndexError
-    return l.ll_getitem_fast(index)
+    return basegetitem(l, index)
 ll_getitem_nonneg._always_inline_ = True
 # no oopspec -- the function is inlined by the JIT
 
-def ll_getitem(func, l, index):
+def ll_getitem(func, basegetitem, l, index):
     if func is dum_checkidx:
         length = l.ll_length()    # common case: 0 <= index < length
         if r_uint(index) >= r_uint(length):
         if index < 0:
             index += l.ll_length()
             ll_assert(index >= 0, "negative list getitem index out of bound")
+    return basegetitem(l, index)
+# no oopspec -- the function is inlined by the JIT
+
+def ll_getitem_fast(l, index):
     return l.ll_getitem_fast(index)
-# no oopspec -- the function is inlined by the JIT
+ll_getitem_fast._always_inline_ = True
 
 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(l, index):
-    if index < 0:
-        index += l.ll_length()
-    return ll_getitem_foldable_nonneg(l, index)
-ll_getitem_foldable._always_inline_ = True
-# 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:

rpython/rtyper/test/test_rlist.py

 from rpython.translator.translator import TranslationContext
 
 
-# undo the specialization parameter
+# undo the specialization parameters
 for n1 in 'get set del'.split():
+    if n1 == "get":
+        extraarg = "ll_getitem_fast, "
+    else:
+        extraarg = ""
     for n2 in '', '_nonneg':
         name = 'll_%sitem%s' % (n1, n2)
         globals()['_' + name] = globals()[name]
         exec """if 1:
             def %s(*args):
-                return _%s(dum_checkidx, *args)
-""" % (name, name)
+                return _%s(dum_checkidx, %s*args)
+""" % (name, name, extraarg)
 del n1, n2, name
 
 
             block = graph.startblock
             op = block.operations[-1]
             assert op.opname == 'direct_call'
-            func = op.args[0].value._obj._callable
+            func = op.args[2].value
             assert ('foldable' in func.func_name) == \
                    ("y[*]" in immutable_fields)
 
         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
+        func1 = lst1_getitem_op.args[2].value
+        func2 = lst2_getitem_op.args[2].value
         assert func1.oopspec == 'list.getitem_foldable(l, index)'
         assert not hasattr(func2, 'oopspec')
 
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.