[pypy-commit] pypy default: Fix for 004a5d649ed9 (issue #2132). See comment in pyjitpl.py.

arigo noreply at buildbot.pypy.org
Sun Oct 11 10:26:28 CEST 2015


Author: Armin Rigo <arigo at tunes.org>
Branch: 
Changeset: r80106:66ca1ac6c1dc
Date: 2015-10-11 09:31 +0200
http://bitbucket.org/pypy/pypy/changeset/66ca1ac6c1dc/

Log:	Fix for 004a5d649ed9 (issue #2132). See comment in pyjitpl.py.

diff --git a/rpython/jit/backend/llgraph/runner.py b/rpython/jit/backend/llgraph/runner.py
--- a/rpython/jit/backend/llgraph/runner.py
+++ b/rpython/jit/backend/llgraph/runner.py
@@ -40,10 +40,13 @@
         self.inputargs = map(mapping, inputargs)
         self.operations = []
         for op in operations:
-            if op.getopnum() == rop.GUARD_VALUE:
+            opnum = op.getopnum()
+            if opnum == rop.GUARD_VALUE:
                 # we don't care about the value 13 here, because we gonna
                 # fish it from the extra slot on frame anyway
                 op.getdescr().make_a_counter_per_value(op, 13)
+            elif opnum == rop.BRIDGE_EXCEPTION:
+                assert len(self.operations) == 0   # must be first
             if op.getdescr() is not None:
                 if op.is_guard() or op.getopnum() == rop.FINISH:
                     newdescr = op.getdescr()
@@ -890,7 +893,10 @@
 
     # -----------------------------------------------------
 
-    def fail_guard(self, descr, saved_data=None, extra_value=None):
+    def fail_guard(self, descr, saved_data=None, extra_value=None,
+                   propagate_exception=False):
+        if not propagate_exception:
+            assert self.last_exception is None
         values = []
         for box in self.current_op.getfailargs():
             if box is not None:
@@ -899,6 +905,9 @@
                 value = None
             values.append(value)
         if hasattr(descr, '_llgraph_bridge'):
+            if propagate_exception:
+                assert (descr._llgraph_bridge.operations[0].opnum ==
+                        rop.BRIDGE_EXCEPTION)
             target = (descr._llgraph_bridge, -1)
             values = [value for value in values if value is not None]
             raise Jump(target, values)
@@ -977,7 +986,7 @@
 
     def execute_guard_no_exception(self, descr):
         if self.last_exception is not None:
-            self.fail_guard(descr)
+            self.fail_guard(descr, propagate_exception=True)
 
     def execute_guard_exception(self, descr, excklass):
         lle = self.last_exception
@@ -989,7 +998,7 @@
             llmemory.cast_int_to_adr(excklass),
             rclass.CLASSTYPE)
         if gotklass != excklass:
-            self.fail_guard(descr)
+            self.fail_guard(descr, propagate_exception=True)
         #
         res = lle.args[1]
         self.last_exception = None
@@ -998,7 +1007,7 @@
     def execute_guard_not_forced(self, descr):
         if self.forced_deadframe is not None:
             saved_data = self.forced_deadframe._saved_data
-            self.fail_guard(descr, saved_data)
+            self.fail_guard(descr, saved_data, propagate_exception=True)
         self.force_guard_op = self.current_op
     execute_guard_not_forced_2 = execute_guard_not_forced
 
@@ -1220,6 +1229,9 @@
     def execute_keepalive(self, descr, x):
         pass
 
+    def execute_bridge_exception(self, descr):
+        pass
+
 
 def _getdescr(op):
     d = op.getdescr()
diff --git a/rpython/jit/backend/llsupport/rewrite.py b/rpython/jit/backend/llsupport/rewrite.py
--- a/rpython/jit/backend/llsupport/rewrite.py
+++ b/rpython/jit/backend/llsupport/rewrite.py
@@ -1,4 +1,5 @@
 from rpython.rlib import rgc
+from rpython.rlib.objectmodel import we_are_translated
 from rpython.rlib.rarithmetic import ovfcheck
 from rpython.rtyper.lltypesystem import llmemory, lltype
 from rpython.jit.metainterp import history
@@ -14,6 +15,9 @@
 FLAG_STR = 1
 FLAG_UNICODE = 2
 
+class BridgeExceptionNotFirst(Exception):
+    pass
+
 class GcRewriterAssembler(object):
     """ This class performs the following rewrites on the list of operations:
 
@@ -164,6 +168,9 @@
                 continue
             if op.getopnum() == rop.JUMP or op.getopnum() == rop.FINISH:
                 self.emit_pending_zeros()
+            if op.getopnum() == rop.BRIDGE_EXCEPTION:
+                self.remove_bridge_exception(operations, i)
+                continue
             #
             self.emit_op(op)
         return self._newops
@@ -678,3 +685,14 @@
             # assume that "self.gc_ll_descr.minimal_size_in_nursery" is 2 WORDs
             size = max(size, 2 * WORD)
             return (size + WORD-1) & ~(WORD-1)     # round up
+
+    def remove_bridge_exception(self, operations, i):
+        """Check that the 'bridge_exception' operation occurs at the
+        start of the bridge."""
+        if i == 0:
+            return     # first operation, ok
+        if i == 1 and operations[0].getopnum() == rop.INCREMENT_DEBUG_COUNTER:
+            return     # 2nd operation after INCREMENT_DEBUG_COUNTER, ok
+        # not ok!
+        assert we_are_translated()
+        raise BridgeExceptionNotFirst
diff --git a/rpython/jit/metainterp/executor.py b/rpython/jit/metainterp/executor.py
--- a/rpython/jit/metainterp/executor.py
+++ b/rpython/jit/metainterp/executor.py
@@ -386,6 +386,7 @@
                          rop.CALL_MALLOC_NURSERY_VARSIZE_FRAME,
                          rop.NURSERY_PTR_INCREMENT,
                          rop.LABEL,
+                         rop.BRIDGE_EXCEPTION,
                          ):      # list of opcodes never executed by pyjitpl
                 continue
             raise AssertionError("missing %r" % (key,))
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
@@ -2480,6 +2480,21 @@
         exception = self.cpu.grab_exc_value(deadframe)
         if (isinstance(resumedescr, compile.ResumeGuardExcDescr) or
             isinstance(resumedescr, compile.ResumeGuardCopiedExcDescr)):
+            # Add a GUARD_EXCEPTION or GUARD_NO_EXCEPTION at the start
+            # of the bridge---except it is not really the start, because
+            # the history aleady contains operations from resume.py.
+            # The optimizer should remove these operations.  However,
+            # 'test_guard_no_exception_incorrectly_removed_from_bridge'
+            # shows a corner case in which just putting GuARD_NO_EXCEPTION
+            # here is a bad idea: the optimizer might remove it too.
+            # So we put a pair BRIDGE_EXCEPTION / GUARD_(NO)_EXCEPTION.
+            # The BRIDGE_EXCEPTION is meant to re-raise the exception
+            # caught before the bridge, but in reality it must end up
+            # as the first operation and thus is a no-op for the backends
+            # (it is removed in rewrite.py).  Its real purpose is only to
+            # pass through the optimizer unmodified, so that the following
+            # GUARD_NO_EXCEPTION is not killed.
+            self.history.record(rop.BRIDGE_EXCEPTION, [], None)
             if exception:
                 self.execute_ll_raised(lltype.cast_opaque_ptr(rclass.OBJECTPTR,
                                                               exception))
diff --git a/rpython/jit/metainterp/resoperation.py b/rpython/jit/metainterp/resoperation.py
--- a/rpython/jit/metainterp/resoperation.py
+++ b/rpython/jit/metainterp/resoperation.py
@@ -827,6 +827,7 @@
     'QUASIIMMUT_FIELD/1d/n',    # [objptr], descr=SlowMutateDescr
     'RECORD_EXACT_CLASS/2/n',   # [objptr, clsptr]
     'KEEPALIVE/1/n',
+    'BRIDGE_EXCEPTION/0/n',     # pyjitpl: prepare_resume_from_failure()
 
     '_CANRAISE_FIRST', # ----- start of can_raise operations -----
     '_CALL_FIRST',


More information about the pypy-commit mailing list