Commits

Alex Gaynor committed 9048883

Special case _resize_ge() on a virtual resizable list.

  • Participants
  • Parent commits 5232aa2
  • Branches jit-resizable-list

Comments (0)

Files changed (6)

pypy/jit/codewriter/effectinfo.py

     #
     OS_MATH_SQRT                = 100
 
+    OS_LIST_RESIZE_GE           = 120
+
     def __new__(cls, readonly_descrs_fields,
                 write_descrs_fields, write_descrs_arrays,
                 extraeffect=EF_CAN_RAISE,

pypy/jit/codewriter/jtransform.py

     do_resizable_void_list_getitem_foldable = do_resizable_void_list_getitem
     do_resizable_void_list_setitem = do_resizable_void_list_getitem
 
+    def do_resizable_list__resize_ge(self, op, args, arraydescr, lengthdescr,
+                                     itemsdescr, structdescr):
+        return self._handle_oopspec_call(op, args, EffectInfo.OS_LIST_RESIZE_GE)
+
+
     # ----------
     # Strings and Unicodes.
 

pypy/jit/metainterp/optimizeopt/rewrite.py

 from pypy.jit.metainterp.history import ConstInt
 from pypy.jit.metainterp.optimizeutil import _findall
 from pypy.jit.metainterp.resoperation import rop, ResOperation
-from pypy.jit.codewriter.effectinfo import EffectInfo
 from pypy.jit.metainterp.optimizeopt.intutils import IntBound
 from pypy.rlib.rarithmetic import highest_bit
 
 ##            return
 ##        self.emit_operation(op)
 
-    def optimize_CALL(self, op):
-        # dispatch based on 'oopspecindex' to a method that handles
-        # specifically the given oopspec call.  For non-oopspec calls,
-        # oopspecindex is just zero.
-        effectinfo = op.getdescr().get_extra_info()
-        if effectinfo is not None:
-            oopspecindex = effectinfo.oopspecindex
-            if oopspecindex == EffectInfo.OS_ARRAYCOPY:
-                if self._optimize_CALL_ARRAYCOPY(op):
-                    return
-        self.emit_operation(op)
-
-    def _optimize_CALL_ARRAYCOPY(self, op):
-        source_value = self.getvalue(op.getarg(1))
-        dest_value = self.getvalue(op.getarg(2))
-        source_start_box = self.get_constant_box(op.getarg(3))
-        dest_start_box = self.get_constant_box(op.getarg(4))
-        length = self.get_constant_box(op.getarg(5))
-        if (source_value.is_virtual() and source_start_box and dest_start_box
-            and length and dest_value.is_virtual()):
-            # XXX optimize the case where dest value is not virtual,
-            #     but we still can avoid a mess
-            source_start = source_start_box.getint()
-            dest_start = dest_start_box.getint()
-            for index in range(length.getint()):
-                val = source_value.getitem(index + source_start)
-                dest_value.setitem(index + dest_start, val)
-            return True
-        if length and length.getint() == 0:
-            return True # 0-length arraycopy
-        return False
-
     def optimize_INT_FLOORDIV(self, op):
         v1 = self.getvalue(op.getarg(0))
         v2 = self.getvalue(op.getarg(1))

pypy/jit/metainterp/optimizeopt/virtualize.py

+from pypy.jit.codewriter.effectinfo import EffectInfo
+from pypy.jit.codewriter.heaptracker import vtable2descr
+from pypy.jit.metainterp.executor import execute
 from pypy.jit.metainterp.history import Const, ConstInt, BoxInt
 from pypy.jit.metainterp.resoperation import rop, ResOperation
-from pypy.jit.metainterp.optimizeutil import _findall, sort_descrs
-from pypy.jit.metainterp.optimizeutil import descrlist_dict
+from pypy.jit.metainterp.optimizeopt import optimizer
+from pypy.jit.metainterp.optimizeutil import _findall, sort_descrs, descrlist_dict
 from pypy.rlib.objectmodel import we_are_translated
-from pypy.jit.metainterp.optimizeopt import optimizer
-from pypy.jit.metainterp.executor import execute
-from pypy.jit.codewriter.heaptracker import vtable2descr
 
 
 class AbstractVirtualValue(optimizer.OptValue):
         assert isinstance(itemvalue, optimizer.OptValue)
         self._items[index] = itemvalue
 
+    def resize(self, newsize):
+        assert newsize >= 0
+        # The current items up to newsize (if we're growing that's the full
+        # current list), plus as many new items as need (if we're shrinking
+        # that's [self.constvalue] * negative_value, aka an empty list)
+        self._items = self._items[:newsize] + [self.constvalue] * (newsize - len(self._items))
+        # Change source_op, if we are forced it is emitted directly.
+        self.source_op = self.source_op.copy_and_change(
+            self.source_op.getopnum(), args=[ConstInt(newsize)]
+        )
+
     def _really_force(self):
         assert self.source_op is not None
         if not we_are_translated():
         self.make_equal_to(box, vvalue)
         return vvalue
 
+    def optimize_CALL(self, op):
+        # dispatch based on 'oopspecindex' to a method that handles
+        # specifically the given oopspec call.  For non-oopspec calls,
+        # oopspecindex is just zero.
+        effectinfo = op.getdescr().get_extra_info()
+        if effectinfo is not None:
+            oopspecindex = effectinfo.oopspecindex
+            if oopspecindex == EffectInfo.OS_ARRAYCOPY:
+                if self._optimize_CALL_ARRAYCOPY(op):
+                    return
+            elif oopspecindex == EffectInfo.OS_LIST_RESIZE_GE:
+                if self._optimize_CALL_LIST_RESIZE_GE(op):
+                    return
+        self.emit_operation(op)
+
     def optimize_VIRTUAL_REF(self, op):
         indexbox = op.getarg(1)
         #
         ###self.heap_op_optimizer.optimize_SETARRAYITEM_GC(op, value, fieldvalue)
         self.emit_operation(op)
 
+    def _optimize_CALL_ARRAYCOPY(self, op):
+        source_value = self.getvalue(op.getarg(1))
+        dest_value = self.getvalue(op.getarg(2))
+        source_start_box = self.get_constant_box(op.getarg(3))
+        dest_start_box = self.get_constant_box(op.getarg(4))
+        length = self.get_constant_box(op.getarg(5))
+        if (source_value.is_virtual() and source_start_box and dest_start_box
+            and length and dest_value.is_virtual()):
+            # XXX optimize the case where dest value is not virtual,
+            #     but we still can avoid a mess
+            source_start = source_start_box.getint()
+            dest_start = dest_start_box.getint()
+            for index in range(length.getint()):
+                val = source_value.getitem(index + source_start)
+                dest_value.setitem(index + dest_start, val)
+            return True
+        if length and length.getint() == 0:
+            return True # 0-length arraycopy
+        return False
+
+    def _optimize_CALL_LIST_RESIZE_GE(self, op):
+        list_value = self.getvalue(op.getarg(1))
+        newsize_value = self.getvalue(op.getarg(2))
+        newsize_box = self.get_constant_box(op.getarg(2))
+
+        if list_value.is_virtual() and newsize_box:
+            # XXX: EVIL HACKS BEGIN HERE
+            length_descr, items_descr = list_value._get_field_descr_list()
+            # XXX: EVIL HACKS END HERE
+            arrayitems = list_value.getfield(items_descr, None)
+            if arrayitems and arrayitems.is_virtual():
+                assert isinstance(arrayitems, VArrayValue)
+                newsize = newsize_box.getint()
+                arrayitems.resize(newsize)
+                list_value.setfield(length_descr, newsize_value)
+                return True
+        return False
+
     def propagate_forward(self, op):
         opnum = op.getopnum()
         for value, func in optimize_ops:

pypy/jit/metainterp/test/test_list.py

                 l = [x + 1]
                 n -= 1
             return l[0]
-        
+
         res = self.meta_interp(f, [10], listops=True)
         assert res == f(10)
         self.check_all_virtualized()
 
     def test_ll_fixed_setitem_fast(self):
         jitdriver = JitDriver(greens = [], reds = ['n', 'l'])
-        
+
         def f(n):
             l = [1, 2, 3]
 
         assert res == f(10)
         py.test.skip("'[non-null] * n' gives a residual call so far")
         self.check_loops(setarrayitem_gc=0, getarrayitem_gc=0, call=0)
-    
+
     def test_arraycopy_simpleoptimize(self):
         def f():
             l = [1, 2, 3, 4]
         assert res == f(15)
         self.check_loops(guard_exception=0)
 
+    def test_virtual_resize(self):
+        jitdriver = JitDriver(greens = [], reds = ['n', 's'])
+        def f(n):
+            s = 0
+            while n > 0:
+                jitdriver.jit_merge_point(n=n, s=s)
+                lst = []
+                lst += [1]
+                n -= len(lst)
+                s += lst[0]
+            return s
+        res = self.meta_interp(f, [15], listops=True)
+        assert res == f(15)
+        self.check_loops({"int_add": 1, "int_sub": 1, "int_gt": 1,
+                          "guard_true": 1, "jump": 1})
+
+
 class TestOOtype(ListTests, OOJitMixin):
     pass
 

pypy/jit/metainterp/test/test_slist.py

 class ListTests(object):
 
     def test_basic_list(self):
-        py.test.skip("not yet")
         myjitdriver = JitDriver(greens = [], reds = ['n', 'lst'])
         def f(n):
             lst = []
             return x
         res = self.meta_interp(f, [-2], listops=True)
         assert res == 41
-        self.check_loops(call=1, guard_value=0)
+        self.check_loops(call=0, guard_value=0)
 
 # we don't support resizable lists on ootype
 #class TestOOtype(ListTests, OOJitMixin):