Author: Carl Friedrich Bolz <cfb...@gmx.de> Branch: improve-heap-caching-tracing Changeset: r47122:e5b582b1252b Date: 2011-09-06 14:03 +0200 http://bitbucket.org/pypy/pypy/changeset/e5b582b1252b/
Log: cache the length of arrays 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 @@ -18,6 +18,8 @@ # heap array cache # maps descrs to {index: {from_box: to_box}} dicts self.heap_array_cache = {} + # cache the length of arrays + self.length_cache = {} def invalidate_caches(self, opnum, descr): if opnum == rop.SETFIELD_GC: @@ -57,6 +59,10 @@ def new(self, box): self.new_boxes[box] = None + def new_array(self, box, lengthbox): + self.new(box) + self.arraylen_now_known(box, lengthbox) + def getfield(self, box, descr): d = self.heap_cache.get(descr, None) if d: @@ -112,23 +118,26 @@ indexcache = cache.get(index, None) cache[index] = self._do_write_with_aliasing(indexcache, box, valuebox) + def arraylen(self, box): + return self.length_cache.get(box, None) + + def arraylen_now_known(self, box, lengthbox): + self.length_cache[box] = lengthbox + + def _replace_box(self, d, oldbox, newbox): + new_d = {} + for frombox, tobox in d.iteritems(): + if frombox is oldbox: + frombox = newbox + if tobox is oldbox: + tobox = newbox + new_d[frombox] = tobox + return new_d + def replace_box(self, oldbox, newbox): for descr, d in self.heap_cache.iteritems(): - new_d = {} - for frombox, tobox in d.iteritems(): - if frombox is oldbox: - frombox = newbox - if tobox is oldbox: - tobox = newbox - new_d[frombox] = tobox - self.heap_cache[descr] = new_d + self.heap_cache[descr] = self._replace_box(d, oldbox, newbox) for descr, d in self.heap_array_cache.iteritems(): for index, cache in d.iteritems(): - new_cache = {} - for frombox, tobox in cache.iteritems(): - if frombox is oldbox: - frombox = newbox - if tobox is oldbox: - tobox = newbox - new_cache[frombox] = tobox - d[index] = new_cache + d[index] = self._replace_box(cache, oldbox, newbox) + self.length_cache = self._replace_box(self.length_cache, oldbox, newbox) 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 @@ -394,9 +394,9 @@ ## self.execute(rop.SUBCLASSOF, box1, box2) @arguments("descr", "box") - def opimpl_new_array(self, itemsizedescr, countbox): - resbox = self.execute_with_descr(rop.NEW_ARRAY, itemsizedescr, countbox) - self.metainterp.heapcache.new(resbox) + def opimpl_new_array(self, itemsizedescr, lengthbox): + resbox = self.execute_with_descr(rop.NEW_ARRAY, itemsizedescr, lengthbox) + self.metainterp.heapcache.new_array(resbox, lengthbox) return resbox @arguments("box", "descr", "box") @@ -456,7 +456,12 @@ @arguments("box", "descr") def opimpl_arraylen_gc(self, arraybox, arraydescr): - return self.execute_with_descr(rop.ARRAYLEN_GC, arraydescr, arraybox) + lengthbox = self.metainterp.heapcache.arraylen(arraybox) + if lengthbox is None: + lengthbox = self.execute_with_descr( + rop.ARRAYLEN_GC, arraydescr, arraybox) + self.metainterp.heapcache.arraylen_now_known(arraybox, lengthbox) + return lengthbox @arguments("orgpc", "box", "descr", "box") def opimpl_check_neg_index(self, orgpc, arraybox, arraydescr, indexbox): @@ -465,10 +470,9 @@ negbox = self.implement_guard_value(orgpc, negbox) if negbox.getint(): # the index is < 0; add the array length to it - lenbox = self.metainterp.execute_and_record( - rop.ARRAYLEN_GC, arraydescr, arraybox) + lengthbox = self.opimpl_arraylen_gc(arraybox, arraydescr) indexbox = self.metainterp.execute_and_record( - rop.INT_ADD, None, indexbox, lenbox) + rop.INT_ADD, None, indexbox, lengthbox) return indexbox @arguments("descr", "descr", "descr", "descr", "box") @@ -721,7 +725,7 @@ def opimpl_arraylen_vable(self, pc, box, fdescr, adescr): if self._nonstandard_virtualizable(pc, box): arraybox = self._opimpl_getfield_gc_any(box, fdescr) - return self.execute_with_descr(rop.ARRAYLEN_GC, adescr, arraybox) + return self.opimpl_arraylen_gc(arraybox, adescr) vinfo = self.metainterp.jitdriver_sd.virtualizable_info virtualizable_box = self.metainterp.virtualizable_boxes[-1] virtualizable = vinfo.unwrap_virtualizable_box(virtualizable_box) 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 @@ -6,6 +6,8 @@ box2 = object() box3 = object() box4 = object() +lengthbox1 = object() +lengthbox2 = object() descr1 = object() descr2 = object() descr3 = object() @@ -206,6 +208,15 @@ assert h.getarrayitem(box3, descr1, index1) is box4 assert h.getarrayitem(box1, descr1, index1) is box3 # box1 and box3 cannot alias + def test_length_cache(self): + h = HeapCache() + h.new_array(box1, lengthbox1) + assert h.arraylen(box1) is lengthbox1 + + assert h.arraylen(box2) is None + h.arraylen_now_known(box2, lengthbox2) + assert h.arraylen(box2) is lengthbox2 + def test_invalidate_cache(self): h = HeapCache() @@ -252,14 +263,20 @@ h = HeapCache() h.setarrayitem(box1, descr1, index1, box2) h.setarrayitem(box1, descr2, index1, box3) + h.arraylen_now_known(box1, lengthbox1) h.setarrayitem(box2, descr1, index2, box1) h.setarrayitem(box3, descr2, index2, box1) h.setarrayitem(box2, descr3, index2, box3) h.replace_box(box1, box4) assert h.getarrayitem(box1, descr1, index1) is None assert h.getarrayitem(box1, descr2, index1) is None + assert h.arraylen(box1) is None + assert h.arraylen(box4) is lengthbox1 assert h.getarrayitem(box4, descr1, index1) is box2 assert h.getarrayitem(box4, descr2, index1) is box3 assert h.getarrayitem(box2, descr1, index2) is box4 assert h.getarrayitem(box3, descr2, index2) is box4 assert h.getarrayitem(box2, descr3, index2) is box3 + + h.replace_box(lengthbox1, lengthbox2) + assert h.arraylen(box4) is lengthbox2 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 @@ -469,3 +469,17 @@ assert res == 2 * -7 + 2 * -8 self.check_operations_history(getarrayitem_gc=0) + def test_length_caching(self): + class Gbl(object): + pass + g = Gbl() + g.a = [0] * 7 + def fn(n): + a = g.a + res = len(a) + len(a) + a1 = [0] * n + g.a = a1 + return len(a1) + res + res = self.interp_operations(fn, [7]) + assert res == 7 * 3 + self.check_operations_history(arraylen_gc=1) _______________________________________________ pypy-commit mailing list pypy-commit@python.org http://mail.python.org/mailman/listinfo/pypy-commit