Author: Armin Rigo <[email protected]>
Branch: sanitize-finally-stack
Changeset: r55006:ca69981170e1
Date: 2012-05-10 16:42 +0200
http://bitbucket.org/pypy/pypy/changeset/ca69981170e1/
Log: (arigo, antocuni): a branch where to try to refactor how the
valuestack is handled inside finally: block. Right now two dummy
Nones values are always pushed to be popped() and ignored
immediately after. Also, it prevent to implement POP_EXCEPT sanely
on py3k
diff --git a/pypy/interpreter/astcompiler/assemble.py
b/pypy/interpreter/astcompiler/assemble.py
--- a/pypy/interpreter/astcompiler/assemble.py
+++ b/pypy/interpreter/astcompiler/assemble.py
@@ -562,7 +562,7 @@
ops.WITH_CLEANUP : -1,
ops.POP_BLOCK : 0,
- ops.END_FINALLY : -3,
+ ops.END_FINALLY : -1,
ops.SETUP_WITH : 1,
ops.SETUP_FINALLY : 0,
ops.SETUP_EXCEPT : 0,
diff --git a/pypy/interpreter/astcompiler/codegen.py
b/pypy/interpreter/astcompiler/codegen.py
--- a/pypy/interpreter/astcompiler/codegen.py
+++ b/pypy/interpreter/astcompiler/codegen.py
@@ -564,7 +564,8 @@
self.visit_sequence(handler.body)
self.emit_jump(ops.JUMP_FORWARD, end)
self.use_next_block(next_except)
- self.emit_op(ops.END_FINALLY)
+ self.emit_op(ops.END_FINALLY) # this END_FINALLY will always re-raise
+ self.is_dead_code()
self.use_next_block(otherwise)
self.visit_sequence(te.orelse)
self.use_next_block(end)
diff --git a/pypy/interpreter/baseobjspace.py b/pypy/interpreter/baseobjspace.py
--- a/pypy/interpreter/baseobjspace.py
+++ b/pypy/interpreter/baseobjspace.py
@@ -801,6 +801,12 @@
return obj
interp_w._annspecialcase_ = 'specialize:arg(1)'
+ def _check_interp_w_or_none(self, RequiredClass, w_obj):
+ if self.is_w(w_obj, self.w_None):
+ return True
+ obj = self.interpclass_w(w_obj)
+ return isinstance(obj, RequiredClass)
+
def unpackiterable(self, w_iterable, expected_length=-1):
"""Unpack an iterable object into a real (interpreter-level) list.
Raise an OperationError(w_ValueError) if the length is wrong."""
diff --git a/pypy/interpreter/pyopcode.py b/pypy/interpreter/pyopcode.py
--- a/pypy/interpreter/pyopcode.py
+++ b/pypy/interpreter/pyopcode.py
@@ -600,16 +600,28 @@
block.cleanup(self) # the block knows how to clean up the value stack
def end_finally(self):
- # unlike CPython, when we reach this opcode the value stack has
- # always been set up as follows (topmost first):
- # [exception type or None]
- # [exception value or None]
- # [wrapped stack unroller ]
- self.popvalue() # ignore the exception type
- self.popvalue() # ignore the exception value
- w_unroller = self.popvalue()
- unroller = self.space.interpclass_w(w_unroller)
- return unroller
+ # unlike CPython, there are two statically distinct cases: the
+ # END_FINALLY might be closing an 'except' block or a 'finally'
+ # block. In the first case, the stack contains three items:
+ # [exception type we are now handling]
+ # [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):
+ # [wrapped subclass of SuspendedUnroller]
+ w_top = self.popvalue()
+ # the following logic is a mess for the flow objspace,
+ # so we hide it specially in the space :-/
+ if self.space._check_interp_w_or_none(SuspendedUnroller, w_top):
+ # case of a finally: block
+ unroller = self.space.interpclass_w(w_top)
+ return unroller
+ else:
+ # case of an except: block. We popped the exception type
+ self.popvalue() # Now we pop the exception value
+ unroller = self.space.interpclass_w(self.popvalue())
+ assert unroller is not None
+ return unroller
def BUILD_CLASS(self, oparg, next_instr):
w_methodsdict = self.popvalue()
@@ -939,17 +951,17 @@
# Implementation since 2.7a0: 62191 (introduce SETUP_WITH)
or self.pycode.magic >= 0xa0df2d1):
# implementation since 2.6a1: 62161 (WITH_CLEANUP optimization)
- self.popvalue()
- self.popvalue()
+ #self.popvalue()
+ #self.popvalue()
w_unroller = self.popvalue()
w_exitfunc = self.popvalue()
self.pushvalue(w_unroller)
- self.pushvalue(self.space.w_None)
- self.pushvalue(self.space.w_None)
+ #self.pushvalue(self.space.w_None)
+ #self.pushvalue(self.space.w_None)
elif self.pycode.magic >= 0xa0df28c:
# Implementation since 2.5a0: 62092 (changed WITH_CLEANUP opcode)
w_exitfunc = self.popvalue()
- w_unroller = self.peekvalue(2)
+ w_unroller = self.peekvalue(0)
else:
raise NotImplementedError("WITH_CLEANUP for CPython <= 2.4")
@@ -966,7 +978,7 @@
w_traceback)
if self.space.is_true(w_suppress):
# __exit__() returned True -> Swallow the exception.
- self.settopvalue(self.space.w_None, 2)
+ self.settopvalue(self.space.w_None)
else:
self.call_contextmanager_exit_function(
w_exitfunc,
@@ -1354,8 +1366,8 @@
# here).
self.cleanupstack(frame)
# one None already pushed by the bytecode
- frame.pushvalue(frame.space.w_None)
- frame.pushvalue(frame.space.w_None)
+ #frame.pushvalue(frame.space.w_None)
+ #frame.pushvalue(frame.space.w_None)
def handle(self, frame, unroller):
# any abnormal reason for unrolling a finally: triggers the end of
@@ -1363,8 +1375,8 @@
# see comments in cleanup().
self.cleanupstack(frame)
frame.pushvalue(frame.space.wrap(unroller))
- frame.pushvalue(frame.space.w_None)
- frame.pushvalue(frame.space.w_None)
+ #frame.pushvalue(frame.space.w_None)
+ #frame.pushvalue(frame.space.w_None)
return r_uint(self.handlerposition) # jump to the handler
_______________________________________________
pypy-commit mailing list
[email protected]
http://mail.python.org/mailman/listinfo/pypy-commit