Author: Armin Rigo <ar...@tunes.org>
Branch: 
Changeset: r82267:96c2ec82f010
Date: 2016-02-15 16:32 +0100
http://bitbucket.org/pypy/pypy/changeset/96c2ec82f010/

Log:    Test and fix for another corner case (likely shown by Krakatau)

diff --git a/rpython/jit/metainterp/optimizeopt/rewrite.py 
b/rpython/jit/metainterp/optimizeopt/rewrite.py
--- a/rpython/jit/metainterp/optimizeopt/rewrite.py
+++ b/rpython/jit/metainterp/optimizeopt/rewrite.py
@@ -380,7 +380,7 @@
                     raise InvalidLoop("promote of a virtual")
                 old_guard_op = info.get_last_guard(self.optimizer)
                 if old_guard_op is not None:
-                    op = self.replace_guard_class_with_guard_value(op, info,
+                    op = self.replace_old_guard_with_guard_value(op, info,
                                                               old_guard_op)
         elif arg0.type == 'f':
             arg0 = self.get_box_replacement(arg0)
@@ -390,11 +390,26 @@
         assert isinstance(constbox, Const)
         self.optimize_guard(op, constbox)
 
-    def replace_guard_class_with_guard_value(self, op, info, old_guard_op):
-        if old_guard_op.opnum != rop.GUARD_NONNULL:
-            previous_classbox = info.get_known_class(self.optimizer.cpu)
-            expected_classbox = self.optimizer.cpu.ts.cls_of_box(op.getarg(1))
-            assert previous_classbox is not None
+    def replace_old_guard_with_guard_value(self, op, info, old_guard_op):
+        # there already has been a guard_nonnull or guard_class or
+        # guard_nonnull_class on this value, which is rather silly.
+        # This function replaces the original guard with a
+        # guard_value.  Must be careful: doing so is unsafe if the
+        # original guard checks for something inconsistent,
+        # i.e. different than what it would give if the guard_value
+        # passed (this is a rare case, but possible).  If we get
+        # inconsistent results in this way, then we must not do the
+        # replacement, otherwise we'd put guard_value up there but all
+        # intermediate ops might be executed by assuming something
+        # different, from the old guard that is now removed...
+
+        c_value = op.getarg(1)
+        if not c_value.nonnull():
+            raise InvalidLoop('A GUARD_VALUE(..., NULL) follows some other '
+                              'guard that it is not NULL')
+        previous_classbox = info.get_known_class(self.optimizer.cpu)
+        if previous_classbox is not None:
+            expected_classbox = self.optimizer.cpu.ts.cls_of_box(c_value)
             assert expected_classbox is not None
             if not previous_classbox.same_constant(
                     expected_classbox):
diff --git a/rpython/jit/metainterp/optimizeopt/test/test_optimizeopt.py 
b/rpython/jit/metainterp/optimizeopt/test/test_optimizeopt.py
--- a/rpython/jit/metainterp/optimizeopt/test/test_optimizeopt.py
+++ b/rpython/jit/metainterp/optimizeopt/test/test_optimizeopt.py
@@ -3063,6 +3063,16 @@
         self.optimize_loop(ops, expected, preamble)
         #self.check_expanded_fail_descr("i0", rop.GUARD_VALUE)
 
+    def test_invalid_guard_value_after_guard_class(self):
+        ops = """
+        [p1, i0, i1, i2, p2]
+        guard_class(p1, ConstClass(node_vtable)) [i0]
+        i3 = int_add(i1, i2)
+        guard_value(p1, NULL) [i1]
+        jump(p2, i0, i1, i3, p2)
+        """
+        self.raises(InvalidLoop, self.optimize_loop, ops, ops)
+
     def test_guard_class_oois(self):
         ops = """
         [p1]
_______________________________________________
pypy-commit mailing list
pypy-commit@python.org
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to