[pypy-commit] pypy py3.5-refactor-sys_exc_info: (arigo, cfbolz, richard around):
cfbolz
pypy.commits at gmail.com
Tue Nov 15 13:13:47 EST 2016
Author: Carl Friedrich Bolz <cfbolz at gmx.de>
Branch: py3.5-refactor-sys_exc_info
Changeset: r88393:195ff4d7c074
Date: 2016-11-15 18:23 +0000
http://bitbucket.org/pypy/pypy/changeset/195ff4d7c074/
Log: (arigo, cfbolz, richard around):
in progress: start a refactoring to store sys_exc_info on the ec,
instead of having last_exception on each frame. this makes it more
like CPython and should make it possible to not force every frame
when an exception is raised.
diff --git a/pypy/interpreter/error.py b/pypy/interpreter/error.py
--- a/pypy/interpreter/error.py
+++ b/pypy/interpreter/error.py
@@ -333,13 +333,12 @@
tb = tb.next
self._application_traceback = tb
- def record_context(self, space, frame):
- """Record a __context__ for this exception if one exists,
- searching from the current frame.
+ def record_context(self, space, ec):
+ """Record a __context__ for this exception if one exists.
"""
if self._context_recorded:
return
- last = frame._exc_info_unroll(space)
+ last = ec.sys_exc_info()
try:
if last is not None:
self.chain_exceptions(space, last)
diff --git a/pypy/interpreter/executioncontext.py b/pypy/interpreter/executioncontext.py
--- a/pypy/interpreter/executioncontext.py
+++ b/pypy/interpreter/executioncontext.py
@@ -28,6 +28,10 @@
def __init__(self, space):
self.space = space
self.topframeref = jit.vref_None
+ # this is exposed to app-level as 'sys.exc_info()'. At any point in
+ # time it is the exception caught by the topmost 'except ... as e:'
+ # app-level block.
+ self.sys_exc_operror = None
self.w_tracefunc = None
self.is_tracing = 0
self.compiler = space.createcompiler()
@@ -230,23 +234,10 @@
# NOTE: the result is not the wrapped sys.exc_info() !!!
"""
- return self.gettopframe()._exc_info_unroll(self.space)
+ return self.sys_exc_operror
def set_sys_exc_info(self, operror):
- frame = self.gettopframe_nohidden()
- if frame: # else, the exception goes nowhere and is lost
- frame.last_exception = operror
-
- def clear_sys_exc_info(self):
- # Find the frame out of which sys_exc_info() would return its result,
- # and hack this frame's last_exception to become the cleared
- # OperationError (which is different from None!).
- frame = self.gettopframe_nohidden()
- while frame:
- if frame.last_exception is not None:
- frame.last_exception = get_cleared_operation_error(self.space)
- break
- frame = self.getnextframe_nohidden(frame)
+ self.sys_exc_operror = operror
@jit.dont_look_inside
def settrace(self, w_func):
@@ -356,7 +347,6 @@
event == 'c_exception'):
return
- last_exception = frame.last_exception
if event == 'leaveframe':
event = 'return'
@@ -372,7 +362,6 @@
raise
finally:
- frame.last_exception = last_exception
self.is_tracing -= 1
def checksignals(self):
diff --git a/pypy/interpreter/pyframe.py b/pypy/interpreter/pyframe.py
--- a/pypy/interpreter/pyframe.py
+++ b/pypy/interpreter/pyframe.py
@@ -66,7 +66,6 @@
f_generator_wref = rweakref.dead_ref # for generators/coroutines
f_generator_nowref = None # (only one of the two attrs)
last_instr = -1
- last_exception = None
f_backref = jit.vref_None
escaped = False # see mark_as_escaped()
@@ -328,10 +327,6 @@
executioncontext)
finally:
executioncontext.return_trace(self, w_exitvalue)
- # it used to say self.last_exception = None
- # this is now done by the code in pypyjit module
- # since we don't want to invalidate the virtualizable
- # for no good reason
got_exception = False
finally:
executioncontext.leave(self, w_exitvalue, got_exception)
@@ -882,33 +877,6 @@
def fdel_f_trace(self, space):
self.getorcreatedebug().w_f_trace = None
- def fget_f_exc_type(self, space):
- if self.last_exception is not None:
- f = self.f_backref()
- while f is not None and f.last_exception is None:
- f = f.f_backref()
- if f is not None:
- return f.last_exception.w_type
- return space.w_None
-
- def fget_f_exc_value(self, space):
- if self.last_exception is not None:
- f = self.f_backref()
- while f is not None and f.last_exception is None:
- f = f.f_backref()
- if f is not None:
- return f.last_exception.get_w_value(space)
- return space.w_None
-
- def fget_f_exc_traceback(self, space):
- if self.last_exception is not None:
- f = self.f_backref()
- while f is not None and f.last_exception is None:
- f = f.f_backref()
- if f is not None:
- return space.wrap(f.last_exception.get_traceback())
- return space.w_None
-
def fget_f_restricted(self, space):
if space.config.objspace.honor__builtins__:
return space.wrap(self.builtin is not space.builtin)
diff --git a/pypy/interpreter/pyopcode.py b/pypy/interpreter/pyopcode.py
--- a/pypy/interpreter/pyopcode.py
+++ b/pypy/interpreter/pyopcode.py
@@ -73,7 +73,7 @@
try:
next_instr = self.dispatch_bytecode(co_code, next_instr, ec)
except OperationError as operr:
- operr.record_context(self.space, self)
+ operr.record_context(self.space, ec)
next_instr = self.handle_operation_error(ec, operr)
except RaiseWithExplicitTraceback as e:
next_instr = self.handle_operation_error(ec, e.operr,
@@ -688,12 +688,11 @@
if nbargs > 2:
raise BytecodeCorruption("bad RAISE_VARARGS oparg")
if nbargs == 0:
- last_operr = self._exc_info_unroll(space, for_hidden=True)
+ last_operr = self.space.getexecutioncontext().sys_exc_info()
if last_operr is None:
raise oefmt(space.w_RuntimeError,
"No active exception to reraise")
# re-raise, no new traceback obj will be attached
- self.last_exception = last_operr
raise RaiseWithExplicitTraceback(last_operr)
if nbargs == 2:
w_cause = self.popvalue()
@@ -747,14 +746,20 @@
self.setdictscope(w_locals)
def POP_EXCEPT(self, oparg, next_instr):
- block = self.pop_block()
- block.cleanup(self)
- return
+ pass # no-op for now: done by the END_FINALLY that follows anyway
def POP_BLOCK(self, oparg, next_instr):
block = self.pop_block()
block.cleanup(self) # the block knows how to clean up the value stack
+ def save_and_change_sys_exc_info(self, operationerr):
+ ec = self.space.getexecutioncontext()
+ last_exception = ec.sys_exc_info()
+ block = SysExcInfoRestorer(last_exception, self.lastblock)
+ self.lastblock = block
+ if operationerr is not None: # otherwise, don't change sys_exc_info
+ ec.set_sys_exc_info(operationerr)
+
def end_finally(self):
# unlike CPython, there are two statically distinct cases: the
# END_FINALLY might be closing an 'except' block or a 'finally'
@@ -763,8 +768,14 @@
# [exception value we are now handling]
# [wrapped SApplicationException]
# In the case of a finally: block, the stack contains only one
- # item (unlike CPython which can have 1, 2 or 3 items):
+ # item (unlike CPython which can have 1, 2, 3 or 5 items, and
+ # even in one case a non-fixed number of items):
# [wrapped subclass of SuspendedUnroller]
+
+ block = self.pop_block()
+ assert isinstance(block, SysExcInfoRestorer)
+ block.cleanupstack() # restores ec.sys_exc_operror
+
w_top = self.popvalue()
if self.space.is_w(w_top, self.space.w_None):
# case of a finally: block with no exception
@@ -1137,8 +1148,8 @@
w_exit = self.space.get(w_descr, w_manager)
self.settopvalue(w_exit)
w_result = self.space.get_and_call_function(w_enter, w_manager)
- block = WithBlock(self.valuestackdepth,
- next_instr + offsettoend, self.lastblock)
+ block = FinallyBlock(self.valuestackdepth,
+ next_instr + offsettoend, self.lastblock)
self.lastblock = block
self.pushvalue(w_result)
@@ -1150,6 +1161,7 @@
if isinstance(w_unroller, SApplicationException):
# app-level exception
operr = w_unroller.operr
+ # this looks again like the kind of code we have. except that it's a call, not a block
old_last_exception = self.last_exception
self.last_exception = operr
w_traceback = self.space.wrap(operr.get_traceback())
@@ -1183,6 +1195,7 @@
if self.space.is_true(w_suppress):
# __exit__() returned True -> Swallow the exception.
self.settopvalue(self.space.w_None)
+ # this is always followed by END_FINALLY
@jit.unroll_safe
def call_function(self, oparg, w_starstar=None, has_vararg=False):
@@ -1680,28 +1693,26 @@
return r_uint(self.handlerposition)
-class ExceptHandlerBlock(FrameBlock):
+class SysExcInfoRestorer(FrameBlock):
"""
- This is a special, implicit block type which is created when entering an
- except handler. It does not belong to any opcode
+ This is a special, implicit block type which is created when entering a
+ finally or except handler. It does not belong to any opcode
"""
_immutable_ = True
- _opname = 'EXCEPT_HANDLER_BLOCK' # it's not associated to any opcode
+ _opname = 'SYS_EXC_INFO_RESTORER' # it's not associated to any opcode
handling_mask = 0 # this block is never handled, only popped by POP_EXCEPT
+ def __init__(self, operr, previous):
+ self.operr = operr
+ self.previous = previous
+
def handle(self, frame, unroller):
assert False # never called
def cleanupstack(self, frame):
- frame.dropvaluesuntil(self.valuestackdepth+1)
- w_last_exception = frame.popvalue()
- if not isinstance(w_last_exception, W_OperationError):
- msg = "expected an OperationError, got %s" % (
- frame.space.str_w(w_last_exception))
- raise BytecodeCorruption(msg)
- frame.last_exception = w_last_exception.operr
- FrameBlock.cleanupstack(self, frame)
+ ec = frame.space.getexecutioncontext()
+ ec.set_sys_exc_info(self.operr)
class ExceptBlock(FrameBlock):
@@ -1715,22 +1726,18 @@
# push the exception to the value stack for inspection by the
# exception handler (the code after the except:)
self.cleanupstack(frame)
+ # the stack setup is slightly different than in CPython:
+ # instead of the traceback, we store the unroller object,
+ # wrapped.
assert isinstance(unroller, SApplicationException)
operationerr = unroller.operr
operationerr.normalize_exception(frame.space)
- # the stack setup is slightly different than in CPython:
- # instead of the traceback, we store the unroller object,
- # wrapped.
- # this is popped by POP_EXCEPT, which is present only in py3k
- w_last_exception = W_OperationError(frame.last_exception)
- w_last_exception = frame.space.wrap(w_last_exception)
- frame.pushvalue(w_last_exception)
- block = ExceptHandlerBlock(self.valuestackdepth, 0, frame.lastblock)
- frame.lastblock = block
frame.pushvalue(frame.space.wrap(unroller))
frame.pushvalue(operationerr.get_w_value(frame.space))
frame.pushvalue(operationerr.w_type)
- frame.last_exception = operationerr
+ # set the current value of sys_exc_info to operationerr,
+ # saving the old value in a custom type of FrameBlock
+ frame.save_and_change_sys_exc_info(operationerr)
return r_uint(self.handlerposition) # jump to the handler
@@ -1740,7 +1747,6 @@
_immutable_ = True
_opname = 'SETUP_FINALLY'
handling_mask = -1 # handles every kind of SuspendedUnroller
- restore_last_exception = True # set to False by WithBlock
def handle(self, frame, unroller):
# any abnormal reason for unrolling a finally: triggers the end of
@@ -1752,53 +1758,44 @@
operationerr = unroller.operr
operationerr.normalize_exception(frame.space)
frame.pushvalue(frame.space.wrap(unroller))
- if operationerr and self.restore_last_exception:
- frame.last_exception = operationerr
+ # set the current value of sys_exc_info to operationerr,
+ # saving the old value in a custom type of FrameBlock
+ frame.save_and_change_sys_exc_info(operationerr)
return r_uint(self.handlerposition) # jump to the handler
-class WithBlock(FinallyBlock):
-
- _immutable_ = True
- restore_last_exception = False
-
- def handle(self, frame, unroller):
- if isinstance(unroller, SApplicationException):
- unroller.operr.normalize_exception(frame.space)
- return FinallyBlock.handle(self, frame, unroller)
-
-block_classes = {'EXCEPT_HANDLER_BLOCK': ExceptHandlerBlock,
+block_classes = {'SYS_EXC_INFO_RESTORER': SysExcInfoRestorer,
'SETUP_LOOP': LoopBlock,
'SETUP_EXCEPT': ExceptBlock,
'SETUP_FINALLY': FinallyBlock,
- 'SETUP_WITH': WithBlock,
+ 'SETUP_WITH': FinallyBlock,
}
-class W_OperationError(W_Root):
- """
- Tiny applevel wrapper around an OperationError.
- """
-
- def __init__(self, operr):
- self.operr = operr
-
- def descr_reduce(self, space):
- from pypy.interpreter.mixedmodule import MixedModule
- w_mod = space.getbuiltinmodule('_pickle_support')
- mod = space.interp_w(MixedModule, w_mod)
- w_new_inst = mod.get('operationerror_new')
- w_args = space.newtuple([])
- operr = self.operr
- if operr is None:
- return space.newtuple([w_new_inst, w_args])
- w_state = space.newtuple([operr.w_type, operr.get_w_value(space),
- operr.get_traceback()])
- return space.newtuple([w_new_inst, w_args, w_state])
-
- def descr_setstate(self, space, w_state):
- w_type, w_value, w_tb = space.fixedview(w_state, 3)
- self.operr = OperationError(w_type, w_value, w_tb)
+##class W_OperationError(W_Root):
+## """
+## Tiny applevel wrapper around an OperationError.
+## """
+##
+## def __init__(self, operr):
+## self.operr = operr
+##
+## def descr_reduce(self, space):
+## from pypy.interpreter.mixedmodule import MixedModule
+## w_mod = space.getbuiltinmodule('_pickle_support')
+## mod = space.interp_w(MixedModule, w_mod)
+## w_new_inst = mod.get('operationerror_new')
+## w_args = space.newtuple([])
+## operr = self.operr
+## if operr is None:
+## return space.newtuple([w_new_inst, w_args])
+## w_state = space.newtuple([operr.w_type, operr.get_w_value(space),
+## operr.get_traceback()])
+## return space.newtuple([w_new_inst, w_args, w_state])
+##
+## def descr_setstate(self, space, w_state):
+## w_type, w_value, w_tb = space.fixedview(w_state, 3)
+## self.operr = OperationError(w_type, w_value, w_tb)
def source_as_str(space, w_source, funcname, what, flags):
"""Return source code as str0 with adjusted compiler flags
diff --git a/pypy/interpreter/typedef.py b/pypy/interpreter/typedef.py
--- a/pypy/interpreter/typedef.py
+++ b/pypy/interpreter/typedef.py
@@ -464,7 +464,7 @@
from pypy.interpreter.eval import Code
from pypy.interpreter.pycode import PyCode, CO_VARARGS, CO_VARKEYWORDS
from pypy.interpreter.pyframe import PyFrame
-from pypy.interpreter.pyopcode import SuspendedUnroller, W_OperationError
+from pypy.interpreter.pyopcode import SuspendedUnroller
from pypy.interpreter.module import Module
from pypy.interpreter.function import (Function, Method, StaticMethod,
ClassMethod, BuiltinFunction, descr_function_get)
@@ -616,9 +616,6 @@
f_lasti = GetSetProperty(PyFrame.fget_f_lasti),
f_trace = GetSetProperty(PyFrame.fget_f_trace, PyFrame.fset_f_trace,
PyFrame.fdel_f_trace),
- f_exc_type = GetSetProperty(PyFrame.fget_f_exc_type),
- f_exc_value = GetSetProperty(PyFrame.fget_f_exc_value),
- f_exc_traceback = GetSetProperty(PyFrame.fget_f_exc_traceback),
f_restricted = GetSetProperty(PyFrame.fget_f_restricted),
f_code = GetSetProperty(PyFrame.fget_code),
f_locals = GetSetProperty(PyFrame.fget_getdictscope),
@@ -878,8 +875,8 @@
SuspendedUnroller.typedef = TypeDef("SuspendedUnroller")
SuspendedUnroller.typedef.acceptable_as_base_class = False
-W_OperationError.typedef = TypeDef("OperationError",
- __reduce__ = interp2app(W_OperationError.descr_reduce),
- __setstate__ = interp2app(W_OperationError.descr_setstate),
-)
-W_OperationError.typedef.acceptable_as_base_class = False
+## W_OperationError.typedef = TypeDef("OperationError",
+## __reduce__ = interp2app(W_OperationError.descr_reduce),
+## __setstate__ = interp2app(W_OperationError.descr_setstate),
+## )
+## W_OperationError.typedef.acceptable_as_base_class = False
More information about the pypy-commit
mailing list