[pypy-commit] pypy improve-heap-caching-tracing: Add a special case for ll_arraycopy in the tracing heap cache.

alex_gaynor noreply at buildbot.pypy.org
Wed Sep 7 23:02:29 CEST 2011


Author: Alex Gaynor <alex.gaynor at gmail.com>
Branch: improve-heap-caching-tracing
Changeset: r47153:70d999525e7c
Date: 2011-09-07 14:02 -0700
http://bitbucket.org/pypy/pypy/changeset/70d999525e7c/

Log:	Add a special case for ll_arraycopy in the tracing heap cache.

diff --git a/pypy/jit/metainterp/heapcache.py b/pypy/jit/metainterp/heapcache.py
--- a/pypy/jit/metainterp/heapcache.py
+++ b/pypy/jit/metainterp/heapcache.py
@@ -1,5 +1,7 @@
+from pypy.jit.codewriter.effectinfo import EffectInfo
+from pypy.jit.metainterp.history import ConstInt
 from pypy.jit.metainterp.resoperation import rop
-from pypy.jit.metainterp.history import ConstInt
+
 
 class HeapCache(object):
     def __init__(self):
@@ -21,7 +23,7 @@
         # cache the length of arrays
         self.length_cache = {}
 
-    def invalidate_caches(self, opnum, descr):
+    def invalidate_caches(self, opnum, descr, argboxes):
         if opnum == rop.SETFIELD_GC:
             return
         if opnum == rop.SETARRAYITEM_GC:
@@ -41,6 +43,20 @@
                ef == effectinfo.EF_ELIDABLE_CANNOT_RAISE or \
                ef == effectinfo.EF_ELIDABLE_CAN_RAISE:
                 return
+            # A special case for ll_arraycopy, because it is so common, and its
+            # effects are so well defined.
+            elif effectinfo.oopspecindex == EffectInfo.OS_ARRAYCOPY:
+                # The destination box
+                if argboxes[2] in self.new_boxes:
+                    # XXX: no descr here so we invalidate any of them, not just
+                    # of the correct type
+                    for descr, cache in self.heap_array_cache.iteritems():
+                        for idx, cache in cache.iteritems():
+                            for frombox in list(cache):
+                                if frombox not in self.new_boxes:
+                                    del cache[frombox]
+                    return
+
         self.heap_cache.clear()
         self.heap_array_cache.clear()
 
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
@@ -1676,7 +1676,7 @@
         # record the operation
         profiler = self.staticdata.profiler
         profiler.count_ops(opnum, RECORDED_OPS)
-        self.heapcache.invalidate_caches(opnum, descr)
+        self.heapcache.invalidate_caches(opnum, descr, argboxes)
         op = self.history.record(opnum, argboxes, resbox, descr)
         self.attach_debug_info(op)
         return resbox
diff --git a/pypy/jit/metainterp/test/test_heapcache.py b/pypy/jit/metainterp/test/test_heapcache.py
--- a/pypy/jit/metainterp/test/test_heapcache.py
+++ b/pypy/jit/metainterp/test/test_heapcache.py
@@ -25,15 +25,17 @@
     EF_FORCES_VIRTUAL_OR_VIRTUALIZABLE = 5 #can raise and force virtualizables
     EF_RANDOM_EFFECTS                  = 6 #can do whatever
 
-    def __init__(self, extraeffect):
+    def __init__(self, extraeffect, oopspecindex):
         self.extraeffect = extraeffect
+        self.oopspecindex = oopspecindex
 
 class FakeCallDescr(object):
-    def __init__(self, extraeffect):
+    def __init__(self, extraeffect, oopspecindex=None):
         self.extraeffect = extraeffect
+        self.oopspecindex = oopspecindex
 
     def get_extra_info(self):
-        return FakeEffektinfo(self.extraeffect)
+        return FakeEffektinfo(self.extraeffect, self.oopspecindex)
 
 class TestHeapCache(object):
     def test_known_class_box(self):
@@ -237,25 +239,25 @@
         h.setfield(box1, descr1, box2)
         h.setarrayitem(box1, descr1, index1, box2)
         h.setarrayitem(box1, descr1, index2, box4)
-        h.invalidate_caches(rop.INT_ADD, None)
-        h.invalidate_caches(rop.INT_ADD_OVF, None)
-        h.invalidate_caches(rop.SETFIELD_RAW, None)
-        h.invalidate_caches(rop.SETARRAYITEM_RAW, None)
+        h.invalidate_caches(rop.INT_ADD, None, [])
+        h.invalidate_caches(rop.INT_ADD_OVF, None, [])
+        h.invalidate_caches(rop.SETFIELD_RAW, None, [])
+        h.invalidate_caches(rop.SETARRAYITEM_RAW, None, [])
         assert h.getfield(box1, descr1) is box2
         assert h.getarrayitem(box1, descr1, index1) is box2
         assert h.getarrayitem(box1, descr1, index2) is box4
 
         h.invalidate_caches(
-            rop.CALL, FakeCallDescr(FakeEffektinfo.EF_ELIDABLE_CANNOT_RAISE))
+            rop.CALL, FakeCallDescr(FakeEffektinfo.EF_ELIDABLE_CANNOT_RAISE), [])
         assert h.getfield(box1, descr1) is box2
         assert h.getarrayitem(box1, descr1, index1) is box2
         assert h.getarrayitem(box1, descr1, index2) is box4
 
         h.invalidate_caches(
-            rop.CALL_LOOPINVARIANT, FakeCallDescr(FakeEffektinfo.EF_LOOPINVARIANT))
+            rop.CALL_LOOPINVARIANT, FakeCallDescr(FakeEffektinfo.EF_LOOPINVARIANT), [])
 
         h.invalidate_caches(
-            rop.CALL, FakeCallDescr(FakeEffektinfo.EF_RANDOM_EFFECTS))
+            rop.CALL, FakeCallDescr(FakeEffektinfo.EF_RANDOM_EFFECTS), [])
         assert h.getfield(box1, descr1) is None
         assert h.getarrayitem(box1, descr1, index1) is None
         assert h.getarrayitem(box1, descr1, index2) is None
@@ -294,3 +296,33 @@
 
         h.replace_box(lengthbox1, lengthbox2)
         assert h.arraylen(box4) is lengthbox2
+
+    def test_ll_arraycopy(self):
+        h = HeapCache()
+        h.new_array(box1, lengthbox1)
+        h.setarrayitem(box1, descr1, index1, box2)
+        h.new_array(box2, lengthbox1)
+        # Just need the destination box for this call
+        h.invalidate_caches(
+            rop.CALL,
+            # XXX: hardcoded oopspecindex
+            FakeCallDescr(FakeEffektinfo.EF_CANNOT_RAISE, 1),
+            [None, None, box2, None, None]
+        )
+        assert h.getarrayitem(box1, descr1, index1) is box2
+        h.invalidate_caches(
+            rop.CALL,
+            FakeCallDescr(FakeEffektinfo.EF_CANNOT_RAISE, 1),
+            [None, None, box3, None, None]
+        )
+        assert h.getarrayitem(box1, descr1, index1) is None
+
+        h.setarrayitem(box4, descr1, index1, box2)
+        assert h.getarrayitem(box4, descr1, index1) is box2
+        h.invalidate_caches(
+            rop.CALL,
+            # XXX: hardcoded oopspecindex
+            FakeCallDescr(FakeEffektinfo.EF_CANNOT_RAISE, 1),
+            [None, None, box2, None, None]
+        )
+        assert h.getarrayitem(box4, descr1, index1) is None
diff --git a/pypy/jit/metainterp/test/test_tracingopts.py b/pypy/jit/metainterp/test/test_tracingopts.py
--- a/pypy/jit/metainterp/test/test_tracingopts.py
+++ b/pypy/jit/metainterp/test/test_tracingopts.py
@@ -558,3 +558,18 @@
         res = self.interp_operations(fn, [7])
         assert res == 7 * 3
         self.check_operations_history(arraylen_gc=1)
+
+    def test_arraycopy(self):
+        class Gbl(object):
+            pass
+        g = Gbl()
+        g.a = [0] * 7
+        def fn(n):
+            assert n >= 0
+            a = g.a
+            x = [0] * n
+            x[2] = 21
+            return len(a[:n]) + x[2]
+        res = self.interp_operations(fn, [3])
+        assert res == 24
+        self.check_operations_history(getarrayitem_gc=0)


More information about the pypy-commit mailing list