[pypy-svn] r74706 - in pypy/branch/blackhole-improvement/pypy/jit: codewriter codewriter/test metainterp metainterp/test

arigo at codespeak.net arigo at codespeak.net
Mon May 24 15:37:30 CEST 2010


Author: arigo
Date: Mon May 24 15:37:28 2010
New Revision: 74706

Modified:
   pypy/branch/blackhole-improvement/pypy/jit/codewriter/flatten.py
   pypy/branch/blackhole-improvement/pypy/jit/codewriter/test/test_flatten.py
   pypy/branch/blackhole-improvement/pypy/jit/metainterp/blackhole.py
   pypy/branch/blackhole-improvement/pypy/jit/metainterp/pyjitpl.py
   pypy/branch/blackhole-improvement/pypy/jit/metainterp/resume.py
   pypy/branch/blackhole-improvement/pypy/jit/metainterp/test/test_exception.py
Log:
First set of fixes to exception handling.


Modified: pypy/branch/blackhole-improvement/pypy/jit/codewriter/flatten.py
==============================================================================
--- pypy/branch/blackhole-improvement/pypy/jit/codewriter/flatten.py	(original)
+++ pypy/branch/blackhole-improvement/pypy/jit/codewriter/flatten.py	Mon May 24 15:37:28 2010
@@ -128,6 +128,8 @@
                 self.emitline("%s_return" % kind, self.getcolor(args[0]))
         elif len(args) == 2:
             # exception block, raising an exception from a function
+            if isinstance(args[1], Variable):
+                self.emitline("-live-")     # xxx hack
             self.emitline("raise", self.getcolor(args[1]))
         else:
             raise Exception("?")

Modified: pypy/branch/blackhole-improvement/pypy/jit/codewriter/test/test_flatten.py
==============================================================================
--- pypy/branch/blackhole-improvement/pypy/jit/codewriter/test/test_flatten.py	(original)
+++ pypy/branch/blackhole-improvement/pypy/jit/codewriter/test/test_flatten.py	Mon May 24 15:37:28 2010
@@ -115,6 +115,7 @@
     def encoding_test(self, func, args, expected,
                       transform=False, liveness=False, cc=None):
         graphs = self.make_graphs(func, args)
+        #graphs[0].show()
         if transform:
             from pypy.jit.codewriter.jtransform import transform_graph
             cc = cc or FakeCallControl()
@@ -382,6 +383,37 @@
             raise $<* struct object>
         """)
 
+    def test_exc_finally(self):
+        def get_exception(n):
+            if n > 5:
+                raise ValueError
+        class Foo:
+            pass
+        Foo.__module__ = "test"
+        foo = Foo()
+        def f(i):
+            try:
+                get_exception(i)
+            finally:
+                foo.sideeffect = 5
+
+        self.encoding_test(f, [65], """
+        residual_call_ir_v $<* fn get_exception>, <Descr>, I[%i0], R[]
+        -live-
+        catch_exception L1
+        setfield_gc_i $<* struct test.Foo>, <Descr>, $5
+        void_return
+        ---
+        L1:
+        last_exception -> %i1
+        last_exc_value -> %r0
+        int_copy %i1 -> %i2
+        ref_copy %r0 -> %r1
+        setfield_gc_i $<* struct test.Foo>, <Descr>, $5
+        -live-
+        raise %r1
+        """, transform=True)
+
     def test_goto_if_not_int_is_true(self):
         def f(i):
             return not i

Modified: pypy/branch/blackhole-improvement/pypy/jit/metainterp/blackhole.py
==============================================================================
--- pypy/branch/blackhole-improvement/pypy/jit/metainterp/blackhole.py	(original)
+++ pypy/branch/blackhole-improvement/pypy/jit/metainterp/blackhole.py	Mon May 24 15:37:28 2010
@@ -305,8 +305,8 @@
             except LeaveFrame:
                 break
             except Exception, e:
-                e = get_llexception(self.cpu, e)
-                self.handle_exception_in_frame(e)
+                lle = get_llexception(self.cpu, e)
+                self.handle_exception_in_frame(lle)
 
     def get_tmpreg_i(self):
         return self.tmpreg_i
@@ -358,19 +358,20 @@
         # the exception is handled in the frame itself.
         code = self.jitcode.code
         position = self.position
-        opcode = ord(code[position])
-        if opcode != self.op_catch_exception:
-            # no 'catch_exception' insn follows: just reraise
-            if we_are_translated():
-                raise Exception, e
-            else:
-                etype = rclass.ll_type(e)
-                raise LLException(etype, e)
-        else:
-            # else store the exception on 'self', and jump to the handler
-            self.exception_last_value = e
-            target = ord(code[position+1]) | (ord(code[position+2])<<8)
-            self.position = target
+        if position < len(code):
+            opcode = ord(code[position])
+            if opcode == self.op_catch_exception:
+                # store the exception on 'self', and jump to the handler
+                self.exception_last_value = e
+                target = ord(code[position+1]) | (ord(code[position+2])<<8)
+                self.position = target
+                return
+        # no 'catch_exception' insn follows: just reraise
+        if we_are_translated():
+            raise Exception, e
+        else:
+            etype = rclass.ll_type(e)
+            raise LLException(etype, e)
 
     # XXX must be specialized
     def copy_constants(self, registers, constants):
@@ -761,15 +762,23 @@
 
     @arguments("self", "r")
     def bhimpl_raise(self, excvalue):
-        import pdb; pdb.set_trace()
-        XXX
-        raise real_instance
+        e = lltype.cast_opaque_ptr(rclass.OBJECTPTR, excvalue)
+        assert e
+        if we_are_translated():
+            raise Exception, e
+        else:
+            etype = rclass.ll_type(e)
+            raise LLException(etype, e)
 
     @arguments("self")
     def bhimpl_reraise(self):
-        real_instance = self.exception_last_value
-        assert real_instance
-        raise real_instance
+        e = self.exception_last_value
+        assert e
+        if we_are_translated():
+            raise Exception, e
+        else:
+            etype = rclass.ll_type(e)
+            raise LLException(etype, e)
 
     @arguments()
     def bhimpl_can_enter_jit():
@@ -1094,18 +1103,29 @@
               opnum == rop.GUARD_ISNULL or
               opnum == rop.GUARD_NONNULL_CLASS):
             # Produced by goto_if_not_ptr_{non,is}zero().  The pc is at the
-            # start of the opcode (so it will be redone).  This is needed
+            # start of the opcode (so it will be redone); this is needed
             # because of GUARD_NONNULL_CLASS.
             pass
+        #
         elif (opnum == rop.GUARD_NO_EXCEPTION or
               opnum == rop.GUARD_EXCEPTION or
-              opnum == rop.GUARD_NOT_FORCED or
-              opnum == rop.GUARD_NO_OVERFLOW or
-              opnum == rop.GUARD_OVERFLOW):
+              opnum == rop.GUARD_NOT_FORCED):
+            return self.cpu.grab_exc_value()
+        #
+        elif opnum == rop.GUARD_NO_OVERFLOW:
+            # Produced by int_xxx_ovf().  The pc is just after the opcode.
+            # We get here because it did not used to overflow, but now it does.
+            return get_llexception(self.cpu, OverflowError())
+        #
+        elif opnum == rop.GUARD_OVERFLOW:
+            # Produced by int_xxx_ovf().  The pc is just after the opcode.
+            # We get here because it used to overflow, but now it no longer
+            # does.
             pass
         else:
             from pypy.jit.metainterp.resoperation import opname
             raise NotImplementedError(opname[opnum])
+        return NULL
 
     # connect the return of values from the called frame to the
     # 'xxx_call_yyy' instructions from the caller frame
@@ -1116,9 +1136,6 @@
     def _setup_return_value_f(self, result):
         self.registers_f[ord(self.jitcode.code[self.position-1])] = result
 
-    def _exit_frame_with_exception(self, e):
-        xxx
-
     def _done_with_this_frame(self):
         # rare case: we only get there if the blackhole interps all returned
         # normally (in general we get a ContinueRunningNormally exception).
@@ -1135,6 +1152,12 @@
         else:
             assert False
 
+    def _exit_frame_with_exception(self, e):
+        # rare case
+        sd = self.builder.metainterp_sd
+        e = lltype.cast_opaque_ptr(llmemory.GCREF, e)
+        raise sd.ExitFrameWithExceptionRef(self.cpu, e)
+
 # ____________________________________________________________
 
 def resume_in_blackhole(metainterp_sd, resumedescr):
@@ -1147,9 +1170,9 @@
         False)  # XXX
     # XXX virtualrefs
     # XXX virtualizable
-    blackholeinterp._prepare_resume_from_failure(resumedescr.guard_opnum)
+    current_exc = blackholeinterp._prepare_resume_from_failure(
+        resumedescr.guard_opnum)
     try:
-        current_exc = blackholeinterp.cpu.grab_exc_value()
         current_exc = lltype.cast_opaque_ptr(rclass.OBJECTPTR, current_exc)
         while True:
             current_exc = blackholeinterp._resume_mainloop(current_exc)

Modified: pypy/branch/blackhole-improvement/pypy/jit/metainterp/pyjitpl.py
==============================================================================
--- pypy/branch/blackhole-improvement/pypy/jit/metainterp/pyjitpl.py	(original)
+++ pypy/branch/blackhole-improvement/pypy/jit/metainterp/pyjitpl.py	Mon May 24 15:37:28 2010
@@ -159,6 +159,8 @@
             assert oldbox not in registers[count:]
 
     def make_result_of_lastop(self, resultbox):
+        if resultbox is None:
+            return
         target_index = ord(self.bytecode[self.pc-1])
         if resultbox.type == history.INT:
             self.registers_i[target_index] = resultbox
@@ -194,6 +196,7 @@
             @arguments("box", "box")
             def opimpl_%s(self, b1, b2):
                 resbox = self.execute(rop.%s, b1, b2)
+                self.make_result_of_lastop(resbox)  # same as execute_varargs()
                 self.metainterp.handle_possible_overflow_error()
                 return resbox
         ''' % (_opimpl, _opimpl.upper())).compile()
@@ -680,7 +683,8 @@
 
     @FixME  #arguments("descr", "varargs")
     def opimpl_residual_call_loopinvariant(self, calldescr, varargs):
-        return self.execute_varargs(rop.CALL_LOOPINVARIANT, varargs, calldescr, exc=True)
+        return self.execute_varargs(rop.CALL_LOOPINVARIANT, varargs, calldescr,
+                                    exc=True)
 
     @FixME  #arguments("orgpc", "descr", "varargs")
     def opimpl_recursive_call(self, pc, calldescr, varargs):
@@ -767,15 +771,18 @@
 
     @FixME  #arguments("descr", "varargs")
     def opimpl_residual_oosend_canraise(self, methdescr, varargs):
-        return self.execute_varargs(rop.OOSEND, varargs, descr=methdescr, exc=True)
+        return self.execute_varargs(rop.OOSEND, varargs, descr=methdescr,
+                                    exc=True)
 
     @FixME  #arguments("descr", "varargs")
     def opimpl_residual_oosend_noraise(self, methdescr, varargs):
-        self.execute_varargs(rop.OOSEND, varargs, descr=methdescr, exc=False)
+        return self.execute_varargs(rop.OOSEND, varargs, descr=methdescr,
+                                    exc=False)
 
     @FixME  #arguments("descr", "varargs")
     def opimpl_residual_oosend_pure(self, methdescr, boxes):
-        self.execute_varargs(rop.OOSEND_PURE, boxes, descr=methdescr, exc=False)
+        return self.execute_varargs(rop.OOSEND_PURE, boxes, descr=methdescr,
+                                    exc=False)
 
     @arguments("orgpc", "box",)
     def _opimpl_guard_value(self, orgpc, box):
@@ -791,16 +798,6 @@
         self.generate_guard(rop.GUARD_CLASS, box, [clsbox], resumepc=orgpc)
         return clsbox
 
-##    @FixME  #arguments("orgpc", "box", "builtin")
-##    def opimpl_guard_builtin(self, pc, box, builtin):
-##        self.generate_guard(pc, "guard_builtin", box, [builtin])
-
-##    @FixME  #arguments("orgpc", "box", "builtin")
-##    def opimpl_guard_len(self, pc, box, builtin):
-##        intbox = self.metainterp.cpu.execute_operation(
-##            'len', [builtin.len_func, box], 'int')
-##        self.generate_guard(pc, "guard_len", box, [intbox])
-
     def verify_green_args(self, varargs):
         num_green_args = self.metainterp.staticdata.num_green_args
         for i in range(num_green_args):
@@ -861,11 +858,17 @@
         metainterp = self.metainterp
         last_exc_value_box = metainterp.last_exc_value_box
         assert last_exc_value_box is not None
+        assert metainterp.class_of_last_exc_is_const
         if not metainterp.cpu.ts.instanceOf(last_exc_value_box, vtablebox):
             self.pc = next_exc_target
 
-    @arguments("box")
-    def opimpl_raise(self, exc_value_box):
+    @arguments("orgpc", "box")
+    def opimpl_raise(self, orgpc, exc_value_box):
+        # xxx hack
+        clsbox = self.cls_of_box(exc_value_box)
+        self.generate_guard(rop.GUARD_CLASS, exc_value_box, [clsbox],
+                            resumepc=orgpc)
+        self.metainterp.class_of_last_exc_is_const = True
         self.metainterp.last_exc_value_box = exc_value_box
         self.metainterp.popframe()
         self.metainterp.finishframe_exception()
@@ -876,6 +879,20 @@
         self.metainterp.popframe()
         self.metainterp.finishframe_exception()
 
+    @arguments()
+    def opimpl_last_exception(self):
+        # Same comment as in opimpl_goto_if_exception_mismatch().
+        exc_value_box = self.metainterp.last_exc_value_box
+        assert exc_value_box is not None
+        assert self.metainterp.class_of_last_exc_is_const
+        return self.metainterp.cpu.ts.cls_of_box(exc_value_box)
+
+    @arguments()
+    def opimpl_last_exc_value(self):
+        exc_value_box = self.metainterp.last_exc_value_box
+        assert exc_value_box is not None
+        return exc_value_box
+
     @FixME  #arguments("box")
     def opimpl_virtual_ref(self, box):
         # Details on the content of metainterp.virtualref_boxes:
@@ -902,10 +919,9 @@
             # Note: we allocate a JIT_VIRTUAL_REF here
             # (in virtual_ref_during_tracing()), in order to detect when
             # the virtual escapes during tracing already.  We record it as a
-            # VIRTUAL_REF operation, although the backend sees this operation
-            # as a no-op.  The point is that the backend should not really see
-            # it in practice, as optimizeopt.py should either kill it or
-            # replace it with a NEW_WITH_VTABLE followed by SETFIELD_GCs.
+            # VIRTUAL_REF operation.  Later, optimizeopt.py should either kill
+            # that operation or replace it with a NEW_WITH_VTABLE followed by
+            # SETFIELD_GCs.
         metainterp.virtualref_boxes.append(box)
         metainterp.virtualref_boxes.append(resbox)
         self.make_result_box(resbox)
@@ -1027,6 +1043,9 @@
     def execute_varargs(self, opnum, argboxes, descr, exc):
         resbox = self.metainterp.execute_and_record_varargs(opnum, argboxes,
                                                             descr=descr)
+        self.make_result_of_lastop(resbox)
+        # ^^^ this is done before handle_possible_exception() because we need
+        # the box to show up in get_list_of_active_boxes()
         if exc:
             self.metainterp.handle_possible_exception()
         else:
@@ -1259,6 +1278,7 @@
         self.portal_trace_positions = []
         self.greenkey_of_huge_function = None
         self.free_frames_list = []
+        self.last_exc_value_box = None
 
     def is_blackholing(self):
         return False       # XXX get rid of this method
@@ -1299,8 +1319,7 @@
     def finishframe(self, resultbox):
         self.popframe()
         if self.framestack:
-            if resultbox is not None:
-                self.framestack[-1].make_result_of_lastop(resultbox)
+            self.framestack[-1].make_result_of_lastop(resultbox)
             raise ChangeFrame
         else:
             if not self.is_blackholing():
@@ -1335,12 +1354,14 @@
             frame = self.framestack[-1]
             code = frame.bytecode
             position = frame.pc    # <-- just after the insn that raised
-            opcode = ord(code[position])
-            if opcode == self.staticdata.op_catch_exception:
-                # found a 'catch_exception' instruction; jump to the handler
-                target = ord(code[position+1]) | (ord(code[position+2])<<8)
-                frame.pc = target
-                raise ChangeFrame
+            if position < len(code):
+                opcode = ord(code[position])
+                if opcode == self.staticdata.op_catch_exception:
+                    # found a 'catch_exception' instruction;
+                    # jump to the handler
+                    target = ord(code[position+1]) | (ord(code[position+2])<<8)
+                    frame.pc = target
+                    raise ChangeFrame
             self.popframe()
         if not self.is_blackholing():
             try:
@@ -1461,6 +1482,10 @@
         if constant:
             exc_value_box = exc_value_box.constbox()
         self.last_exc_value_box = exc_value_box
+        self.class_of_last_exc_is_const = constant
+        # 'class_of_last_exc_is_const' means that the class of the value
+        # stored in the exc_value Box can be assumed to be a Const.  This
+        # is only True after a GUARD_EXCEPTION or GUARD_CLASS.
 
     def execute_did_not_raise(self):
         self.last_exc_value_box = None
@@ -1647,8 +1672,7 @@
               opnum == rop.GUARD_ISNULL or
               opnum == rop.GUARD_NONNULL_CLASS):
             pass        # the pc is already set to the *start* of the opcode
-        elif (opnum == rop.GUARD_NO_EXCEPTION or opnum == rop.GUARD_EXCEPTION
-              or opnum == rop.GUARD_NOT_FORCED):
+        elif opnum == rop.GUARD_NO_EXCEPTION or opnum == rop.GUARD_EXCEPTION:
             exception = self.cpu.grab_exc_value()
             if exception:
                 self.execute_raised(exception)
@@ -1657,9 +1681,12 @@
             self.handle_possible_exception()
         elif opnum == rop.GUARD_NO_OVERFLOW:   # an overflow now detected
             self.execute_raised(OverflowError(), constant=True)
-            self.finishframe_exception()
+            try:
+                self.finishframe_exception()
+            except ChangeFrame:
+                pass
         elif opnum == rop.GUARD_OVERFLOW:      # no longer overflowing
-            pass
+            self.execute_did_not_raise()
         else:
             from pypy.jit.metainterp.resoperation import opname
             raise NotImplementedError(opname[opnum])
@@ -1855,27 +1882,29 @@
 
     def handle_possible_exception(self):
         frame = self.framestack[-1]
-        if self.last_exc_value_box:
+        if self.last_exc_value_box is not None:
             exception_box = self.cpu.ts.cls_of_box(self.last_exc_value_box)
             op = frame.generate_guard(rop.GUARD_EXCEPTION,
                                       None, [exception_box])
-            if op:
-                op.result = self.last_exc_value_box
+            assert op is not None
+            op.result = self.last_exc_value_box
+            self.class_of_last_exc_is_const = True
             self.finishframe_exception()
         else:
             frame.generate_guard(rop.GUARD_NO_EXCEPTION, None, [])
 
     def handle_possible_overflow_error(self):
         frame = self.framestack[-1]
-        if self.last_exc_value_box:
+        if self.last_exc_value_box is not None:
             frame.generate_guard(rop.GUARD_OVERFLOW, None)
             assert isinstance(self.last_exc_value_box, Const)
+            assert self.class_of_last_exc_is_const
             self.finishframe_exception()
         else:
             frame.generate_guard(rop.GUARD_NO_OVERFLOW, None)
 
     def assert_no_exception(self):
-        assert not self.last_exc_value_box
+        assert self.last_exc_value_box is None
 
     def rebuild_state_after_failure(self, resumedescr):
         vinfo = self.staticdata.virtualizable_info
@@ -2130,10 +2159,8 @@
         num_return_args = len(argcodes) - next_argcode
         assert num_return_args == 0 or num_return_args == 2
         if num_return_args:
-            # Save the type of the resulting box.  This is needed if the
-            # operation is an inlined call and we need to get the list of
-            # all alive boxes in it, to know that the result box was not
-            # written yet.
+            # Save the type of the resulting box.  This is needed if there is
+            # a get_list_of_active_boxes().  See comments there.
             self._result_argcode = argcodes[next_argcode + 1]
             position += 1
         else:
@@ -2160,8 +2187,7 @@
         else:
             resultbox = unboundmethod(self, *args)
         #
-        if resultbox is not None:
-            self.make_result_of_lastop(resultbox)
+        self.make_result_of_lastop(resultbox)
     #
     unboundmethod = getattr(MIFrame, 'opimpl_' + name).im_func
     argtypes = unrolling_iterable(unboundmethod.argtypes)

Modified: pypy/branch/blackhole-improvement/pypy/jit/metainterp/resume.py
==============================================================================
--- pypy/branch/blackhole-improvement/pypy/jit/metainterp/resume.py	(original)
+++ pypy/branch/blackhole-improvement/pypy/jit/metainterp/resume.py	Mon May 24 15:37:28 2010
@@ -32,10 +32,13 @@
 
 def _ensure_parent_resumedata(framestack, n):
     target = framestack[n]
-    if n == 0 or target.parent_resumedata_frame_info_list is not None:
+    if n == 0:
         return
-    _ensure_parent_resumedata(framestack, n-1)
     back = framestack[n-1]
+    if target.parent_resumedata_frame_info_list is not None:
+        assert target.parent_resumedata_frame_info_list.pc == back.pc
+        return
+    _ensure_parent_resumedata(framestack, n-1)
     target.parent_resumedata_frame_info_list = FrameInfo(
                                          back.parent_resumedata_frame_info_list,
                                          back.jitcode,

Modified: pypy/branch/blackhole-improvement/pypy/jit/metainterp/test/test_exception.py
==============================================================================
--- pypy/branch/blackhole-improvement/pypy/jit/metainterp/test/test_exception.py	(original)
+++ pypy/branch/blackhole-improvement/pypy/jit/metainterp/test/test_exception.py	Mon May 24 15:37:28 2010
@@ -2,7 +2,7 @@
 from pypy.jit.metainterp.test.test_basic import LLJitMixin, OOJitMixin
 from pypy.rlib.jit import JitDriver, OPTIMIZER_SIMPLE
 from pypy.rlib.rarithmetic import ovfcheck, LONG_BIT, intmask
-from pypy.jit.metainterp.policy import StopAtXPolicy
+from pypy.jit.codewriter.policy import StopAtXPolicy
 
 
 class ExceptionTests:



More information about the Pypy-commit mailing list