[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