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

Reply via email to