Author: Carl Friedrich Bolz <[email protected]>
Branch: guard-compatible
Changeset: r86269:2963715f455b
Date: 2016-08-18 11:44 +0200
http://bitbucket.org/pypy/pypy/changeset/2963715f455b/

Log:    guard_compatible was broken by b116f09c4e9d: by removing the quasi-
        immut operations, the guard_compatible optimizer doesn't see them
        early enough. Fix it by making clearing this cache when emmitting a
        guard_compatible

diff --git a/rpython/jit/metainterp/heapcache.py 
b/rpython/jit/metainterp/heapcache.py
--- a/rpython/jit/metainterp/heapcache.py
+++ b/rpython/jit/metainterp/heapcache.py
@@ -163,6 +163,10 @@
         # maps descrs to {index: CacheEntry} dicts
         self.heap_array_cache = {}
 
+        # maps descrs to CacheEntry, contains only descrs that are
+        # quasi-immutable
+        self.quasi_immut_descrs = {}
+
     def reset_keep_likely_virtuals(self):
         # Update only 'head_version', but 'likely_virtual_version' remains
         # at its older value.
@@ -511,7 +515,17 @@
         cache = self.heap_cache.get(fielddescr, None)
         if cache is None:
             cache = self.heap_cache[fielddescr] = CacheEntry(self)
+        self.quasi_immut_descrs[fielddescr] = cache
         if cache.quasiimmut_seen is not None:
             cache.quasiimmut_seen[box] = None
         else:
             cache.quasiimmut_seen = {box: None}
+
+    def invalidate_quasi_immut(self, box):
+        # slow, but should be rare
+        for fielddescr, cache in self.quasi_immut_descrs.iteritems():
+            if cache.quasiimmut_seen:
+                try:
+                    del cache.quasiimmut_seen[box]
+                except KeyError:
+                    pass
diff --git a/rpython/jit/metainterp/pyjitpl.py 
b/rpython/jit/metainterp/pyjitpl.py
--- a/rpython/jit/metainterp/pyjitpl.py
+++ b/rpython/jit/metainterp/pyjitpl.py
@@ -1209,7 +1209,11 @@
             self.metainterp.generate_guard(rop.GUARD_COMPATIBLE, box, 
[promoted_box],
                                            resumepc=orgpc)
             self.metainterp.heapcache.have_guard_compatible_now(box)
-            # importantly, there is no replace_box here!
+            # it's necessary to not cache quasi-immutable reads on this box
+            # the guard-compatible machinery needs to see the quasi-immutable
+            # read
+            self.metainterp.heapcache.invalidate_quasi_immut(box)
+            # importantly, there is no replace_box here (unlike guard_value)
 
     @arguments("box", "orgpc")
     def opimpl_guard_class(self, box, orgpc):
diff --git a/rpython/jit/metainterp/test/test_compatible.py 
b/rpython/jit/metainterp/test/test_compatible.py
--- a/rpython/jit/metainterp/test/test_compatible.py
+++ b/rpython/jit/metainterp/test/test_compatible.py
@@ -622,6 +622,7 @@
                 self.num = num
                 self.version = Version()
                 self.dct = {}
+                self.classdct = {}
 
             def instantiate(self):
                 return Obj(self)
@@ -630,6 +631,10 @@
             def lookup_version(self, version, name):
                 return self.dct.get(name, -1)
 
+            
@jit.elidable_compatible(quasi_immut_field_name_for_second_arg='version')
+            def lookup_class(self, version, name):
+                return self.classdct.get(name, -1)
+
         class Version(object):
             pass
 
@@ -641,18 +646,30 @@
                 map = self.map
                 assert isinstance(map, Map)
                 map = jit.hint(map, promote_compatible=True)
-                return map.lookup_version(name)
+                result = map.lookup_version(name)
+                if result == -1:
+                    return map.lookup_class(name)
+                return result
 
         m1 = Map(1)
         m1.dct['a'] = 1
         m1.dct['b'] = 2
+        m1.classdct['d'] = 4
+        m1.classdct['e'] = 5
         m2 = Map(2)
         m2.dct['a'] = 1
         m2.dct['b'] = 2
         m2.dct['c'] = 5
+        m2.classdct['d'] = 4
+        m2.classdct['e'] = 5
+        m2.classdct['f'] = 5
+
+        m3 = Map(3)
+        m3.version = None
 
         p1 = m1.instantiate()
         p2 = m2.instantiate()
+        p3 = m3.instantiate()
 
         driver = jit.JitDriver(greens = [], reds = ['n', 'res', 'p'])
 
@@ -660,15 +677,21 @@
             res = p.map.num
             while n > 0:
                 driver.jit_merge_point(n=n, p=p, res=res)
-                res += p.lookup('a')
-                res += p.lookup('c')
-                res += p.lookup('b')
+                version = p.map.version
+                if version is not None:
+                    res += p.lookup('a')
+                    res += p.lookup('c')
+                    res += p.lookup('b')
+                    res += p.lookup('d')
+                    res += p.lookup('e')
+                    res += p.lookup('f')
                 n -= 1
             return res
 
         def main(x):
             res = f(100, p1)
             res = f(100, p2)
+            res = f(100, p3)
         main(True)
         main(False)
 
diff --git a/rpython/jit/metainterp/test/test_tracingopts.py 
b/rpython/jit/metainterp/test/test_tracingopts.py
--- a/rpython/jit/metainterp/test/test_tracingopts.py
+++ b/rpython/jit/metainterp/test/test_tracingopts.py
@@ -538,6 +538,34 @@
         self.check_operations_history(quasiimmut_field=1)
 
 
+    def test_heap_caching_quasi_immutable_clear_after_guard_compatible(self):
+        class A:
+            _immutable_fields_ = ['x?']
+        a1 = A()
+        a1.x = 5
+        a2 = A()
+        a2.x = 7
+
+        @jit.elidable
+        def get(n):
+            if n > 0:
+                return a1
+            return a2
+
+        def g(a):
+            return a.x
+
+        def fn(n):
+            a = get(n)
+            res = g(a)
+            jit.hint(a, promote_compatible=True)
+            return res + a.x
+
+        res = self.interp_operations(fn, [7])
+        assert res == 10
+        self.check_operations_history(quasiimmut_field=2)
+
+
     def test_heap_caching_multiple_tuples(self):
         class Gbl(object):
             pass
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to