[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