Author: Alex Gaynor<[email protected]>
Branch:
Changeset: r45043:456273d0b54f
Date: 2011-06-21 11:37 -0700
http://bitbucket.org/pypy/pypy/changeset/456273d0b54f/
Log: When a virtual is forced, and then subsequenly an immutable field is
read out of it, the value is known if it was seen in a setfield,
because it can't be set again by anything, therefore remove the
getfield_gc_pure for it. Thanks to fijal for the review.
diff --git a/pypy/jit/metainterp/optimizeopt/heap.py
b/pypy/jit/metainterp/optimizeopt/heap.py
--- a/pypy/jit/metainterp/optimizeopt/heap.py
+++ b/pypy/jit/metainterp/optimizeopt/heap.py
@@ -112,7 +112,7 @@
class OptHeap(Optimization):
"""Cache repeated heap accesses"""
-
+
def __init__(self):
# cached fields: {descr: CachedField}
self.cached_fields = {}
@@ -129,7 +129,7 @@
self.force_all_lazy_setfields()
else:
assert 0 # was: new.lazy_setfields = self.lazy_setfields
-
+
for descr, d in self.cached_fields.items():
new.cached_fields[descr] = d.get_reconstructed(optimizer,
valuemap)
diff --git a/pypy/jit/metainterp/optimizeopt/optimizer.py
b/pypy/jit/metainterp/optimizeopt/optimizer.py
--- a/pypy/jit/metainterp/optimizeopt/optimizer.py
+++ b/pypy/jit/metainterp/optimizeopt/optimizer.py
@@ -141,6 +141,9 @@
# meaning it has been forced.
return self.box is None
+ def is_forced_virtual(self):
+ return False
+
def getfield(self, ofs, default):
raise NotImplementedError
diff --git a/pypy/jit/metainterp/optimizeopt/rewrite.py
b/pypy/jit/metainterp/optimizeopt/rewrite.py
--- a/pypy/jit/metainterp/optimizeopt/rewrite.py
+++ b/pypy/jit/metainterp/optimizeopt/rewrite.py
@@ -219,7 +219,7 @@
break
arg_consts.append(const)
else:
- # all constant arguments: check if we already know the reslut
+ # all constant arguments: check if we already know the result
try:
result = self.optimizer.call_pure_results[arg_consts]
except KeyError:
diff --git a/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py
b/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py
--- a/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py
+++ b/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py
@@ -5837,3 +5837,30 @@
jump(i3, i4)
"""
self.optimize_loop(ops, expected)
+
+ def test_forced_virtual_pure_getfield(self):
+ ops = """
+ [p0]
+ p1 = getfield_gc_pure(p0, descr=valuedescr)
+ jump(p1)
+ """
+ self.optimize_loop(ops, ops)
+
+ ops = """
+ [p0]
+ p1 = new_with_vtable(ConstClass(node_vtable))
+ setfield_gc(p1, p0, descr=valuedescr)
+ escape(p1)
+ p2 = getfield_gc_pure(p1, descr=valuedescr)
+ escape(p2)
+ jump(p0)
+ """
+ expected = """
+ [p0]
+ p1 = new_with_vtable(ConstClass(node_vtable))
+ setfield_gc(p1, p0, descr=valuedescr)
+ escape(p1)
+ escape(p0)
+ jump(p0)
+ """
+ self.optimize_loop(ops, expected)
\ No newline at end of file
diff --git a/pypy/jit/metainterp/optimizeopt/virtualize.py
b/pypy/jit/metainterp/optimizeopt/virtualize.py
--- a/pypy/jit/metainterp/optimizeopt/virtualize.py
+++ b/pypy/jit/metainterp/optimizeopt/virtualize.py
@@ -20,6 +20,9 @@
self.source_op = source_op # the NEW_WITH_VTABLE/NEW_ARRAY operation
# that builds this box
+ def is_forced_virtual(self):
+ return self.box is not None
+
def get_key_box(self):
if self.box is None:
return self.keybox
@@ -120,7 +123,6 @@
op = ResOperation(rop.SETFIELD_GC, [box, subbox], None,
descr=ofs)
newoperations.append(op)
- self._fields = None
def _get_field_descr_list(self):
_cached_sorted_fields = self._cached_sorted_fields
@@ -351,7 +353,7 @@
if not self.optimizer.cpu.ts.CONST_NULL.same_constant(objbox):
seo(ResOperation(rop.SETFIELD_GC, op.getarglist(), None,
descr = vrefinfo.descr_forced))
-
+
# - set 'virtual_token' to TOKEN_NONE
args = [op.getarg(0), ConstInt(vrefinfo.TOKEN_NONE)]
seo(ResOperation(rop.SETFIELD_GC, args, None,
@@ -365,6 +367,14 @@
def optimize_GETFIELD_GC(self, op):
value = self.getvalue(op.getarg(0))
+ # If this is an immutable field (as indicated by op.is_always_pure())
+ # then it's safe to reuse the virtual's field, even if it has been
+ # forced, because it should never be written to again.
+ if value.is_forced_virtual() and op.is_always_pure():
+ fieldvalue = value.getfield(op.getdescr(), None)
+ if fieldvalue is not None:
+ self.make_equal_to(op.result, fieldvalue)
+ return
if value.is_virtual():
assert isinstance(value, AbstractVirtualValue)
fieldvalue = value.getfield(op.getdescr(), None)
@@ -382,6 +392,7 @@
def optimize_SETFIELD_GC(self, op):
value = self.getvalue(op.getarg(0))
+
if value.is_virtual():
fieldvalue = self.getvalue(op.getarg(1))
value.setfield(op.getdescr(), fieldvalue)
diff --git a/pypy/jit/metainterp/test/test_dict.py
b/pypy/jit/metainterp/test/test_dict.py
--- a/pypy/jit/metainterp/test/test_dict.py
+++ b/pypy/jit/metainterp/test/test_dict.py
@@ -130,6 +130,38 @@
assert res == 50
self.check_loops(int_mod=1)
+ def test_repeated_lookup(self):
+ myjitdriver = JitDriver(greens = [], reds = ['n', 'd'])
+ class Wrapper(object):
+ _immutable_fields_ = ["value"]
+ def __init__(self, value):
+ self.value = value
+ def eq_func(a, b):
+ return a.value == b.value
+ def hash_func(x):
+ return objectmodel.compute_hash(x.value)
+
+ def f(n):
+ d = None
+ while n> 0:
+ myjitdriver.jit_merge_point(n=n, d=d)
+ d = objectmodel.r_dict(eq_func, hash_func)
+ y = Wrapper(str(n))
+ d[y] = n - 1
+ n = d[y]
+ return d[Wrapper(str(n + 1))]
+
+ res = self.meta_interp(f, [100], listops=True)
+ assert res == f(50)
+ # XXX: ideally there would be 7 calls here, but repeated CALL_PURE with
+ # the same arguments are not folded, because we have conflicting
+ # definitions of pure, once strhash can be appropriately folded
+ # this should be decreased to seven.
+ self.check_loops({"call": 8, "guard_false": 1, "guard_no_exception": 5,
+ "guard_true": 1, "int_and": 1, "int_gt": 1,
+ "int_is_true": 1, "int_sub": 1, "jump": 1,
+ "new_with_vtable": 1, "setfield_gc": 1})
+
class TestOOtype(DictTests, OOJitMixin):
pass
diff --git a/pypy/rpython/lltypesystem/rstr.py
b/pypy/rpython/lltypesystem/rstr.py
--- a/pypy/rpython/lltypesystem/rstr.py
+++ b/pypy/rpython/lltypesystem/rstr.py
@@ -323,6 +323,8 @@
return s
ll_str2unicode.oopspec = 'str.str2unicode(str)'
+ # it's pure but it does not look like it
+ @purefunction
def ll_strhash(s):
# unlike CPython, there is no reason to avoid to return -1
# but our malloc initializes the memory to zero, so we use zero as the
@@ -334,7 +336,6 @@
x = 29872897
s.hash = x
return x
- ll_strhash._pure_function_ = True # it's pure but it does not look like it
def ll_strfasthash(s):
return s.hash # assumes that the hash is already computed
_______________________________________________
pypy-commit mailing list
[email protected]
http://mail.python.org/mailman/listinfo/pypy-commit