Author: Carl Friedrich Bolz <[email protected]>
Branch: heap-caching-during-tracing
Changeset: r45661:be79442107df
Date: 2011-07-16 14:32 +0200
http://bitbucket.org/pypy/pypy/changeset/be79442107df/
Log: add a minimal heap cache to be used when tracing
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
@@ -502,7 +502,12 @@
@arguments("box", "descr")
def _opimpl_getfield_gc_any(self, box, fielddescr):
- return self.execute_with_descr(rop.GETFIELD_GC, fielddescr, box)
+ frombox, tobox = self.metainterp.heap_cache.get(fielddescr, (None,
None))
+ if frombox is box:
+ return tobox
+ resbox = self.execute_with_descr(rop.GETFIELD_GC, fielddescr, box)
+ self.metainterp.heap_cache[fielddescr] = (box, resbox)
+ return resbox
opimpl_getfield_gc_i = _opimpl_getfield_gc_any
opimpl_getfield_gc_r = _opimpl_getfield_gc_any
opimpl_getfield_gc_f = _opimpl_getfield_gc_any
@@ -532,7 +537,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 +626,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 +638,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()
@@ -1462,6 +1470,9 @@
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 = {}
def perform_call(self, jitcode, boxes, greenkey=None):
# causes the metainterp to enter the given subfunction
@@ -1637,6 +1648,9 @@
# record the operation
profiler = self.staticdata.profiler
profiler.count_ops(opnum, RECORDED_OPS)
+ if opnum != rop.SETFIELD_GC and self.heap_cache:
+ if not (rop._NOSIDEEFFECT_FIRST <= opnum <=
rop._NOSIDEEFFECT_LAST):
+ self.heap_cache = {}
op = self.history.record(opnum, argboxes, resbox, descr)
self.attach_debug_info(op)
return resbox
@@ -1804,6 +1818,7 @@
def reached_loop_header(self, greenboxes, redboxes, resumedescr):
self.known_class_boxes = {}
self.nonstandard_virtualizables = {} # XXX maybe not needed?
+ self.heap_cache = {}
duplicates = {}
self.remove_consts_and_duplicates(redboxes, len(redboxes),
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:
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,147 @@
+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
+ def fn(n):
+ if n > 0:
+ a = a1
+ else:
+ a = a2
+ a.x = n
+ x1 = a.x
+ f(a)
+ return a.x + x1
+ res = self.interp_operations(fn, [7])
+ assert res == 5 + 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)
_______________________________________________
pypy-commit mailing list
[email protected]
http://mail.python.org/mailman/listinfo/pypy-commit