[pypy-commit] pypy translation-cleanup: Copy frame block handling from pyopcode.py into flowcontext.py
rlamy
noreply at buildbot.pypy.org
Tue Sep 25 03:04:17 CEST 2012
Author: Ronan Lamy <ronan.lamy at gmail.com>
Branch: translation-cleanup
Changeset: r57542:1aa0d529d66a
Date: 2012-09-25 02:03 +0100
http://bitbucket.org/pypy/pypy/changeset/1aa0d529d66a/
Log: Copy frame block handling from pyopcode.py into flowcontext.py
Also:
* Copy CONTINUE_LOOP, BREAK_LOOP, SETUP_LOOP, SETUP_EXCEPT,
SETUP_FINALLY.
* Remove now-unnecessary support for flow space from the copied parts
of pyopcode.py.
diff --git a/pypy/interpreter/pyopcode.py b/pypy/interpreter/pyopcode.py
--- a/pypy/interpreter/pyopcode.py
+++ b/pypy/interpreter/pyopcode.py
@@ -1177,10 +1177,6 @@
def nomoreblocks(self):
raise BytecodeCorruption("misplaced bytecode - should not return")
- # NB. for the flow object space, the state_(un)pack_variables methods
- # give a way to "pickle" and "unpickle" the SuspendedUnroller by
- # enumerating the Variables it contains.
-
class SReturnValue(SuspendedUnroller):
"""Signals a 'return' statement.
Argument is the wrapped object to return."""
@@ -1191,12 +1187,6 @@
def nomoreblocks(self):
return self.w_returnvalue
- def state_unpack_variables(self, space):
- return [self.w_returnvalue]
- def state_pack_variables(space, w_returnvalue):
- return SReturnValue(w_returnvalue)
- state_pack_variables = staticmethod(state_pack_variables)
-
class SApplicationException(SuspendedUnroller):
"""Signals an application-level exception
(i.e. an OperationException)."""
@@ -1211,13 +1201,6 @@
"""Signals a 'break' statement."""
_immutable_ = True
kind = 0x04
-
- def state_unpack_variables(self, space):
- return []
- def state_pack_variables(space):
- return SBreakLoop.singleton
- state_pack_variables = staticmethod(state_pack_variables)
-
SBreakLoop.singleton = SBreakLoop()
class SContinueLoop(SuspendedUnroller):
@@ -1228,12 +1211,6 @@
def __init__(self, jump_to):
self.jump_to = jump_to
- def state_unpack_variables(self, space):
- return [space.wrap(self.jump_to)]
- def state_pack_variables(space, w_jump_to):
- return SContinueLoop(space.int_w(w_jump_to))
- state_pack_variables = staticmethod(state_pack_variables)
-
class FrameBlock(object):
"""Abstract base class for frame blocks from the blockstack,
@@ -1308,8 +1285,7 @@
self.cleanupstack(frame)
assert isinstance(unroller, SApplicationException)
operationerr = unroller.operr
- if frame.space.full_exceptions:
- operationerr.normalize_exception(frame.space)
+ operationerr.normalize_exception(frame.space)
# the stack setup is slightly different than in CPython:
# instead of the traceback, we store the unroller object,
# wrapped.
@@ -1341,8 +1317,7 @@
_immutable_ = True
def handle(self, frame, unroller):
- if (frame.space.full_exceptions and
- isinstance(unroller, SApplicationException)):
+ if isinstance(unroller, SApplicationException):
unroller.operr.normalize_exception(frame.space)
return FinallyBlock.handle(self, frame, unroller)
diff --git a/pypy/objspace/flow/flowcontext.py b/pypy/objspace/flow/flowcontext.py
--- a/pypy/objspace/flow/flowcontext.py
+++ b/pypy/objspace/flow/flowcontext.py
@@ -5,8 +5,7 @@
from pypy.interpreter.nestedscope import Cell
from pypy.interpreter.pycode import CO_OPTIMIZED, CO_NEWLOCALS
from pypy.interpreter.argument import ArgumentsForTranslation
-from pypy.interpreter.pyopcode import (Return, Yield, SuspendedUnroller,
- SReturnValue, SApplicationException, BytecodeCorruption)
+from pypy.interpreter.pyopcode import Return, Yield, BytecodeCorruption
from pypy.objspace.flow.model import *
from pypy.objspace.flow.framestate import (FrameState, recursively_unflatten,
recursively_flatten)
@@ -459,14 +458,21 @@
return next_instr
def handle_operation_error(self, operr):
- block = self.unrollstack(SFlowException.kind)
+ block = self.unrollstack(SApplicationException.kind)
if block is None:
raise operr
else:
- unroller = SFlowException(operr)
+ unroller = SApplicationException(operr)
next_instr = block.handle(self, unroller)
return next_instr
+ def BREAK_LOOP(self, oparg, next_instr):
+ return self.unrollstack_and_jump(SBreakLoop.singleton)
+
+ def CONTINUE_LOOP(self, startofloop, next_instr):
+ unroller = SContinueLoop(startofloop)
+ return self.unrollstack_and_jump(unroller)
+
def RAISE_VARARGS(self, nbargs, next_instr):
space = self.space
if nbargs == 0:
@@ -578,11 +584,22 @@
self.pushvalue(w_nextitem)
return next_instr
+ def SETUP_LOOP(self, offsettoend, next_instr):
+ block = LoopBlock(self, next_instr + offsettoend, self.lastblock)
+ self.lastblock = block
+
+ def SETUP_EXCEPT(self, offsettoend, next_instr):
+ block = ExceptBlock(self, next_instr + offsettoend, self.lastblock)
+ self.lastblock = block
+
+ def SETUP_FINALLY(self, offsettoend, next_instr):
+ block = FinallyBlock(self, next_instr + offsettoend, self.lastblock)
+ self.lastblock = block
+
def SETUP_WITH(self, offsettoend, next_instr):
# A simpler version than the 'real' 2.7 one:
# directly call manager.__enter__(), don't use special lookup functions
# which don't make sense on the RPython type system.
- from pypy.interpreter.pyopcode import WithBlock
w_manager = self.peekvalue()
w_exit = self.space.getattr(w_manager, self.space.wrap("__exit__"))
self.settopvalue(w_exit)
@@ -653,8 +670,53 @@
### Frame blocks ###
-class SFlowException(SApplicationException):
- """Flowspace override for SApplicationException"""
+class SuspendedUnroller(object):
+ """Abstract base class for interpreter-level objects that
+ instruct the interpreter to change the control flow and the
+ block stack.
+
+ The concrete subclasses correspond to the various values WHY_XXX
+ values of the why_code enumeration in ceval.c:
+
+ WHY_NOT, OK, not this one :-)
+ WHY_EXCEPTION, SApplicationException
+ WHY_RERAISE, implemented differently, see Reraise
+ WHY_RETURN, SReturnValue
+ WHY_BREAK, SBreakLoop
+ WHY_CONTINUE, SContinueLoop
+ WHY_YIELD not needed
+ """
+ def nomoreblocks(self):
+ raise BytecodeCorruption("misplaced bytecode - should not return")
+
+ # NB. for the flow object space, the state_(un)pack_variables methods
+ # give a way to "pickle" and "unpickle" the SuspendedUnroller by
+ # enumerating the Variables it contains.
+
+class SReturnValue(SuspendedUnroller):
+ """Signals a 'return' statement.
+ Argument is the wrapped object to return."""
+ kind = 0x01
+ def __init__(self, w_returnvalue):
+ self.w_returnvalue = w_returnvalue
+
+ def nomoreblocks(self):
+ return self.w_returnvalue
+
+ def state_unpack_variables(self, space):
+ return [self.w_returnvalue]
+
+ @staticmethod
+ def state_pack_variables(space, w_returnvalue):
+ return SReturnValue(w_returnvalue)
+
+class SApplicationException(SuspendedUnroller):
+ """Signals an application-level exception
+ (i.e. an OperationException)."""
+ kind = 0x02
+ def __init__(self, operr):
+ self.operr = operr
+
def nomoreblocks(self):
raise self.operr
@@ -663,4 +725,134 @@
@staticmethod
def state_pack_variables(space, w_type, w_value):
- return SFlowException(FSException(w_type, w_value))
+ return SApplicationException(FSException(w_type, w_value))
+
+class SBreakLoop(SuspendedUnroller):
+ """Signals a 'break' statement."""
+ kind = 0x04
+
+ def state_unpack_variables(self, space):
+ return []
+
+ @staticmethod
+ def state_pack_variables(space):
+ return SBreakLoop.singleton
+
+SBreakLoop.singleton = SBreakLoop()
+
+class SContinueLoop(SuspendedUnroller):
+ """Signals a 'continue' statement.
+ Argument is the bytecode position of the beginning of the loop."""
+ kind = 0x08
+ def __init__(self, jump_to):
+ self.jump_to = jump_to
+
+ def state_unpack_variables(self, space):
+ return [space.wrap(self.jump_to)]
+
+ @staticmethod
+ def state_pack_variables(space, w_jump_to):
+ return SContinueLoop(space.int_w(w_jump_to))
+
+
+class FrameBlock(object):
+ """Abstract base class for frame blocks from the blockstack,
+ used by the SETUP_XXX and POP_BLOCK opcodes."""
+
+ def __init__(self, frame, handlerposition, previous):
+ self.handlerposition = handlerposition
+ self.valuestackdepth = frame.valuestackdepth
+ self.previous = previous # this makes a linked list of blocks
+
+ def __eq__(self, other):
+ return (self.__class__ is other.__class__ and
+ self.handlerposition == other.handlerposition and
+ self.valuestackdepth == other.valuestackdepth)
+
+ def __ne__(self, other):
+ return not (self == other)
+
+ def __hash__(self):
+ return hash((self.handlerposition, self.valuestackdepth))
+
+ def cleanupstack(self, frame):
+ frame.dropvaluesuntil(self.valuestackdepth)
+
+ def cleanup(self, frame):
+ "Clean up a frame when we normally exit the block."
+ self.cleanupstack(frame)
+
+ # internal pickling interface, not using the standard protocol
+ def _get_state_(self, space):
+ w = space.wrap
+ return space.newtuple([w(self._opname), w(self.handlerposition),
+ w(self.valuestackdepth)])
+
+ def handle(self, frame, unroller):
+ raise NotImplementedError
+
+class LoopBlock(FrameBlock):
+ """A loop block. Stores the end-of-loop pointer in case of 'break'."""
+
+ _opname = 'SETUP_LOOP'
+ handling_mask = SBreakLoop.kind | SContinueLoop.kind
+
+ def handle(self, frame, unroller):
+ if isinstance(unroller, SContinueLoop):
+ # re-push the loop block without cleaning up the value stack,
+ # and jump to the beginning of the loop, stored in the
+ # exception's argument
+ frame.append_block(self)
+ return r_uint(unroller.jump_to)
+ else:
+ # jump to the end of the loop
+ self.cleanupstack(frame)
+ return r_uint(self.handlerposition)
+
+
+class ExceptBlock(FrameBlock):
+ """An try:except: block. Stores the position of the exception handler."""
+
+ _opname = 'SETUP_EXCEPT'
+ handling_mask = SApplicationException.kind
+
+ def handle(self, frame, unroller):
+ # push the exception to the value stack for inspection by the
+ # exception handler (the code after the except:)
+ self.cleanupstack(frame)
+ assert isinstance(unroller, SApplicationException)
+ operationerr = unroller.operr
+ if frame.space.full_exceptions:
+ operationerr.normalize_exception(frame.space)
+ # the stack setup is slightly different than in CPython:
+ # instead of the traceback, we store the unroller object,
+ # wrapped.
+ frame.pushvalue(frame.space.wrap(unroller))
+ frame.pushvalue(operationerr.get_w_value(frame.space))
+ frame.pushvalue(operationerr.w_type)
+ frame.last_exception = operationerr
+ return r_uint(self.handlerposition) # jump to the handler
+
+
+class FinallyBlock(FrameBlock):
+ """A try:finally: block. Stores the position of the exception handler."""
+
+ _opname = 'SETUP_FINALLY'
+ handling_mask = -1 # handles every kind of SuspendedUnroller
+
+ def handle(self, frame, unroller):
+ # any abnormal reason for unrolling a finally: triggers the end of
+ # the block unrolling and the entering the finally: handler.
+ # see comments in cleanup().
+ self.cleanupstack(frame)
+ frame.pushvalue(frame.space.wrap(unroller))
+ return r_uint(self.handlerposition) # jump to the handler
+
+
+class WithBlock(FinallyBlock):
+
+ def handle(self, frame, unroller):
+ if (frame.space.full_exceptions and
+ isinstance(unroller, SApplicationException)):
+ unroller.operr.normalize_exception(frame.space)
+ return FinallyBlock.handle(self, frame, unroller)
diff --git a/pypy/objspace/flow/framestate.py b/pypy/objspace/flow/framestate.py
--- a/pypy/objspace/flow/framestate.py
+++ b/pypy/objspace/flow/framestate.py
@@ -1,4 +1,3 @@
-from pypy.interpreter.pyopcode import SuspendedUnroller
from pypy.rlib.unroll import SpecTag
from pypy.objspace.flow.model import *
@@ -106,6 +105,7 @@
UNPICKLE_TAGS = {}
def recursively_flatten(space, lst):
+ from pypy.objspace.flow.flowcontext import SuspendedUnroller
i = 0
while i < len(lst):
item = lst[i]
More information about the pypy-commit
mailing list