[pypy-commit] pypy default: merge translation-cleanup

rlamy noreply at buildbot.pypy.org
Sat Sep 29 18:34:56 CEST 2012


Author: Ronan Lamy <ronan.lamy at gmail.com>
Branch: 
Changeset: r57663:c80ffd88abd2
Date: 2012-09-29 17:34 +0100
http://bitbucket.org/pypy/pypy/changeset/c80ffd88abd2/

Log:	merge translation-cleanup

diff --git a/pypy/interpreter/baseobjspace.py b/pypy/interpreter/baseobjspace.py
--- a/pypy/interpreter/baseobjspace.py
+++ b/pypy/interpreter/baseobjspace.py
@@ -208,11 +208,11 @@
     def int_w(self, space):
         raise OperationError(space.w_TypeError,
                              typed_unwrap_error_msg(space, "integer", self))
-    
+
     def uint_w(self, space):
         raise OperationError(space.w_TypeError,
                              typed_unwrap_error_msg(space, "integer", self))
-    
+
     def bigint_w(self, space):
         raise OperationError(space.w_TypeError,
                              typed_unwrap_error_msg(space, "integer", self))
@@ -292,8 +292,6 @@
     """Base class for the interpreter-level implementations of object spaces.
     http://pypy.readthedocs.org/en/latest/objspace.html"""
 
-    full_exceptions = True  # full support for exceptions (normalization & more)
-
     def __init__(self, config=None):
         "NOT_RPYTHON: Basic initialization of objects."
         self.fromcache = InternalSpaceCache(self).getorbuild
@@ -1124,13 +1122,9 @@
     def exception_is_valid_obj_as_class_w(self, w_obj):
         if not self.isinstance_w(w_obj, self.w_type):
             return False
-        if not self.full_exceptions:
-            return True
         return self.is_true(self.issubtype(w_obj, self.w_BaseException))
 
     def exception_is_valid_class_w(self, w_cls):
-        if not self.full_exceptions:
-            return True
         return self.is_true(self.issubtype(w_cls, self.w_BaseException))
 
     def exception_getclass(self, w_obj):
@@ -1381,7 +1375,7 @@
         if not self.is_true(self.isinstance(w_obj, self.w_str)):
             raise OperationError(self.w_TypeError,
                                  self.wrap('argument must be a string'))
-        return self.str_w(w_obj)            
+        return self.str_w(w_obj)
 
     def unicode_w(self, w_obj):
         return w_obj.unicode_w(self)
@@ -1702,7 +1696,7 @@
     'ValueError',
     'ZeroDivisionError',
     ]
-    
+
 if sys.platform.startswith("win"):
     ObjSpace.ExceptionTable += ['WindowsError']
 
diff --git a/pypy/interpreter/error.py b/pypy/interpreter/error.py
--- a/pypy/interpreter/error.py
+++ b/pypy/interpreter/error.py
@@ -45,11 +45,6 @@
 
     def async(self, space):
         "Check if this is an exception that should better not be caught."
-        if not space.full_exceptions:
-            # flow objspace does not support such exceptions and more
-            # importantly, raises KeyboardInterrupt if you try to access
-            # space.w_KeyboardInterrupt
-            return False
         return (self.match(space, space.w_SystemExit) or
                 self.match(space, space.w_KeyboardInterrupt))
 
@@ -166,9 +161,7 @@
         # Or 'Class' can also be an old-style class and 'inst' an old-style
         # instance of it.
         #
-        # Note that 'space.full_exceptions' is set to False by the flow
-        # object space; in this case we must assume that we are in a
-        # non-advanced case, and ignore the advanced cases.  Old-style
+        # The flow object space only deals with non-advanced case. Old-style
         # classes and instances *are* advanced.
         #
         #  input (w_type, w_value)... becomes...                advanced case?
@@ -183,9 +176,8 @@
         #
         w_type  = self.w_type
         w_value = self.get_w_value(space)
-        if space.full_exceptions:
-            while space.is_true(space.isinstance(w_type, space.w_tuple)):
-                w_type = space.getitem(w_type, space.wrap(0))
+        while space.is_true(space.isinstance(w_type, space.w_tuple)):
+            w_type = space.getitem(w_type, space.wrap(0))
 
         if space.exception_is_valid_obj_as_class_w(w_type):
             # this is for all cases of the form (Class, something)
@@ -199,8 +191,7 @@
                     # raise Type, Instance: let etype be the exact type of value
                     w_type = w_valuetype
                 else:
-                    if space.full_exceptions and space.is_true(
-                        space.isinstance(w_value, space.w_tuple)):
+                    if space.is_true(space.isinstance(w_value, space.w_tuple)):
                         # raise Type, tuple: assume the tuple contains the
                         #                    constructor args
                         w_value = space.call(w_type, w_value)
diff --git a/pypy/interpreter/gateway.py b/pypy/interpreter/gateway.py
--- a/pypy/interpreter/gateway.py
+++ b/pypy/interpreter/gateway.py
@@ -944,14 +944,6 @@
         def appcaller(space, *args_w):
             if not isinstance(space, ObjSpace):
                 raise TypeError("first argument must be a space instance.")
-            # redirect if the space handles this specially
-            # XXX can this be factored a bit less flow space dependently?
-            if hasattr(space, 'specialcases'):
-                sc = space.specialcases
-                if ApplevelClass in sc:
-                    ret_w = sc[ApplevelClass](space, self, name, args_w)
-                    if ret_w is not None: # it was RPython
-                        return ret_w
             # the last argument can be an Arguments
             w_func = self.wget(space, name)
             if not args_w:
diff --git a/pypy/interpreter/pyopcode.py b/pypy/interpreter/pyopcode.py
--- a/pypy/interpreter/pyopcode.py
+++ b/pypy/interpreter/pyopcode.py
@@ -557,7 +557,7 @@
             w_type = self.popvalue()
         operror = OperationError(w_type, w_value)
         operror.normalize_exception(space)
-        if not space.full_exceptions or space.is_w(w_traceback, space.w_None):
+        if space.is_w(w_traceback, space.w_None):
             # common case
             raise operror
         else:
@@ -944,21 +944,9 @@
 
     def WITH_CLEANUP(self, oparg, next_instr):
         # see comment in END_FINALLY for stack state
-        # This opcode changed a lot between CPython versions
-        if (self.pycode.magic >= 0xa0df2ef
-            # Implementation since 2.7a0: 62191 (introduce SETUP_WITH)
-            or self.pycode.magic >= 0xa0df2d1):
-            # implementation since 2.6a1: 62161 (WITH_CLEANUP optimization)
-            w_unroller = self.popvalue()
-            w_exitfunc = self.popvalue()
-            self.pushvalue(w_unroller)
-        elif self.pycode.magic >= 0xa0df28c:
-            # Implementation since 2.5a0: 62092 (changed WITH_CLEANUP opcode)
-            w_exitfunc = self.popvalue()
-            w_unroller = self.peekvalue(0)
-        else:
-            raise NotImplementedError("WITH_CLEANUP for CPython <= 2.4")
-
+        w_unroller = self.popvalue()
+        w_exitfunc = self.popvalue()
+        self.pushvalue(w_unroller)
         unroller = self.space.interpclass_w(w_unroller)
         is_app_exc = (unroller is not None and
                       isinstance(unroller, SApplicationException))
@@ -1192,10 +1180,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."""
@@ -1206,12 +1190,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)."""
@@ -1226,13 +1204,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):
@@ -1243,12 +1214,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,
@@ -1323,8 +1288,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.
@@ -1356,8 +1320,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/bytecode.py b/pypy/objspace/flow/bytecode.py
--- a/pypy/objspace/flow/bytecode.py
+++ b/pypy/objspace/flow/bytecode.py
@@ -1,7 +1,8 @@
 """
 Bytecode handling classes and functions for use by the flow space.
 """
-from pypy.interpreter.pycode import PyCode, BytecodeCorruption
+from pypy.interpreter.pycode import (PyCode, BytecodeCorruption, cpython_magic,
+        cpython_code_signature)
 from pypy.tool.stdlib_opcode import (host_bytecode_spec, EXTENDED_ARG,
         HAVE_ARGUMENT)
 from pypy.interpreter.astcompiler.consts import CO_GENERATOR
@@ -12,6 +13,57 @@
     """
     opnames = host_bytecode_spec.method_names
 
+    def __init__(self, space,  argcount, nlocals, stacksize, flags,
+                     code, consts, names, varnames, filename,
+                     name, firstlineno, lnotab, freevars, cellvars,
+                     hidden_applevel=False, magic=cpython_magic):
+        """Initialize a new code object"""
+        self.space = space
+        self.co_name = name
+        assert nlocals >= 0
+        self.co_argcount = argcount
+        self.co_nlocals = nlocals
+        self.co_stacksize = stacksize
+        self.co_flags = flags
+        self.co_code = code
+        self.co_consts_w = consts
+        self.co_names_w = [space.wrap(aname) for aname in names]
+        self.co_varnames = varnames
+        self.co_freevars = freevars
+        self.co_cellvars = cellvars
+        self.co_filename = filename
+        self.co_name = name
+        self.co_firstlineno = firstlineno
+        self.co_lnotab = lnotab
+        self.hidden_applevel = hidden_applevel
+        self.magic = magic
+        self._signature = cpython_code_signature(self)
+        self._initialize()
+
+    def _initialize(self):
+        # Precompute what arguments need to be copied into cellvars
+        self._args_as_cellvars = []
+
+        if self.co_cellvars:
+            argcount = self.co_argcount
+            assert argcount >= 0     # annotator hint
+            if self.co_flags & CO_VARARGS:
+                argcount += 1
+            if self.co_flags & CO_VARKEYWORDS:
+                argcount += 1
+            # Cell vars could shadow already-set arguments.
+            # See comment in PyCode._initialize()
+            argvars  = self.co_varnames
+            cellvars = self.co_cellvars
+            for i in range(len(cellvars)):
+                cellname = cellvars[i]
+                for j in range(argcount):
+                    if cellname == argvars[j]:
+                        # argument j has the same name as the cell var i
+                        while len(self._args_as_cellvars) <= i:
+                            self._args_as_cellvars.append(-1)   # pad
+                        self._args_as_cellvars[i] = j
+
     def read(self, pos):
         """
         Decode the instruction starting at position ``next_instr``.
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
@@ -1,19 +1,17 @@
 import collections
-import sys
 from pypy.tool.error import source_lines
-from pypy.interpreter.error import OperationError
-from pypy.interpreter.pytraceback import PyTraceback
 from pypy.interpreter import pyframe
 from pypy.interpreter.nestedscope import Cell
-from pypy.interpreter.pycode import CO_OPTIMIZED, CO_NEWLOCALS
+from pypy.interpreter.pycode import CO_NEWLOCALS
 from pypy.interpreter.argument import ArgumentsForTranslation
-from pypy.interpreter.pyopcode import (Return, Yield, SuspendedUnroller,
-        SReturnValue, SApplicationException, BytecodeCorruption,
-        RaiseWithExplicitTraceback)
-from pypy.objspace.flow.model import *
+from pypy.interpreter.pyopcode import Return, BytecodeCorruption
+from pypy.objspace.flow.model import (Constant, Variable, Block, Link,
+    UnwrapException, SpaceOperation, FunctionGraph, c_last_exception)
 from pypy.objspace.flow.framestate import (FrameState, recursively_unflatten,
         recursively_flatten)
 from pypy.objspace.flow.bytecode import HostCode
+from pypy.objspace.flow.specialcase import (rpython_print_item,
+        rpython_print_newline)
 
 class FlowingError(Exception):
     """ Signals invalid RPython in the function being analysed"""
@@ -27,16 +25,14 @@
         msg += source_lines(self.frame.graph, None, offset=self.frame.last_instr)
         return "\n".join(msg)
 
-
 class StopFlowing(Exception):
     pass
 
-class FSException(OperationError):
-    def __init__(self, w_type, w_value, tb=None):
+class FSException(Exception):
+    def __init__(self, w_type, w_value):
         assert w_type is not None
         self.w_type = w_type
         self.w_value = w_value
-        self._application_traceback = tb
 
     def get_w_value(self, _):
         return self.w_value
@@ -44,45 +40,6 @@
     def __str__(self):
         return '[%s: %s]' % (self.w_type, self.w_value)
 
-    def normalize_exception(self, space):
-        """Normalize the OperationError.  In other words, fix w_type and/or
-        w_value to make sure that the __class__ of w_value is exactly w_type.
-        """
-        w_type  = self.w_type
-        w_value = self.w_value
-        if space.exception_is_valid_obj_as_class_w(w_type):
-            # this is for all cases of the form (Class, something)
-            if space.is_w(w_value, space.w_None):
-                # raise Type: we assume we have to instantiate Type
-                w_value = space.call_function(w_type)
-                w_type = self._exception_getclass(space, w_value)
-            else:
-                w_valuetype = space.exception_getclass(w_value)
-                if space.exception_issubclass_w(w_valuetype, w_type):
-                    # raise Type, Instance: let etype be the exact type of value
-                    w_type = w_valuetype
-                else:
-                    # raise Type, X: assume X is the constructor argument
-                    w_value = space.call_function(w_type, w_value)
-                    w_type = self._exception_getclass(space, w_value)
-
-        else:
-            # the only case left here is (inst, None), from a 'raise inst'.
-            w_inst = w_type
-            w_instclass = self._exception_getclass(space, w_inst)
-            if not space.is_w(w_value, space.w_None):
-                raise FSException(space.w_TypeError,
-                                     space.wrap("instance exception may not "
-                                                "have a separate value"))
-            w_value = w_inst
-            w_type = w_instclass
-
-        self.w_type = w_type
-        self.w_value = w_value
-
-class OperationThatShouldNotBePropagatedError(FSException):
-    pass
-
 class ImplicitOperationError(FSException):
     pass
 
@@ -262,6 +219,20 @@
 
 # ____________________________________________________________
 
+compare_method = [
+    "cmp_lt",   # "<"
+    "cmp_le",   # "<="
+    "cmp_eq",   # "=="
+    "cmp_ne",   # "!="
+    "cmp_gt",   # ">"
+    "cmp_ge",   # ">="
+    "cmp_in",
+    "cmp_not_in",
+    "cmp_is",
+    "cmp_is_not",
+    "cmp_exc_match",
+    ]
+
 class FlowSpaceFrame(pyframe.CPythonFrame):
 
     def __init__(self, space, func, constargs=None):
@@ -497,38 +468,68 @@
                 res = getattr(self, methodname)(oparg, next_instr)
                 if res is not None:
                     next_instr = res
-        except OperationThatShouldNotBePropagatedError, e:
-            raise Exception(
-                'found an operation that always raises %s: %s' % (
-                    self.space.unwrap(e.w_type).__name__,
-                    self.space.unwrap(e.w_value)))
         except FSException, operr:
-            self.attach_traceback(operr)
             next_instr = self.handle_operation_error(operr)
-        except RaiseWithExplicitTraceback, e:
-            next_instr = self.handle_operation_error(e.operr)
         return next_instr
 
-    def attach_traceback(self, operr):
-        if self.pycode.hidden_applevel:
-            return
-        tb = operr.get_traceback()
-        tb = PyTraceback(self.space, self, self.last_instr, tb)
-        operr.set_traceback(tb)
-
     def handle_operation_error(self, operr):
-        block = self.unrollstack(SFlowException.kind)
+        block = self.unrollstack(SApplicationException.kind)
         if block is None:
-            # no handler found for the exception
-            # try to preserve the CPython-level traceback
-            import sys
-            tb = sys.exc_info()[2]
-            raise operr, None, tb
+            raise operr
         else:
-            unroller = SFlowException(operr)
+            unroller = SApplicationException(operr)
             next_instr = block.handle(self, unroller)
             return next_instr
 
+    def BAD_OPCODE(self, _, next_instr):
+        raise FlowingError(self, "This operation is not RPython")
+
+    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 cmp_lt(self, w_1, w_2):
+        return self.space.lt(w_1, w_2)
+
+    def cmp_le(self, w_1, w_2):
+        return self.space.le(w_1, w_2)
+
+    def cmp_eq(self, w_1, w_2):
+        return self.space.eq(w_1, w_2)
+
+    def cmp_ne(self, w_1, w_2):
+        return self.space.ne(w_1, w_2)
+
+    def cmp_gt(self, w_1, w_2):
+        return self.space.gt(w_1, w_2)
+
+    def cmp_ge(self, w_1, w_2):
+        return self.space.ge(w_1, w_2)
+
+    def cmp_in(self, w_1, w_2):
+        return self.space.contains(w_2, w_1)
+
+    def cmp_not_in(self, w_1, w_2):
+        return self.space.not_(self.space.contains(w_2, w_1))
+
+    def cmp_is(self, w_1, w_2):
+        return self.space.is_(w_1, w_2)
+
+    def cmp_is_not(self, w_1, w_2):
+        return self.space.not_(self.space.is_(w_1, w_2))
+
+    def cmp_exc_match(self, w_1, w_2):
+        return self.space.newbool(self.space.exception_match(w_1, w_2))
+
+    def COMPARE_OP(self, testnum, next_instr):
+        w_2 = self.popvalue()
+        w_1 = self.popvalue()
+        w_result = getattr(self, compare_method[testnum])(w_1, w_2)
+        self.pushvalue(w_result)
+
     def RAISE_VARARGS(self, nbargs, next_instr):
         space = self.space
         if nbargs == 0:
@@ -538,7 +539,7 @@
                     # re-raising an implicit operation makes it an explicit one
                     operr = FSException(operr.w_type, operr.w_value)
                 self.last_exception = operr
-                raise RaiseWithExplicitTraceback(operr)
+                raise operr
             else:
                 raise FSException(space.w_TypeError,
                     space.wrap("raise: no active exception to re-raise"))
@@ -550,8 +551,7 @@
             w_value = self.popvalue()
         if 1:
             w_type = self.popvalue()
-        operror = FSException(w_type, w_value)
-        operror.normalize_exception(space)
+        operror = space.exc_from_raise(w_type, w_value)
         raise operror
 
     def IMPORT_NAME(self, nameindex, next_instr):
@@ -580,17 +580,45 @@
             return next_instr    # now inside a 'finally' block
 
     def END_FINALLY(self, oparg, next_instr):
-        unroller = self.end_finally()
-        if isinstance(unroller, SuspendedUnroller):
-            # go on unrolling the stack
-            block = self.unrollstack(unroller.kind)
-            if block is None:
-                w_result = unroller.nomoreblocks()
-                self.pushvalue(w_result)
-                raise Return
-            else:
-                next_instr = block.handle(self, unroller)
-        return next_instr
+        # 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()
+        if w_top == self.space.w_None:
+            # finally: block with no unroller active
+            return
+        try:
+            unroller = self.space.unwrap(w_top)
+        except UnwrapException:
+            pass
+        else:
+            if isinstance(unroller, SuspendedUnroller):
+                # case of a finally: block
+                return self.unroll_finally(unroller)
+        # case of an except: block.  We popped the exception type
+        self.popvalue()        #     Now we pop the exception value
+        unroller = self.space.unwrap(self.popvalue())
+        return self.unroll_finally(unroller)
+
+    def unroll_finally(self, unroller):
+        # go on unrolling the stack
+        block = self.unrollstack(unroller.kind)
+        if block is None:
+            w_result = unroller.nomoreblocks()
+            self.pushvalue(w_result)
+            raise Return
+        else:
+            return block.handle(self, unroller)
+
+    def POP_BLOCK(self, oparg, next_instr):
+        block = self.pop_block()
+        block.cleanupstack(self)  # the block knows how to clean up the value stack
 
     def JUMP_ABSOLUTE(self, jumpto, next_instr):
         return jumpto
@@ -603,11 +631,48 @@
         # isn't popped straightaway.
         self.pushvalue(None)
 
+    PRINT_EXPR = BAD_OPCODE
+    PRINT_ITEM_TO = BAD_OPCODE
+    PRINT_NEWLINE_TO = BAD_OPCODE
+
+    def PRINT_ITEM(self, oparg, next_instr):
+        w_item = self.popvalue()
+        w_s = self.space.do_operation('str', w_item)
+        self.space.appcall(rpython_print_item, w_s)
+
+    def PRINT_NEWLINE(self, oparg, next_instr):
+        self.space.appcall(rpython_print_newline)
+
+    def FOR_ITER(self, jumpby, next_instr):
+        w_iterator = self.peekvalue()
+        try:
+            w_nextitem = self.space.next(w_iterator)
+        except FSException, e:
+            if not self.space.exception_match(e.w_type, self.space.w_StopIteration):
+                raise
+            # iterator exhausted
+            self.popvalue()
+            next_instr += jumpby
+        else:
+            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)
@@ -616,10 +681,47 @@
         self.lastblock = block
         self.pushvalue(w_result)
 
+    def WITH_CLEANUP(self, oparg, next_instr):
+        # Note: RPython context managers receive None in lieu of tracebacks
+        # and cannot suppress the exception.
+        # This opcode changed a lot between CPython versions
+        if (self.pycode.magic >= 0xa0df2ef
+            # Implementation since 2.7a0: 62191 (introduce SETUP_WITH)
+            or self.pycode.magic >= 0xa0df2d1):
+            # implementation since 2.6a1: 62161 (WITH_CLEANUP optimization)
+            w_unroller = self.popvalue()
+            w_exitfunc = self.popvalue()
+            self.pushvalue(w_unroller)
+        elif self.pycode.magic >= 0xa0df28c:
+            # Implementation since 2.5a0: 62092 (changed WITH_CLEANUP opcode)
+            w_exitfunc = self.popvalue()
+            w_unroller = self.peekvalue(0)
+        else:
+            raise NotImplementedError("WITH_CLEANUP for CPython <= 2.4")
+
+        unroller = self.space.unwrap(w_unroller)
+        w_None = self.space.w_None
+        if isinstance(unroller, SApplicationException):
+            operr = unroller.operr
+            # The annotator won't allow to merge exception types with None.
+            # Replace it with the exception value...
+            self.space.call_function(w_exitfunc,
+                    operr.w_value, operr.w_value, w_None)
+        else:
+            self.space.call_function(w_exitfunc, w_None, w_None, w_None)
+
     def LOAD_GLOBAL(self, nameindex, next_instr):
         w_result = self.space.find_global(self.w_globals, self.getname_u(nameindex))
         self.pushvalue(w_result)
 
+    def LOAD_ATTR(self, nameindex, next_instr):
+        "obj.attributename"
+        w_obj = self.popvalue()
+        w_attributename = self.getname_w(nameindex)
+        w_value = self.space.getattr(w_obj, w_attributename)
+        self.pushvalue(w_value)
+    LOOKUP_METHOD = LOAD_ATTR
+
     def BUILD_LIST_FROM_ARG(self, _, next_instr):
         # This opcode was added with pypy-1.8.  Here is a simpler
         # version, enough for annotation.
@@ -647,23 +749,173 @@
     def argument_factory(self, *args):
         return ArgumentsForTranslation(self.space, *args)
 
-    def call_contextmanager_exit_function(self, w_func, w_typ, w_val, w_tb):
-        if w_typ is not self.space.w_None:
-            # The annotator won't allow to merge exception types with None.
-            # Replace it with the exception value...
-            w_typ = w_val
-        self.space.call_function(w_func, w_typ, w_val, w_tb)
-        # Return None so that the flow space statically knows that we didn't
-        # swallow the exception
-        return self.space.w_None
-
 ### 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
+
     def state_unpack_variables(self, space):
         return [self.operr.w_type, self.operr.w_value]
 
     @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 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 unroller.jump_to
+        else:
+            # jump to the end of the loop
+            self.cleanupstack(frame)
+            return 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
+        # 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 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.
+        self.cleanupstack(frame)
+        frame.pushvalue(frame.space.wrap(unroller))
+        return self.handlerposition   # jump to the handler
+
+
+class WithBlock(FinallyBlock):
+
+    def handle(self, frame, unroller):
+        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]
diff --git a/pypy/objspace/flow/objspace.py b/pypy/objspace/flow/objspace.py
--- a/pypy/objspace/flow/objspace.py
+++ b/pypy/objspace/flow/objspace.py
@@ -1,14 +1,14 @@
 # ______________________________________________________________________
 import __builtin__
 import sys
-import operator
 import types
-from pypy.interpreter.baseobjspace import ObjSpace, Wrappable
-from pypy.interpreter import pyframe, argument
-from pypy.objspace.flow.model import *
+from pypy.interpreter.baseobjspace import ObjSpace
+from pypy.interpreter.argument import ArgumentsForTranslation
+from pypy.objspace.flow.model import (Constant, Variable, WrapException,
+    UnwrapException, checkgraph, SpaceOperation)
 from pypy.objspace.flow import operation
 from pypy.objspace.flow.flowcontext import (FlowSpaceFrame, fixeggblocks,
-    OperationThatShouldNotBePropagatedError, FSException, FlowingError)
+    FSException, FlowingError)
 from pypy.objspace.flow.specialcase import SPECIAL_CASES
 from pypy.rlib.unroll import unrolling_iterable, _unroller
 from pypy.rlib import rstackovf, rarithmetic
@@ -38,47 +38,32 @@
     }
 
 # ______________________________________________________________________
-class FlowObjSpace(ObjSpace):
+class FlowObjSpace(object):
     """NOT_RPYTHON.
     The flow objspace space is used to produce a flow graph by recording
     the space operations that the interpreter generates when it interprets
     (the bytecode of) some function.
     """
+    w_None = Constant(None)
+    builtin = Constant(__builtin__)
+    sys = Constant(sys)
+    w_False = Constant(False)
+    w_True = Constant(True)
+    w_type = Constant(type)
+    w_tuple = Constant(tuple)
+    for exc in [KeyError, ValueError, IndexError, StopIteration,
+                AssertionError, TypeError, AttributeError, ImportError]:
+        clsname = exc.__name__
+        locals()['w_' + clsname] = Constant(exc)
 
-    full_exceptions = False
-    FrameClass = FlowSpaceFrame
+    # the following exceptions should not show up
+    # during flow graph construction
+    w_NameError = None
+    w_UnboundLocalError = None
 
-    def initialize(self):
-        self.w_None     = Constant(None)
-        self.builtin = Constant(__builtin__)
-        self.sys = Constant(sys)
-        self.w_False    = Constant(False)
-        self.w_True     = Constant(True)
-        self.w_type     = Constant(type)
-        self.w_tuple    = Constant(tuple)
-        for exc in [KeyError, ValueError, IndexError, StopIteration,
-                    AssertionError, TypeError, AttributeError, ImportError]:
-            clsname = exc.__name__
-            setattr(self, 'w_'+clsname, Constant(exc))
-        # the following exceptions are the ones that should not show up
-        # during flow graph construction; they are triggered by
-        # non-R-Pythonic constructs or real bugs like typos.
-        for exc in [NameError, UnboundLocalError]:
-            clsname = exc.__name__
-            setattr(self, 'w_'+clsname, None)
-        self.specialcases = SPECIAL_CASES.copy()
-        #self.make_builtins()
-        #self.make_sys()
-        # w_str is needed because cmp_exc_match of frames checks against it,
-        # as string exceptions are deprecated
-        self.w_str = Constant(str)
-        # objects which should keep their SomeObjectness
-        self.not_really_const = NOT_REALLY_CONST
-
-    # disable superclass methods
-    enter_cache_building_mode = None
-    leave_cache_building_mode = None
-    createcompiler = None
+    specialcases = SPECIAL_CASES
+    # objects which should keep their SomeObjectness
+    not_really_const = NOT_REALLY_CONST
 
     def is_w(self, w_one, w_two):
         return self.is_true(self.is_(w_one, w_two))
@@ -103,6 +88,12 @@
     def newslice(self, w_start, w_stop, w_step):
         return self.do_operation('newslice', w_start, w_stop, w_step)
 
+    def newbool(self, b):
+        if b:
+            return self.w_True
+        else:
+            return self.w_False
+
     def wrap(self, obj):
         if isinstance(obj, (Variable, Constant)):
             raise TypeError("already wrapped: " + repr(obj))
@@ -167,53 +158,77 @@
                 raise UnwrapException
         return obj
 
-    def interpclass_w(self, w_obj):
-        obj = self.unwrap(w_obj)
-        if isinstance(obj, Wrappable):
-            return obj
-        return None
+    def exception_issubclass_w(self, w_cls1, w_cls2):
+        return self.is_true(self.issubtype(w_cls1, w_cls2))
 
-    def _check_constant_interp_w_or_w_None(self, RequiredClass, w_obj):
+    def _exception_match(self, w_exc_type, w_check_class):
+        """Helper for exception_match
+
+        Handles the base case where w_check_class is a constant exception
+        type.
         """
-        WARNING: this implementation is not complete at all. It's just enough
-        to be used by end_finally() inside pyopcode.py.
-        """
-        return w_obj == self.w_None or (isinstance(w_obj, Constant) and
-                                        isinstance(w_obj.value, RequiredClass))
-
-    def getexecutioncontext(self):
-        return self.frame
+        if self.is_w(w_exc_type, w_check_class):
+            return True   # fast path (also here to handle string exceptions)
+        try:
+            return self.exception_issubclass_w(w_exc_type, w_check_class)
+        except FSException, e:
+            if e.match(self, self.w_TypeError):   # string exceptions maybe
+                return False
+            raise
 
     def exception_match(self, w_exc_type, w_check_class):
+        """Checks if the given exception type matches 'w_check_class'."""
         try:
             check_class = self.unwrap(w_check_class)
         except UnwrapException:
-            raise Exception, "non-constant except guard"
+            raise FlowingError(self.frame, "Non-constant except guard.")
         if check_class in (NotImplementedError, AssertionError):
             raise FlowingError(self.frame,
                 "Catching %s is not valid in RPython" % check_class.__name__)
         if not isinstance(check_class, tuple):
             # the simple case
-            return ObjSpace.exception_match(self, w_exc_type, w_check_class)
+            return self._exception_match(w_exc_type, w_check_class)
         # special case for StackOverflow (see rlib/rstackovf.py)
         if check_class == rstackovf.StackOverflow:
             w_real_class = self.wrap(rstackovf._StackOverflow)
-            return ObjSpace.exception_match(self, w_exc_type, w_real_class)
+            return self._exception_match(w_exc_type, w_real_class)
         # checking a tuple of classes
         for w_klass in self.fixedview(w_check_class):
             if self.exception_match(w_exc_type, w_klass):
                 return True
         return False
 
-    def getconstclass(space, w_cls):
-        try:
-            ecls = space.unwrap(w_cls)
-        except UnwrapException:
-            pass
+    def exc_from_raise(self, w_type, w_value):
+        """
+        Create a wrapped exception from the arguments of a raise statement.
+
+        Returns an FSException object whose w_value is an instance of w_type.
+        """
+        if self.isinstance_w(w_type, self.w_type):
+            # this is for all cases of the form (Class, something)
+            if self.is_w(w_value, self.w_None):
+                # raise Type: we assume we have to instantiate Type
+                w_value = self.call_function(w_type)
+                w_type = self.type(w_value)
+            else:
+                w_valuetype = self.type(w_value)
+                if self.exception_issubclass_w(w_valuetype, w_type):
+                    # raise Type, Instance: let etype be the exact type of value
+                    w_type = w_valuetype
+                else:
+                    # raise Type, X: assume X is the constructor argument
+                    w_value = self.call_function(w_type, w_value)
+                    w_type = self.type(w_value)
         else:
-            if isinstance(ecls, (type, types.ClassType)):
-                return ecls
-        return None
+            # the only case left here is (inst, None), from a 'raise inst'.
+            w_inst = w_type
+            w_instclass = self.type(w_inst)
+            if not self.is_w(w_value, self.w_None):
+                raise FSException(self.w_TypeError, self.wrap(
+                    "instance exception may not have a separate value"))
+            w_value = w_inst
+            w_type = w_instclass
+        return FSException(w_type, w_value)
 
     def build_flow(self, func, constargs={}, tweak_for_generator=True):
         """
@@ -232,7 +247,7 @@
 
     def fixedview(self, w_tuple, expected_length=None):
         return self.unpackiterable(w_tuple, expected_length)
-    listview = fixedview
+    listview = fixedview_unroll = fixedview
 
     def unpackiterable(self, w_iterable, expected_length=None):
         if not isinstance(w_iterable, Variable):
@@ -240,19 +255,17 @@
             if expected_length is not None and len(l) != expected_length:
                 raise ValueError
             return [self.wrap(x) for x in l]
-        if isinstance(w_iterable, Variable) and expected_length is None:
-            raise UnwrapException, ("cannot unpack a Variable iterable"
+        elif expected_length is None:
+            raise UnwrapException("cannot unpack a Variable iterable "
                                     "without knowing its length")
-        elif expected_length is not None:
+        else:
             w_len = self.len(w_iterable)
             w_correct = self.eq(w_len, self.wrap(expected_length))
             if not self.is_true(w_correct):
-                e = FSException(self.w_ValueError, self.w_None)
-                e.normalize_exception(self)
+                e = self.exc_from_raise(self.w_ValueError, self.w_None)
                 raise e
             return [self.do_operation('getitem', w_iterable, self.wrap(i))
                         for i in range(expected_length)]
-        return ObjSpace.unpackiterable(self, w_iterable, expected_length)
 
     # ____________________________________________________________
     def do_operation(self, name, *args_w):
@@ -267,6 +280,9 @@
                 operation.implicit_exceptions.get(name))
         return w_result
 
+    def not_(self, w_obj):
+        return self.wrap(not self.is_true(w_obj))
+
     def is_true(self, w_obj):
         try:
             obj = self.unwrap_for_computation(w_obj)
@@ -310,11 +326,14 @@
     def setitem(self, w_obj, w_key, w_val):
         # protect us from globals write access
         if w_obj is self.frame.w_globals:
-            raise SyntaxError("attempt to modify global attribute %r in %r"
-                            % (w_key, ec.graph.func))
+            raise FlowingError(self.frame,
+                    "Attempting to modify global variable  %r." % (w_key))
         return self.do_operation_with_implicit_exceptions('setitem', w_obj,
                                                           w_key, w_val)
 
+    def setitem_str(self, w_obj, key, w_value):
+        return self.setitem(w_obj, self.wrap(key), w_value)
+
     def getattr(self, w_obj, w_name):
         # handling special things like sys
         # unfortunately this will never vanish with a unique import logic :-(
@@ -333,10 +352,9 @@
                 result = getattr(obj, name)
             except Exception, e:
                 etype = e.__class__
-                msg = "generated by a constant operation:\n\t%s%r" % (
-                    'getattr', (obj, name))
-                raise OperationThatShouldNotBePropagatedError(
-                    self.wrap(etype), self.wrap(msg))
+                msg = "getattr(%s, %s) always raises %s: %s" % (
+                    obj, name, etype, e)
+                raise FlowingError(self.frame, msg)
             try:
                 return self.wrap(result)
             except WrapException:
@@ -344,6 +362,9 @@
         return self.do_operation_with_implicit_exceptions('getattr',
                 w_obj, w_name)
 
+    def isinstance_w(self, w_obj, w_type):
+        return self.is_true(self.isinstance(w_obj, w_type))
+
     def import_name(self, name, glob=None, loc=None, frm=None, level=-1):
         try:
             mod = __import__(name, glob, loc, frm, level)
@@ -352,20 +373,37 @@
         return self.wrap(mod)
 
     def import_from(self, w_module, w_name):
+        assert isinstance(w_module, Constant)
+        assert isinstance(w_name, Constant)
+        # handle sys
+        if w_module in self.not_really_const:
+            const_w = self.not_really_const[w_obj]
+            if w_name not in const_w:
+                return self.do_operation_with_implicit_exceptions('getattr',
+                                                                w_obj, w_name)
         try:
-            return self.getattr(w_module, w_name)
-        except FSException, e:
-            if e.match(self, self.w_AttributeError):
-                raise FSException(self.w_ImportError,
-                    self.wrap("cannot import name '%s'" % w_name.value))
-            else:
-                raise
+            return self.wrap(getattr(w_module.value, w_name.value))
+        except AttributeError:
+            raise FSException(self.w_ImportError,
+                self.wrap("cannot import name '%s'" % w_name.value))
+
+    def call_valuestack(self, w_func, nargs, frame):
+        args = frame.make_arguments(nargs)
+        return self.call_args(w_func, args)
+
+    def call_method(self, w_obj, methname, *arg_w):
+        w_meth = self.getattr(w_obj, self.wrap(methname))
+        return self.call_function(w_meth, *arg_w)
 
     def call_function(self, w_func, *args_w):
-        nargs = len(args_w)
-        args = argument.ArgumentsForTranslation(self, list(args_w))
+        args = ArgumentsForTranslation(self, list(args_w))
         return self.call_args(w_func, args)
 
+    def appcall(self, func, *args_w):
+        """Call an app-level RPython function directly"""
+        w_func = self.wrap(func)
+        return self.do_operation('simple_call', w_func, *args_w)
+
     def call_args(self, w_callable, args):
         try:
             fn = self.unwrap(w_callable)
@@ -424,20 +462,6 @@
                 raise FlowingError(self.frame, self.wrap(message))
         return self.wrap(value)
 
-    def w_KeyboardInterrupt(self):
-        # the reason to do this is: if you interrupt the flowing of a function
-        # with <Ctrl-C> the bytecode interpreter will raise an applevel
-        # KeyboardInterrupt and you will get an AttributeError: space does not
-        # have w_KeyboardInterrupt, which is not very helpful
-        raise KeyboardInterrupt
-    w_KeyboardInterrupt = property(w_KeyboardInterrupt)
-
-    def w_RuntimeError(self):
-        # XXX same as w_KeyboardInterrupt()
-        raise RuntimeError("the interpreter raises RuntimeError during "
-                           "flow graph construction")
-    w_RuntimeError = prebuilt_recursion_error = property(w_RuntimeError)
-
 def make_op(name, arity):
     """Add function operation to the flow space."""
     if getattr(FlowObjSpace, name, None) is not None:
@@ -486,10 +510,9 @@
                     result = op(*args)
                 except Exception, e:
                     etype = e.__class__
-                    msg = "generated by a constant operation:\n\t%s%r" % (
-                        name, tuple(args))
-                    raise OperationThatShouldNotBePropagatedError(
-                        self.wrap(etype), self.wrap(msg))
+                    msg = "%s%r always raises %s: %s" % (
+                        name, tuple(args), etype, e)
+                    raise FlowingError(self.frame, msg)
                 else:
                     # don't try to constant-fold operations giving a 'long'
                     # result.  The result is probably meant to be sent to
diff --git a/pypy/objspace/flow/operation.py b/pypy/objspace/flow/operation.py
--- a/pypy/objspace/flow/operation.py
+++ b/pypy/objspace/flow/operation.py
@@ -6,13 +6,9 @@
 import __builtin__
 import __future__
 import operator
-import types
-import sys
 from pypy.interpreter.baseobjspace import ObjSpace
-from pypy.interpreter.error import OperationError
 from pypy.tool.sourcetools import compile2
 from pypy.rlib.rarithmetic import ovfcheck
-from pypy.objspace.flow import model
 
 
 FunctionByName = {}   # dict {"operation_name": <built-in function>}
diff --git a/pypy/objspace/flow/specialcase.py b/pypy/objspace/flow/specialcase.py
--- a/pypy/objspace/flow/specialcase.py
+++ b/pypy/objspace/flow/specialcase.py
@@ -1,11 +1,7 @@
-from pypy.objspace.flow.model import Constant, UnwrapException
+from pypy.objspace.flow.model import Constant
 from pypy.objspace.flow.operation import OperationName, Arity
-from pypy.interpreter.gateway import ApplevelClass
-from pypy.interpreter.error import OperationError
-from pypy.tool.cache import Cache
 from pypy.rlib.rarithmetic import r_uint
 from pypy.rlib.objectmodel import we_are_translated
-import py
 
 def sc_import(space, fn, args):
     args_w, kwds_w = args.unpack()
@@ -35,11 +31,13 @@
 class StdOutBuffer:
     linebuf = []
 stdoutbuffer = StdOutBuffer()
+
 def rpython_print_item(s):
     buf = stdoutbuffer.linebuf
     for c in s:
         buf.append(c)
     buf.append(' ')
+
 def rpython_print_newline():
     buf = stdoutbuffer.linebuf
     if buf:
@@ -51,18 +49,6 @@
     import os
     os.write(1, s)
 
-def sc_applevel(space, app, name, args_w):
-    # special case only for print_item and print_newline
-    if 'pyopcode' in app.filename and name == 'print_item':
-        w_s = space.do_operation('str', *args_w)
-        args_w = (w_s,)
-    elif 'pyopcode' in app.filename and name == 'print_newline':
-        pass
-    else:
-        raise Exception("not RPython: calling %r from %r" % (name, app))
-    func = globals()['rpython_' + name]
-    return space.do_operation('simple_call', Constant(func), *args_w)
-
 # _________________________________________________________________________
 
 def sc_r_uint(space, r_uint, args):
@@ -79,8 +65,8 @@
 def sc_we_are_translated(space, we_are_translated, args):
     return Constant(True)
 
-SPECIAL_CASES = {__import__: sc_import, ApplevelClass: sc_applevel,
-        r_uint: sc_r_uint, we_are_translated: sc_we_are_translated}
+SPECIAL_CASES = {__import__: sc_import, r_uint: sc_r_uint,
+        we_are_translated: sc_we_are_translated}
 for fn in OperationName:
     SPECIAL_CASES[fn] = sc_operator
 
diff --git a/pypy/objspace/flow/test/test_framestate.py b/pypy/objspace/flow/test/test_framestate.py
--- a/pypy/objspace/flow/test/test_framestate.py
+++ b/pypy/objspace/flow/test/test_framestate.py
@@ -1,6 +1,4 @@
-from py.test import raises
 from pypy.objspace.flow.model import *
-from pypy.interpreter.pycode import PyCode
 from pypy.rlib.unroll import SpecTag
 from pypy.objspace.flow.objspace import FlowObjSpace
 from pypy.objspace.flow.flowcontext import FlowSpaceFrame
diff --git a/pypy/objspace/flow/test/test_objspace.py b/pypy/objspace/flow/test/test_objspace.py
--- a/pypy/objspace/flow/test/test_objspace.py
+++ b/pypy/objspace/flow/test/test_objspace.py
@@ -1,9 +1,8 @@
 from __future__ import with_statement
 import new
 import py, sys
-from pypy.objspace.flow.model import Constant, Block, Link, Variable
+from pypy.objspace.flow.model import Constant
 from pypy.objspace.flow.model import mkentrymap, c_last_exception
-from pypy.interpreter.argument import Arguments
 from pypy.translator.simplify import simplify_graph
 from pypy.objspace.flow.objspace import FlowObjSpace
 from pypy.objspace.flow.flowcontext import FlowingError, FlowSpaceFrame
@@ -100,6 +99,11 @@
     def test_print(self):
         x = self.codetest(self.print_)
 
+    def test_bad_print(self):
+        def f(x):
+            print >> x, "Hello"
+        with py.test.raises(FlowingError):
+            self.codetest(f)
     #__________________________________________________________
     def while_(i):
         while i > 0:
@@ -460,6 +464,15 @@
     def test_globalconstdict(self):
         x = self.codetest(self.globalconstdict)
 
+    def test_dont_write_globals(self):
+        def f():
+            global DATA
+            DATA = 5
+        with py.test.raises(FlowingError) as excinfo:
+            self.codetest(f)
+        assert "modify global" in str(excinfo.value)
+        assert DATA == {'x': 5, 'y': 6}
+
     #__________________________________________________________
     def dictliteral(name):
         x = {'x': 1}
@@ -500,6 +513,12 @@
             assert len(op.args) == 2
             assert op.args[1].value == 3
 
+    def test_unary_ops(self):
+        def f(x):
+            return not ~-x
+        graph = self.codetest(f)
+        assert self.all_operations(graph) == {'is_true': 1, 'invert': 1, 'neg': 1}
+
     #__________________________________________________________
 
     def wearetranslated(x):
@@ -953,14 +972,32 @@
             return s[-3:]
         check(f3, 'llo')
 
-    def test_propagate_attribute_error(self):
+    def test_constfold_attribute_error(self):
         def f(x):
             try:
                 "".invalid
             finally:
                 if x and 0:
                     raise TypeError()
-        py.test.raises(Exception, self.codetest, f)
+        with py.test.raises(FlowingError) as excinfo:
+            self.codetest(f)
+        assert 'getattr' in str(excinfo.value)
+
+    def test_constfold_exception(self):
+        def f():
+            return (3 + 2) / (4 - 2 * 2)
+        with py.test.raises(FlowingError) as excinfo:
+            self.codetest(f)
+        assert 'div(5, 0)' in str(excinfo.value)
+
+    def test_nonconstant_except(self):
+        def f(exc_cls):
+            try:
+                raise AttributeError
+            except exc_cls:
+                pass
+        with py.test.raises(FlowingError):
+            self.codetest(f)
 
     def test__flowspace_rewrite_directly_as_(self):
         def g(x):
diff --git a/pypy/translator/translator.py b/pypy/translator/translator.py
--- a/pypy/translator/translator.py
+++ b/pypy/translator/translator.py
@@ -8,6 +8,7 @@
 
 from pypy.translator import simplify
 from pypy.objspace.flow.model import FunctionGraph, checkgraph, Block
+from pypy.objspace.flow.objspace import FlowObjSpace
 from pypy.tool.ansi_print import ansi_log
 from pypy.tool.sourcetools import nice_repr_for_func
 from pypy.config.pypyoption import pypy_optiondescription
@@ -35,7 +36,6 @@
                 setattr(config.translation, attr, flowing_flags[attr])
         self.config = config
         self.platform = get_platform(config)
-        self.create_flowspace_config()
         self.annotator = None
         self.rtyper = None
         self.exceptiontransformer = None
@@ -43,17 +43,6 @@
         self.callgraph = {}   # {opaque_tag: (caller-graph, callee-graph)}
         self._prebuilt_graphs = {}   # only used by the pygame viewer
 
-    def create_flowspace_config(self):
-        # XXX this is a hack: we create a new config, which is only used
-        # for the flow object space. The problem is that the flow obj space
-        # needs an objspace config, but the thing we are translating might not
-        # have one (or worse we are translating pypy and the flow space picks
-        # up strange options of the pypy we are translating). Therefore we need
-        # to construct this new config
-        self.flowconfig = get_combined_translation_config(
-                pypy_optiondescription, self.config, translating=True)
-        self.flowconfig.objspace.name = "flow"
-
     def buildflowgraph(self, func, mute_dot=False):
         """Get the flow graph for a function."""
         if not isinstance(func, types.FunctionType):
@@ -64,8 +53,7 @@
         else:
             if self.config.translation.verbose:
                 log.start(nice_repr_for_func(func))
-            from pypy.objspace.flow.objspace import FlowObjSpace
-            space = FlowObjSpace(self.flowconfig)
+            space = FlowObjSpace()
             graph = space.build_flow(func)
             if self.config.translation.simplifying:
                 simplify.simplify_graph(graph)


More information about the pypy-commit mailing list