[pypy-commit] pypy default: 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
Alex Gaynor
alex.gaynor at gmail.com
Wed Jun 22 15:50:24 CEST 2011
Given that a virtual is forced only right before it escapes, and the
external call would flush the heap cache, what's the value there?
Alex
On Wed, Jun 22, 2011 at 2:34 AM, Carl Friedrich Bolz <cfbolz at gmx.de> wrote:
> Hi Alex,
>
> This is part of a more general problem: If a virtual is forced the heap
> cache is not informed of the values that are written into the newly
> allocated object. This is useful also for fields that are not
> immutable. Do you maybe feel like generalizing this?
>
> Cheers,
>
> Carl Friedrich
>
>
> On 06/21/2011 08:33 PM, alex_gaynor wrote:
>
>> Author: Alex Gaynor<alex.gaynor at gmail.com>
>> Branch:
>> Changeset: r45043:456273d0b54f
>> Date: 2011-06-21 11:37 -0700
>> http://bitbucket.org/pypy/**pypy/changeset/456273d0b54f/<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
>> pypy-commit at python.org
>> http://mail.python.org/**mailman/listinfo/pypy-commit<http://mail.python.org/mailman/listinfo/pypy-commit>
>>
>
> ______________________________**_________________
> pypy-commit mailing list
> pypy-commit at python.org
> http://mail.python.org/**mailman/listinfo/pypy-commit<http://mail.python.org/mailman/listinfo/pypy-commit>
>
--
"I disapprove of what you say, but I will defend to the death your right to
say it." -- Evelyn Beatrice Hall (summarizing Voltaire)
"The people's good is the highest law." -- Cicero
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/pypy-commit/attachments/20110622/f6895e69/attachment-0001.html>
More information about the pypy-commit
mailing list