[pypy-svn] pypy out-of-line-guards-2: Detect cases were the value stored in the quasi-immutable field

arigo commits-noreply at bitbucket.org
Sat Apr 2 20:17:36 CEST 2011


Author: Armin Rigo <arigo at tunes.org>
Branch: out-of-line-guards-2
Changeset: r43116:941dde3b5b4e
Date: 2011-04-02 18:46 +0200
http://bitbucket.org/pypy/pypy/changeset/941dde3b5b4e/

Log:	Detect cases were the value stored in the quasi-immutable field
	changed already between tracing and optimization.

diff --git a/pypy/jit/metainterp/quasiimmut.py b/pypy/jit/metainterp/quasiimmut.py
--- a/pypy/jit/metainterp/quasiimmut.py
+++ b/pypy/jit/metainterp/quasiimmut.py
@@ -44,11 +44,22 @@
 
 
 class SlowMutateDescr(AbstractDescr):
-    def __init__(self, cpu, gcref,
-                 constantfieldbox, fielddescr, mutatefielddescr):
+    def __init__(self, cpu, structbox, fielddescr, mutatefielddescr):
         self.cpu = cpu
-        self.gcref = gcref
-        self.constantfieldbox = constantfieldbox
+        self.structbox = structbox
         self.fielddescr = fielddescr
         self.mutatefielddescr = mutatefielddescr
+        gcref = structbox.getref_base()
         self.mutate = get_current_mutate_instance(cpu, gcref, mutatefielddescr)
+        self.constantfieldbox = self.get_current_constant_fieldvalue()
+
+    def get_current_constant_fieldvalue(self):
+        from pypy.jit.metainterp import executor
+        from pypy.jit.metainterp.resoperation import rop
+        fieldbox = executor.execute(self.cpu, None, rop.GETFIELD_GC,
+                                    self.fielddescr, self.structbox)
+        return fieldbox.constbox()
+
+    def is_still_valid(self):
+        currentbox = self.get_current_constant_fieldvalue()
+        return self.constantfieldbox.same_constant(currentbox)

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
@@ -385,15 +385,22 @@
         # a constant too, and we rely on the rest of the optimizations to
         # constant-fold the following getfield_gc.
         structvalue = self.getvalue(op.getarg(0))
-        if structvalue.is_constant():
-            from pypy.jit.metainterp.quasiimmut import SlowMutateDescr
-            # XXX check that the value is still correct!
-            # XXX record as an out-of-line guard!
-            smdescr = op.getdescr()
-            assert isinstance(smdescr, SlowMutateDescr)
-            fieldvalue = self.getvalue(smdescr.constantfieldbox)
-            cf = self.field_cache(smdescr.fielddescr)
-            cf.remember_field_value(structvalue, fieldvalue)
+        if not structvalue.is_constant():
+            return    # not a constant at all; ignore QUASIIMMUT_FIELD
+        #
+        from pypy.jit.metainterp.quasiimmut import SlowMutateDescr
+        smdescr = op.getdescr()
+        assert isinstance(smdescr, SlowMutateDescr)
+        # check that the value is still correct; it could have changed
+        # already between the tracing and now.  In this case, we are
+        # simply ignoring the QUASIIMMUT_FIELD hint and compiling it
+        # as a regular getfield.
+        if not smdescr.is_still_valid():
+            return
+        # XXX record as an out-of-line guard!
+        fieldvalue = self.getvalue(smdescr.constantfieldbox)
+        cf = self.field_cache(smdescr.fielddescr)
+        cf.remember_field_value(structvalue, fieldvalue)
 
     def propagate_forward(self, op):
         opnum = op.getopnum()

diff --git a/pypy/jit/metainterp/test/test_quasiimmut.py b/pypy/jit/metainterp/test/test_quasiimmut.py
--- a/pypy/jit/metainterp/test/test_quasiimmut.py
+++ b/pypy/jit/metainterp/test/test_quasiimmut.py
@@ -4,7 +4,7 @@
 from pypy.jit.metainterp.quasiimmut import SlowMutate
 from pypy.jit.metainterp.quasiimmut import get_current_mutate_instance
 from pypy.jit.metainterp.test.test_basic import LLJitMixin
-from pypy.rlib.jit import JitDriver
+from pypy.rlib.jit import JitDriver, dont_look_inside
 
 
 def test_get_current_mutate_instance():
@@ -64,6 +64,31 @@
         assert res == 700
         self.check_loops(getfield_gc=0, everywhere=True)
 
+    def test_change_during_tracing(self):
+        myjitdriver = JitDriver(greens=['foo'], reds=['x', 'total'])
+        class Foo:
+            _immutable_fields_ = ['a?']
+            def __init__(self, a):
+                self.a = a
+        @dont_look_inside
+        def residual_call(foo):
+            foo.a += 1
+        def f(a, x):
+            foo = Foo(a)
+            total = 0
+            while x > 0:
+                myjitdriver.jit_merge_point(foo=foo, x=x, total=total)
+                # read a quasi-immutable field out of a Constant
+                total += foo.a
+                residual_call(foo)
+                x -= 1
+            return total
+        #
+        assert f(100, 7) == 721
+        res = self.meta_interp(f, [100, 7])
+        assert res == 721
+        self.check_loops(getfield_gc=1)
+
 
 class TestLLtypeGreenFieldsTests(QuasiImmutTests, LLJitMixin):
     pass

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
@@ -560,11 +560,7 @@
                                        mutatefielddescr):
         from pypy.jit.metainterp.quasiimmut import SlowMutateDescr
         cpu = self.metainterp.cpu
-        fieldbox = executor.execute(cpu, self.metainterp, rop.GETFIELD_GC,
-                                    fielddescr, box)
-        fieldbox = fieldbox.constbox()
-        descr = SlowMutateDescr(cpu, box.getref_base(), fieldbox,
-                                fielddescr, mutatefielddescr)
+        descr = SlowMutateDescr(cpu, box, fielddescr, mutatefielddescr)
         self.metainterp.history.record(rop.QUASIIMMUT_FIELD, [box],
                                        None, descr=descr)
 


More information about the Pypy-commit mailing list