Author: Carl Friedrich Bolz <[email protected]>
Branch: 
Changeset: r45770:3f7ee4a5a25a
Date: 2011-07-20 13:46 +0200
http://bitbucket.org/pypy/pypy/changeset/3f7ee4a5a25a/

Log:    merge heap-caching-during-tracing:

        perform some very simple and straightforward heap caching while
        tracing. this brings down the JIT overhead considerable, making
        warmup faster.

diff --git a/pypy/jit/metainterp/pyjitpl.py b/pypy/jit/metainterp/pyjitpl.py
--- a/pypy/jit/metainterp/pyjitpl.py
+++ b/pypy/jit/metainterp/pyjitpl.py
@@ -390,8 +390,21 @@
 
     @arguments("box", "descr", "box")
     def _opimpl_getarrayitem_gc_any(self, arraybox, arraydescr, indexbox):
-        return self.execute_with_descr(rop.GETARRAYITEM_GC,
+        cache = self.metainterp.heap_array_cache.get(arraydescr, None)
+        if cache and isinstance(indexbox, ConstInt):
+            index = indexbox.getint()
+            frombox, tobox = cache.get(index, (None, None))
+            if frombox is arraybox:
+                return tobox
+        resbox = self.execute_with_descr(rop.GETARRAYITEM_GC,
                                        arraydescr, arraybox, indexbox)
+        if isinstance(indexbox, ConstInt):
+            if not cache:
+                cache = self.metainterp.heap_array_cache[arraydescr] = {}
+            index = indexbox.getint()
+            cache[index] = arraybox, resbox
+        return resbox
+
 
     opimpl_getarrayitem_gc_i = _opimpl_getarrayitem_gc_any
     opimpl_getarrayitem_gc_r = _opimpl_getarrayitem_gc_any
@@ -419,6 +432,13 @@
                                     indexbox, itembox):
         self.execute_with_descr(rop.SETARRAYITEM_GC, arraydescr, arraybox,
                                 indexbox, itembox)
+        if isinstance(indexbox, ConstInt):
+            cache = self.metainterp.heap_array_cache.setdefault(arraydescr, {})
+            cache[indexbox.getint()] = arraybox, itembox
+        else:
+            cache = self.metainterp.heap_array_cache.get(arraydescr, None)
+            if cache:
+                cache.clear()
 
     opimpl_setarrayitem_gc_i = _opimpl_setarrayitem_gc_any
     opimpl_setarrayitem_gc_r = _opimpl_setarrayitem_gc_any
@@ -454,21 +474,17 @@
     def opimpl_newlist(self, structdescr, lengthdescr, itemsdescr, arraydescr,
                        sizebox):
         sbox = self.metainterp.execute_and_record(rop.NEW, structdescr)
-        self.metainterp.execute_and_record(rop.SETFIELD_GC, lengthdescr,
-                                           sbox, sizebox)
+        self._opimpl_setfield_gc_any(sbox, lengthdescr, sizebox)
         abox = self.metainterp.execute_and_record(rop.NEW_ARRAY, arraydescr,
                                                   sizebox)
-        self.metainterp.execute_and_record(rop.SETFIELD_GC, itemsdescr,
-                                           sbox, abox)
+        self._opimpl_setfield_gc_any(sbox, itemsdescr, abox)
         return sbox
 
     @arguments("box", "descr", "descr", "box")
     def _opimpl_getlistitem_gc_any(self, listbox, itemsdescr, arraydescr,
                                    indexbox):
-        arraybox = self.metainterp.execute_and_record(rop.GETFIELD_GC,
-                                                      itemsdescr, listbox)
-        return self.execute_with_descr(rop.GETARRAYITEM_GC,
-                                       arraydescr, arraybox, indexbox)
+        arraybox = self._opimpl_getfield_gc_any(listbox, itemsdescr)
+        return self._opimpl_getarrayitem_gc_any(arraybox, arraydescr, indexbox)
 
     opimpl_getlistitem_gc_i = _opimpl_getlistitem_gc_any
     opimpl_getlistitem_gc_r = _opimpl_getlistitem_gc_any
@@ -477,10 +493,9 @@
     @arguments("box", "descr", "descr", "box", "box")
     def _opimpl_setlistitem_gc_any(self, listbox, itemsdescr, arraydescr,
                                    indexbox, valuebox):
-        arraybox = self.metainterp.execute_and_record(rop.GETFIELD_GC,
-                                                      itemsdescr, listbox)
-        self.execute_with_descr(rop.SETARRAYITEM_GC, arraydescr, arraybox,
-                                indexbox, valuebox)
+        arraybox = self._opimpl_getfield_gc_any(listbox, itemsdescr)
+        self._opimpl_setarrayitem_gc_any(arraybox, arraydescr, indexbox,
+                                         valuebox)
 
     opimpl_setlistitem_gc_i = _opimpl_setlistitem_gc_any
     opimpl_setlistitem_gc_r = _opimpl_setlistitem_gc_any
@@ -502,18 +517,29 @@
 
     @arguments("box", "descr")
     def _opimpl_getfield_gc_any(self, box, fielddescr):
-        return self.execute_with_descr(rop.GETFIELD_GC, fielddescr, box)
+        return self._opimpl_getfield_gc_any_pureornot(
+                rop.GETFIELD_GC, box, fielddescr)
     opimpl_getfield_gc_i = _opimpl_getfield_gc_any
     opimpl_getfield_gc_r = _opimpl_getfield_gc_any
     opimpl_getfield_gc_f = _opimpl_getfield_gc_any
 
     @arguments("box", "descr")
     def _opimpl_getfield_gc_pure_any(self, box, fielddescr):
-        return self.execute_with_descr(rop.GETFIELD_GC_PURE, fielddescr, box)
+        return self._opimpl_getfield_gc_any_pureornot(
+                rop.GETFIELD_GC_PURE, box, fielddescr)
     opimpl_getfield_gc_i_pure = _opimpl_getfield_gc_pure_any
     opimpl_getfield_gc_r_pure = _opimpl_getfield_gc_pure_any
     opimpl_getfield_gc_f_pure = _opimpl_getfield_gc_pure_any
 
+    @specialize.arg(1)
+    def _opimpl_getfield_gc_any_pureornot(self, opnum, box, fielddescr):
+        frombox, tobox = self.metainterp.heap_cache.get(fielddescr, (None, 
None))
+        if frombox is box:
+            return tobox
+        resbox = self.execute_with_descr(opnum, fielddescr, box)
+        self.metainterp.heap_cache[fielddescr] = (box, resbox)
+        return resbox
+
     @arguments("orgpc", "box", "descr")
     def _opimpl_getfield_gc_greenfield_any(self, pc, box, fielddescr):
         ginfo = self.metainterp.jitdriver_sd.greenfield_info
@@ -532,7 +558,11 @@
 
     @arguments("box", "descr", "box")
     def _opimpl_setfield_gc_any(self, box, fielddescr, valuebox):
+        frombox, tobox = self.metainterp.heap_cache.get(fielddescr, (None, 
None))
+        if frombox is box and tobox is valuebox:
+            return
         self.execute_with_descr(rop.SETFIELD_GC, fielddescr, box, valuebox)
+        self.metainterp.heap_cache[fielddescr] = (box, valuebox)
     opimpl_setfield_gc_i = _opimpl_setfield_gc_any
     opimpl_setfield_gc_r = _opimpl_setfield_gc_any
     opimpl_setfield_gc_f = _opimpl_setfield_gc_any
@@ -617,7 +647,7 @@
     @arguments("orgpc", "box", "descr")
     def _opimpl_getfield_vable(self, pc, box, fielddescr):
         if self._nonstandard_virtualizable(pc, box):
-            return self.execute_with_descr(rop.GETFIELD_GC, fielddescr, box)
+            return self._opimpl_getfield_gc_any(box, fielddescr)
         self.metainterp.check_synchronized_virtualizable()
         index = self._get_virtualizable_field_index(fielddescr)
         return self.metainterp.virtualizable_boxes[index]
@@ -629,8 +659,7 @@
     @arguments("orgpc", "box", "descr", "box")
     def _opimpl_setfield_vable(self, pc, box, fielddescr, valuebox):
         if self._nonstandard_virtualizable(pc, box):
-            self.execute_with_descr(rop.SETFIELD_GC, fielddescr, box, valuebox)
-            return
+            return self._opimpl_setfield_gc_any(box, fielddescr, valuebox)
         index = self._get_virtualizable_field_index(fielddescr)
         self.metainterp.virtualizable_boxes[index] = valuebox
         self.metainterp.synchronize_virtualizable()
@@ -660,10 +689,8 @@
     @arguments("orgpc", "box", "descr", "descr", "box")
     def _opimpl_getarrayitem_vable(self, pc, box, fdescr, adescr, indexbox):
         if self._nonstandard_virtualizable(pc, box):
-            arraybox = self.metainterp.execute_and_record(rop.GETFIELD_GC,
-                                                          fdescr, box)
-            return self.execute_with_descr(rop.GETARRAYITEM_GC, adescr,
-                                           arraybox, indexbox)
+            arraybox = self._opimpl_getfield_gc_any(box, fdescr)
+            return self._opimpl_getarrayitem_gc_any(arraybox, adescr, indexbox)
         self.metainterp.check_synchronized_virtualizable()
         index = self._get_arrayitem_vable_index(pc, fdescr, indexbox)
         return self.metainterp.virtualizable_boxes[index]
@@ -676,10 +703,9 @@
     def _opimpl_setarrayitem_vable(self, pc, box, fdescr, adescr, indexbox,
                                   valuebox):
         if self._nonstandard_virtualizable(pc, box):
-            arraybox = self.metainterp.execute_and_record(rop.GETFIELD_GC,
-                                                          fdescr, box)
-            self.execute_with_descr(rop.SETARRAYITEM_GC, adescr,
-                                    arraybox, indexbox, valuebox)
+            arraybox = self._opimpl_getfield_gc_any(box, fdescr)
+            self._opimpl_setarrayitem_gc_any(arraybox, adescr,
+                                             indexbox, valuebox)
             return
         index = self._get_arrayitem_vable_index(pc, fdescr, indexbox)
         self.metainterp.virtualizable_boxes[index] = valuebox
@@ -693,8 +719,7 @@
     @arguments("orgpc", "box", "descr", "descr")
     def opimpl_arraylen_vable(self, pc, box, fdescr, adescr):
         if self._nonstandard_virtualizable(pc, box):
-            arraybox = self.metainterp.execute_and_record(rop.GETFIELD_GC,
-                                                          fdescr, box)
+            arraybox = self._opimpl_getfield_gc_any(box, fdescr)
             return self.execute_with_descr(rop.ARRAYLEN_GC, adescr, arraybox)
         vinfo = self.metainterp.jitdriver_sd.virtualizable_info
         virtualizable_box = self.metainterp.virtualizable_boxes[-1]
@@ -1462,6 +1487,12 @@
         self.known_class_boxes = {}
         # contains frame boxes that are not virtualizables
         self.nonstandard_virtualizables = {}
+        # heap cache
+        # maps descrs to (from_box, to_box) tuples
+        self.heap_cache = {}
+        # heap array cache
+        # maps descrs to {index: (from_box, to_box)} dicts
+        self.heap_array_cache = {}
 
     def perform_call(self, jitcode, boxes, greenkey=None):
         # causes the metainterp to enter the given subfunction
@@ -1637,10 +1668,27 @@
         # record the operation
         profiler = self.staticdata.profiler
         profiler.count_ops(opnum, RECORDED_OPS)
+        self._invalidate_caches(opnum, descr)
         op = self.history.record(opnum, argboxes, resbox, descr)
         self.attach_debug_info(op)
         return resbox
 
+    def _invalidate_caches(self, opnum, descr):
+        if opnum == rop.SETFIELD_GC:
+            return
+        if opnum == rop.SETARRAYITEM_GC:
+            return
+        if rop._NOSIDEEFFECT_FIRST <= opnum <= rop._NOSIDEEFFECT_LAST:
+            return
+        if opnum == rop.CALL:
+            effectinfo = descr.get_extra_info()
+            if effectinfo.extraeffect == effectinfo.EF_ELIDABLE:
+                return
+        if self.heap_cache:
+            self.heap_cache.clear()
+        if self.heap_array_cache:
+            self.heap_array_cache.clear()
+
     def attach_debug_info(self, op):
         if (not we_are_translated() and op is not None
             and getattr(self, 'framestack', None)):
@@ -1804,6 +1852,8 @@
     def reached_loop_header(self, greenboxes, redboxes, resumedescr):
         self.known_class_boxes = {}
         self.nonstandard_virtualizables = {} # XXX maybe not needed?
+        self.heap_cache = {}
+        self.heap_array_cache = {}
 
         duplicates = {}
         self.remove_consts_and_duplicates(redboxes, len(redboxes),
@@ -2311,6 +2361,16 @@
             for i in range(len(boxes)):
                 if boxes[i] is oldbox:
                     boxes[i] = newbox
+        for descr, (frombox, tobox) in self.heap_cache.iteritems():
+            change = False
+            if frombox is oldbox:
+                change = True
+                frombox = newbox
+            if tobox is oldbox:
+                change = True
+                tobox = newbox
+            if change:
+                self.heap_cache[descr] = frombox, tobox
 
     def find_biggest_function(self):
         start_stack = []
diff --git a/pypy/jit/metainterp/test/test_ajit.py 
b/pypy/jit/metainterp/test/test_ajit.py
--- a/pypy/jit/metainterp/test/test_ajit.py
+++ b/pypy/jit/metainterp/test/test_ajit.py
@@ -1024,69 +1024,6 @@
         res = self.meta_interp(main, [])
         assert res == 55
 
-    def test_dont_record_repeated_guard_class(self):
-        class A:
-            pass
-        class B(A):
-            pass
-        @dont_look_inside
-        def extern(n):
-            if n == -7:
-                return None
-            elif n:
-                return A()
-            else:
-                return B()
-        def fn(n):
-            obj = extern(n)
-            return isinstance(obj, B) + isinstance(obj, B) + isinstance(obj, 
B) + isinstance(obj, B)
-        res = self.interp_operations(fn, [0])
-        assert res == 4
-        self.check_operations_history(guard_class=1, guard_nonnull=1)
-        res = self.interp_operations(fn, [1])
-        assert not res
-
-    def test_dont_record_guard_class_after_new(self):
-        class A:
-            pass
-        class B(A):
-            pass
-        def fn(n):
-            if n == -7:
-                obj = None
-            elif n:
-                obj = A()
-            else:
-                obj = B()
-            return isinstance(obj, B) + isinstance(obj, B) + isinstance(obj, 
B) + isinstance(obj, B)
-        res = self.interp_operations(fn, [0])
-        assert res == 4
-        self.check_operations_history(guard_class=0, guard_nonnull=0)
-        res = self.interp_operations(fn, [1])
-        assert not res
-
-    def test_guard_isnull_nullifies(self):
-        class A:
-            pass
-        a = A()
-        a.x = None
-        def fn(n):
-            if n == -7:
-                a.x = ""
-            obj = a.x
-            res = 0
-            if not obj:
-                res += 1
-            if obj:
-                res += 1
-            if obj is None:
-                res += 1
-            if obj is not None:
-                res += 1
-            return res
-        res = self.interp_operations(fn, [0])
-        assert res == 2
-        self.check_operations_history(guard_isnull=1)
 
     def test_assert_isinstance(self):
         class A:
@@ -1248,7 +1185,7 @@
             return tup[1]
         res = self.interp_operations(f, [3, 5])
         assert res == 5
-        self.check_operations_history(setfield_gc=2, getfield_gc_pure=1)
+        self.check_operations_history(setfield_gc=2, getfield_gc_pure=0)
 
     def test_oosend_look_inside_only_one(self):
         class A:
diff --git a/pypy/jit/metainterp/test/test_immutable.py 
b/pypy/jit/metainterp/test/test_immutable.py
--- a/pypy/jit/metainterp/test/test_immutable.py
+++ b/pypy/jit/metainterp/test/test_immutable.py
@@ -1,5 +1,9 @@
+from pypy.rlib import jit
 from pypy.jit.metainterp.test.support import LLJitMixin, OOJitMixin
 
[email protected]_look_inside
+def escape(x):
+    return x
 
 class ImmutableFieldsTests:
 
@@ -11,7 +15,7 @@
                 self.x = x
 
         def f(x):
-            y = X(x)
+            y = escape(X(x))
             return y.x + 5
         res = self.interp_operations(f, [23])
         assert res == 28
@@ -33,7 +37,7 @@
 
         def f(x, y):
             X(x)     # force the field 'x' to be on class 'X'
-            z = Y(x, y)
+            z = escape(Y(x, y))
             return z.x + z.y + 5
         res = self.interp_operations(f, [23, 11])
         assert res == 39
@@ -42,7 +46,7 @@
 
         def f(x, y):
             # this time, the field 'x' only shows up on subclass 'Y'
-            z = Y(x, y)
+            z = escape(Y(x, y))
             return z.x + z.y + 5
         res = self.interp_operations(f, [23, 11])
         assert res == 39
@@ -58,7 +62,7 @@
         def f(index):
             l = [1, 2, 3, 4]
             l[2] = 30
-            a = X(l)
+            a = escape(X(l))
             return a.y[index]
         res = self.interp_operations(f, [2], listops=True)
         assert res == 30
@@ -76,7 +80,7 @@
                 self.y = y
 
         def f(x, index):
-            y = X([x], x+1)
+            y = escape(X([x], x+1))
             return y.lst[index] + y.y + 5
         res = self.interp_operations(f, [23, 0], listops=True)
         assert res == 23 + 24 + 5
diff --git a/pypy/jit/metainterp/test/test_tracingopts.py 
b/pypy/jit/metainterp/test/test_tracingopts.py
new file mode 100644
--- /dev/null
+++ b/pypy/jit/metainterp/test/test_tracingopts.py
@@ -0,0 +1,407 @@
+import py
+import sys
+from pypy.rlib import jit
+from pypy.jit.metainterp.test.support import LLJitMixin
+
+
+class TestLLtype(LLJitMixin):
+    def test_dont_record_repeated_guard_class(self):
+        class A:
+            pass
+        class B(A):
+            pass
+        @jit.dont_look_inside
+        def extern(n):
+            if n == -7:
+                return None
+            elif n:
+                return A()
+            else:
+                return B()
+        def fn(n):
+            obj = extern(n)
+            return isinstance(obj, B) + isinstance(obj, B) + isinstance(obj, 
B) + isinstance(obj, B)
+        res = self.interp_operations(fn, [0])
+        assert res == 4
+        self.check_operations_history(guard_class=1, guard_nonnull=1)
+        res = self.interp_operations(fn, [1])
+        assert not res
+
+    def test_dont_record_guard_class_after_new(self):
+        class A:
+            pass
+        class B(A):
+            pass
+        def fn(n):
+            if n == -7:
+                obj = None
+            elif n:
+                obj = A()
+            else:
+                obj = B()
+            return isinstance(obj, B) + isinstance(obj, B) + isinstance(obj, 
B) + isinstance(obj, B)
+        res = self.interp_operations(fn, [0])
+        assert res == 4
+        self.check_operations_history(guard_class=0, guard_nonnull=0)
+        res = self.interp_operations(fn, [1])
+        assert not res
+
+    def test_guard_isnull_nullifies(self):
+        class A:
+            pass
+        a = A()
+        a.x = None
+        def fn(n):
+            if n == -7:
+                a.x = ""
+            obj = a.x
+            res = 0
+            if not obj:
+                res += 1
+            if obj:
+                res += 1
+            if obj is None:
+                res += 1
+            if obj is not None:
+                res += 1
+            return res
+        res = self.interp_operations(fn, [0])
+        assert res == 2
+        self.check_operations_history(guard_isnull=1)
+
+    def test_heap_caching_while_tracing(self):
+        class A:
+            pass
+        a1 = A()
+        a2 = A()
+        def fn(n):
+            if n > 0:
+                a = a1
+            else:
+                a = a2
+            a.x = n
+            return a.x
+        res = self.interp_operations(fn, [7])
+        assert res == 7
+        self.check_operations_history(getfield_gc=0)
+        res = self.interp_operations(fn, [-7])
+        assert res == -7
+        self.check_operations_history(getfield_gc=0)
+
+        def fn(n, ca, cb):
+            a1.x = n
+            a2.x = n
+            a = a1
+            if ca:
+                a = a2
+            b = a1
+            if cb:
+                b = a
+            return a.x + b.x
+        res = self.interp_operations(fn, [7, 0, 1])
+        assert res == 7 * 2
+        self.check_operations_history(getfield_gc=1)
+        res = self.interp_operations(fn, [-7, 1, 1])
+        assert res == -7 * 2
+        self.check_operations_history(getfield_gc=1)
+
+    def test_heap_caching_while_tracing_invalidation(self):
+        class A:
+            pass
+        a1 = A()
+        a2 = A()
+        @jit.dont_look_inside
+        def f(a):
+            a.x = 5
+        l = [1]
+        def fn(n):
+            if n > 0:
+                a = a1
+            else:
+                a = a2
+            a.x = n
+            x1 = a.x
+            f(a)
+            x2 = a.x
+            l[0] = x2
+            return a.x + x1 + x2
+        res = self.interp_operations(fn, [7])
+        assert res == 5 * 2 + 7
+        self.check_operations_history(getfield_gc=1)
+
+    def test_heap_caching_dont_store_same(self):
+        class A:
+            pass
+        a1 = A()
+        a2 = A()
+        def fn(n):
+            if n > 0:
+                a = a1
+            else:
+                a = a2
+            a.x = n
+            a.x = n
+            return a.x
+        res = self.interp_operations(fn, [7])
+        assert res == 7
+        self.check_operations_history(getfield_gc=0, setfield_gc=1)
+        res = self.interp_operations(fn, [-7])
+        assert res == -7
+        self.check_operations_history(getfield_gc=0)
+
+    def test_array_caching(self):
+        a1 = [0, 0]
+        a2 = [0, 0]
+        def fn(n):
+            if n > 0:
+                a = a1
+            else:
+                a = a2
+            a[0] = n
+            x1 = a[0]
+            a[n - n] = n + 1
+            return a[0] + x1
+        res = self.interp_operations(fn, [7])
+        assert res == 7 + 7 + 1
+        self.check_operations_history(getarrayitem_gc=1)
+        res = self.interp_operations(fn, [-7])
+        assert res == -7 - 7 + 1
+        self.check_operations_history(getarrayitem_gc=1)
+
+        def fn(n, ca, cb):
+            a1[0] = n
+            a2[0] = n
+            a = a1
+            if ca:
+                a = a2
+            b = a1
+            if cb:
+                b = a
+            return a[0] + b[0]
+        res = self.interp_operations(fn, [7, 0, 1])
+        assert res == 7 * 2
+        self.check_operations_history(getarrayitem_gc=1)
+        res = self.interp_operations(fn, [-7, 1, 1])
+        assert res == -7 * 2
+        self.check_operations_history(getarrayitem_gc=1)
+
+    def test_array_caching_while_tracing_invalidation(self):
+        a1 = [0, 0]
+        a2 = [0, 0]
+        @jit.dont_look_inside
+        def f(a):
+            a[0] = 5
+        class A: pass
+        l = A()
+        def fn(n):
+            if n > 0:
+                a = a1
+            else:
+                a = a2
+            a[0] = n
+            x1 = a[0]
+            f(a)
+            x2 = a[0]
+            l.x = x2
+            return a[0] + x1 + x2
+        res = self.interp_operations(fn, [7])
+        assert res == 5 * 2 + 7
+        self.check_operations_history(getarrayitem_gc=1)
+
+    def test_array_and_getfield_interaction(self):
+        class A: pass
+        a1 = A()
+        a2 = A()
+        a1.l = a2.l = [0, 0]
+        def fn(n):
+            if n > 0:
+                a = a1
+            else:
+                a = a2
+                a.l = [0, 0]
+            a.x = 0
+            a.l[a.x] = n
+            a.x += 1
+            a.l[a.x] = n + 1
+            x1 = a.l[a.x]
+            a.x -= 1
+            x2 = a.l[a.x]
+            return x1 + x2
+        res = self.interp_operations(fn, [7])
+        assert res == 7 * 2 + 1
+        self.check_operations_history(setarrayitem_gc=2, setfield_gc=3,
+                                      getarrayitem_gc=0, getfield_gc=1)
+
+    def test_promote_changes_heap_cache(self):
+        class A: pass
+        a1 = A()
+        a2 = A()
+        a1.l = a2.l = [0, 0]
+        a1.x = a2.x = 0
+        def fn(n):
+            if n > 0:
+                a = a1
+            else:
+                a = a2
+                a.l = [0, 0]
+            jit.promote(a.x)
+            a.l[a.x] = n
+            a.x += 1
+            a.l[a.x] = n + 1
+            x1 = a.l[a.x]
+            a.x -= 1
+            x2 = a.l[a.x]
+            return x1 + x2
+        res = self.interp_operations(fn, [7])
+        assert res == 7 * 2 + 1
+        self.check_operations_history(setarrayitem_gc=2, setfield_gc=2,
+                                      getarrayitem_gc=0, getfield_gc=2)
+
+    def test_list_caching(self):
+        a1 = [0, 0]
+        a2 = [0, 0]
+        def fn(n):
+            if n > 0:
+                a = a1
+            else:
+                a = a2
+                if n < -1000:
+                    a.append(5)
+            a[0] = n
+            x1 = a[0]
+            a[n - n] = n + 1
+            return a[0] + x1
+        res = self.interp_operations(fn, [7])
+        assert res == 7 + 7 + 1
+        self.check_operations_history(getarrayitem_gc=1,
+                getfield_gc=1)
+        res = self.interp_operations(fn, [-7])
+        assert res == -7 - 7 + 1
+        self.check_operations_history(getarrayitem_gc=1,
+                getfield_gc=1)
+
+        def fn(n, ca, cb):
+            a1[0] = n
+            a2[0] = n
+            a = a1
+            if ca:
+                a = a2
+                if n < -100:
+                    a.append(5)
+            b = a1
+            if cb:
+                b = a
+            return a[0] + b[0]
+        res = self.interp_operations(fn, [7, 0, 1])
+        assert res == 7 * 2
+        self.check_operations_history(getarrayitem_gc=1,
+                getfield_gc=3)
+        res = self.interp_operations(fn, [-7, 1, 1])
+        assert res == -7 * 2
+        self.check_operations_history(getarrayitem_gc=1,
+                getfield_gc=3)
+
+    def test_list_caching_negative(self):
+        def fn(n):
+            a = [0] * n
+            if n > 1000:
+                a.append(0)
+            a[-1] = n
+            x1 = a[-1]
+            a[n - n - 1] = n + 1
+            return a[-1] + x1
+        res = self.interp_operations(fn, [7])
+        assert res == 7 + 7 + 1
+        self.check_operations_history(setarrayitem_gc=2,
+                setfield_gc=2)
+
+    def test_virtualizable_with_array_heap_cache(self):
+        myjitdriver = jit.JitDriver(greens = [], reds = ['n', 'x', 'i', 
'frame'],
+                                    virtualizables = ['frame'])
+
+        class Frame(object):
+            _virtualizable2_ = ['l[*]', 's']
+
+            def __init__(self, a, s):
+                self = jit.hint(self, access_directly=True, 
fresh_virtualizable=True)
+                self.l = [0] * (4 + a)
+                self.s = s
+
+        def f(n, a, i):
+            frame = Frame(a, 0)
+            frame.l[0] = a
+            frame.l[1] = a + 1
+            frame.l[2] = a + 2
+            frame.l[3] = a + 3
+            if not i:
+                return frame.l[0] + len(frame.l)
+            x = 0
+            while n > 0:
+                myjitdriver.can_enter_jit(frame=frame, n=n, x=x, i=i)
+                myjitdriver.jit_merge_point(frame=frame, n=n, x=x, i=i)
+                frame.s = jit.promote(frame.s)
+                n -= 1
+                s = frame.s
+                assert s >= 0
+                x += frame.l[s]
+                frame.s += 1
+                s = frame.s
+                assert s >= 0
+                x += frame.l[s]
+                x += len(frame.l)
+                x += f(n, n, 0)
+                frame.s -= 1
+            return x
+
+        res = self.meta_interp(f, [10, 1, 1], listops=True)
+        assert res == f(10, 1, 1)
+        self.check_history(getarrayitem_gc=0, getfield_gc=0)
+
+    def test_heap_caching_pure(self):
+        class A(object):
+            pass
+        p1 = A()
+        p2 = A()
+        def fn(n):
+            if n >= 0:
+                a = (n, n + 1)
+                p = p1
+            else:
+                a = (n + 1, n)
+                p = p2
+            p.x = a
+
+            return p.x[0] + p.x[1]
+        res = self.interp_operations(fn, [7])
+        assert res == 7 + 7 + 1
+        self.check_operations_history(getfield_gc=0, getfield_gc_pure=0)
+        res = self.interp_operations(fn, [-7])
+        assert res == -7 - 7 + 1
+        self.check_operations_history(getfield_gc=0, getfield_gc_pure=0)
+
+    def test_heap_caching_and_elidable_function(self):
+        class A:
+            pass
+        class B: pass
+        a1 = A()
+        a1.y = 6
+        a2 = A()
+        a2.y = 13
+        @jit.elidable
+        def f(b):
+            return b + 1
+        def fn(n):
+            if n > 0:
+                a = a1
+            else:
+                a = A()
+            a.x = n
+            z = f(6)
+            return z + a.x
+        res = self.interp_operations(fn, [7])
+        assert res == 7 + 7
+        self.check_operations_history(getfield_gc=0)
+        res = self.interp_operations(fn, [-7])
+        assert res == -7 + 7
+        self.check_operations_history(getfield_gc=0)
+        return
diff --git a/pypy/jit/metainterp/test/test_virtualizable.py 
b/pypy/jit/metainterp/test/test_virtualizable.py
--- a/pypy/jit/metainterp/test/test_virtualizable.py
+++ b/pypy/jit/metainterp/test/test_virtualizable.py
@@ -377,7 +377,7 @@
         expected = f(20)
         res = self.meta_interp(f, [20], enable_opts='')
         assert res == expected
-        self.check_loops(getfield_gc=3, setfield_gc=0,
+        self.check_loops(getfield_gc=1, setfield_gc=0,
                          arraylen_gc=1, getarrayitem_gc=1, setarrayitem_gc=1)
 
     # ------------------------------
_______________________________________________
pypy-commit mailing list
[email protected]
http://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to