Commits

Antonio Cuni committed 4fcb841 Draft Merge

hg merge default

  • Participants
  • Parent commits f35922a, 7f6d5c8
  • Branches py3k

Comments (0)

Files changed (31)

File pypy/doc/arm.rst

 
 The tools required to cross translate from a Linux based host to an ARM based Linux target are:
 
-- A checkout of PyPy's arm-backend-2 branch.
+- A checkout of PyPy (default branch).
 - The GCC ARM cross compiler (on Ubuntu it is the ``gcc-arm-linux-gnueabi package``) but other toolchains should also work.
 - Scratchbox 2, a cross-compilation engine (``scratchbox2`` Ubuntu package).
 - A 32-bit PyPy or Python.
       return 0
 
   def target(*args):
-      return main, None
+      return main, None

File pypy/doc/project-ideas.rst

   which data structures would be more appropriate?  For example, a dict
   implemented as a hash table will suffer "stm collisions" in all threads
   whenever one thread writes anything to it; but there could be other
-  implementations.
+  implementations.  Maybe alternate strategies can be implemented at the
+  level of the Python interpreter (see list/dict strategies,
+  ``pypy/objspace/std/{list,dict}object.py``).
 
 * More generally, there is the idea that we would need some kind of
   "debugger"-like tool to "debug" things that are not bugs, but stm
   conflicts.  How would this tool look like to the end Python
   programmers?  Like a profiler?  Or like a debugger with breakpoints
-  on aborted transactions?
+  on aborted transactions?  It would probably be all app-level, with
+  a few hooks e.g. for transaction conflicts.
 
 * Find good ways to have libraries using internally threads and atomics,
   but not exposing threads to the user.  Right now there is a rough draft

File pypy/doc/whatsnew-head.rst

 .. branch: numpypy_count_nonzero
 .. branch: numpy-refactor
 Remove numpy lazy evaluation and simplify everything
+.. branch: numpy-reintroduce-jit-drivers
 .. branch: numpy-fancy-indexing
 Support for array[array-of-ints] in numpy
 .. branch: even-more-jit-hooks

File pypy/interpreter/astcompiler/codegen.py

                 if f_type == F_BLOCK_LOOP:
                     self.emit_jump(ops.CONTINUE_LOOP, block, True)
                     break
-                if self.frame_blocks[i][0] == F_BLOCK_FINALLY_END:
+                if f_type == F_BLOCK_FINALLY_END:
                     self.error("'continue' not supported inside 'finally' " \
                                    "clause",
                                cont)

File pypy/interpreter/baseobjspace.py

     """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)
     py3k = True             # are we interpreting py3k bytecode?
 
     def __init__(self, config=None):
     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):
         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)
     'ValueError',
     'ZeroDivisionError',
     ]
-    
+
 if sys.platform.startswith("win"):
     ObjSpace.ExceptionTable += ['WindowsError']
 

File pypy/interpreter/error.py

 
     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))
 
         # 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?
         #
         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)
                     # 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)

File pypy/interpreter/gateway.py

         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:

File pypy/interpreter/pyopcode.py

                 return next_instr
 
             if opcode == self.opcodedesc.JUMP_ABSOLUTE.index:
-                return self.jump_absolute(oparg, next_instr, ec)
+                return self.jump_absolute(oparg, ec)
 
             if we_are_translated():
                 for opdesc in unrolling_all_opcode_descs:
             operror.set_traceback(tb)
         raise operror
 
-
     def LOAD_LOCALS(self, oparg, next_instr):
         self.pushvalue(self.w_locals)
 
     def YIELD_VALUE(self, oparg, next_instr):
         raise Yield
 
-    def jump_absolute(self, jumpto, next_instr, ec):
+    def jump_absolute(self, jumpto, ec):
+        # this function is overridden by pypy.module.pypyjit.interp_jit
         check_nonneg(jumpto)
         return jumpto
 
 
     def WITH_CLEANUP(self, oparg, next_instr):
         # see comment in END_FINALLY for stack state
-        # This opcode changed a lot between CPython versions
         w_unroller = self.popvalue()
         w_exitfunc = self.popvalue()
         self.pushvalue(w_unroller)
     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."""
     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)."""
     """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):
     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,
             # and jump to the beginning of the loop, stored in the
             # exception's argument
             frame.append_block(self)
-            return r_uint(unroller.jump_to)
+            jumpto = unroller.jump_to
+            ec = frame.space.getexecutioncontext()
+            return r_uint(frame.jump_absolute(jumpto, ec))
         else:
             # jump to the end of the loop
             self.cleanupstack(frame)
         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.
         operationerr = None
         if isinstance(unroller, SApplicationException):
             operationerr = unroller.operr
-            if frame.space.full_exceptions:
-                operationerr.normalize_exception(frame.space)
+            operationerr.normalize_exception(frame.space)
         frame.pushvalue(frame.space.wrap(unroller))
         if operationerr and self.restore_last_exception:
             frame.last_exception = operationerr
     restore_last_exception = False
 
     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)
 

File pypy/jit/backend/model.py

     def get_latest_value_float(self, index):
         """Returns the value for the index'th argument to the
         last executed operation (from 'fail_args' if it was a guard,
-        or from 'args' if it was a FINISH).  Returns a float."""
+        or from 'args' if it was a FINISH).  Returns a FLOATSTORAGE."""
         raise NotImplementedError
 
     def get_latest_value_ref(self, index):
         """Returns the value for the index'th argument to the
         last executed operation (from 'fail_args' if it was a guard,
-        or from 'args' if it was a FINISH).  Returns a ptr or an obj."""
+        or from 'args' if it was a FINISH).  Returns a GCREF."""
         raise NotImplementedError
 
     def get_latest_value_count(self):

File pypy/module/_cffi_backend/test/_backend_test_c.py

     assert strlenaddr == cast(BVoidP, strlen)
 
 def test_read_variable():
-    if sys.platform == 'win32':
+    if sys.platform == 'win32' or sys.platform == 'darwin':
         py.test.skip("untested")
     BVoidP = new_pointer_type(new_void_type())
     ll = find_and_load_library('c')
     assert stderr == cast(BVoidP, _testfunc(8))
 
 def test_read_variable_as_unknown_length_array():
-    if sys.platform == 'win32':
+    if sys.platform == 'win32' or sys.platform == 'darwin':
         py.test.skip("untested")
     BCharP = new_pointer_type(new_primitive_type("char"))
     BArray = new_array_type(BCharP, None)
     # ^^ and not 'char[]', which is basically not allowed and would crash
 
 def test_write_variable():
-    if sys.platform == 'win32':
+    if sys.platform == 'win32' or sys.platform == 'darwin':
         py.test.skip("untested")
     BVoidP = new_pointer_type(new_void_type())
     ll = find_and_load_library('c')

File pypy/module/micronumpy/arrayimpl/concrete.py

     def setitem_index(self, space, index, value):
         self.setitem(self._lookup_by_unwrapped_index(space, index), value)
 
+    @jit.unroll_safe
     def _single_item_index(self, space, w_idx):
         """ Return an index of single item if possible, otherwise raises
         IndexError

File pypy/module/micronumpy/compile.py

 from pypy.interpreter.error import OperationError
 from pypy.module.micronumpy import interp_boxes
 from pypy.module.micronumpy.interp_dtype import get_dtype_cache
-from pypy.module.micronumpy.interp_numarray import (Scalar, BaseArray,
-     scalar_w, W_NDimArray, array)
+from pypy.module.micronumpy.base import W_NDimArray
+from pypy.module.micronumpy.interp_numarray import array
 from pypy.module.micronumpy.interp_arrayops import where
 from pypy.module.micronumpy import interp_ufuncs
 from pypy.rlib.objectmodel import specialize, instantiate
 
     def is_true(self, w_obj):
         assert isinstance(w_obj, BoolObject)
-        return w_obj.boolval
+        return False
+        #return w_obj.boolval
 
     def is_w(self, w_obj, w_what):
         return w_obj is w_what
         if isinstance(w_index, FloatObject):
             w_index = IntObject(int(w_index.floatval))
         w_val = self.expr.execute(interp)
-        assert isinstance(arr, BaseArray)
+        assert isinstance(arr, W_NDimArray)
         arr.descr_setitem(interp.space, w_index, w_val)
 
     def __repr__(self):
             w_rhs = self.rhs.wrap(interp.space)
         else:
             w_rhs = self.rhs.execute(interp)
-        if not isinstance(w_lhs, BaseArray):
+        if not isinstance(w_lhs, W_NDimArray):
             # scalar
             dtype = get_dtype_cache(interp.space).w_float64dtype
-            w_lhs = scalar_w(interp.space, dtype, w_lhs)
-        assert isinstance(w_lhs, BaseArray)
+            w_lhs = W_NDimArray.new_scalar(interp.space, dtype, w_lhs)
+        assert isinstance(w_lhs, W_NDimArray)
         if self.name == '+':
             w_res = w_lhs.descr_add(interp.space, w_rhs)
         elif self.name == '*':
         elif self.name == '-':
             w_res = w_lhs.descr_sub(interp.space, w_rhs)
         elif self.name == '->':
-            assert not isinstance(w_rhs, Scalar)
             if isinstance(w_rhs, FloatObject):
                 w_rhs = IntObject(int(w_rhs.floatval))
-            assert isinstance(w_lhs, BaseArray)
+            assert isinstance(w_lhs, W_NDimArray)
             w_res = w_lhs.descr_getitem(interp.space, w_rhs)
         else:
             raise NotImplementedError
-        if (not isinstance(w_res, BaseArray) and
+        if (not isinstance(w_res, W_NDimArray) and
             not isinstance(w_res, interp_boxes.W_GenericBox)):
             dtype = get_dtype_cache(interp.space).w_float64dtype
-            w_res = scalar_w(interp.space, dtype, w_res)
+            w_res = W_NDimArray.new_scalar(interp.space, dtype, w_res)
         return w_res
 
     def __repr__(self):
 
     def execute(self, interp):
         arr = self.args[0].execute(interp)
-        if not isinstance(arr, BaseArray):
+        if not isinstance(arr, W_NDimArray):
             raise ArgumentNotAnArray
         if self.name in SINGLE_ARG_FUNCTIONS:
             if len(self.args) != 1 and self.name != 'sum':
             elif self.name == "unegative":
                 neg = interp_ufuncs.get(interp.space).negative
                 w_res = neg.call(interp.space, [arr])
+            elif self.name == "cos":
+                cos = interp_ufuncs.get(interp.space).cos
+                w_res = cos.call(interp.space, [arr])                
             elif self.name == "flat":
                 w_res = arr.descr_get_flatiter(interp.space)
             elif self.name == "tostring":
                 arr.descr_tostring(interp.space)
                 w_res = None
-            elif self.name == "count_nonzero":
-                w_res = arr.descr_count_nonzero(interp.space)
             else:
                 assert False # unreachable code
         elif self.name in TWO_ARG_FUNCTIONS:
             if len(self.args) != 2:
                 raise ArgumentMismatch
             arg = self.args[1].execute(interp)
-            if not isinstance(arg, BaseArray):
+            if not isinstance(arg, W_NDimArray):
                 raise ArgumentNotAnArray
             if self.name == "dot":
                 w_res = arr.descr_dot(interp.space, arg)
                 raise ArgumentMismatch
             arg1 = self.args[1].execute(interp)
             arg2 = self.args[2].execute(interp)
-            if not isinstance(arg1, BaseArray):
+            if not isinstance(arg1, W_NDimArray):
                 raise ArgumentNotAnArray
-            if not isinstance(arg2, BaseArray):
+            if not isinstance(arg2, W_NDimArray):
                 raise ArgumentNotAnArray
             if self.name == "where":
                 w_res = where(interp.space, arr, arg1, arg2)
                 assert False
         else:
             raise WrongFunctionName
-        if isinstance(w_res, BaseArray):
+        if isinstance(w_res, W_NDimArray):
             return w_res
         if isinstance(w_res, FloatObject):
             dtype = get_dtype_cache(interp.space).w_float64dtype
             dtype = w_res.get_dtype(interp.space)
         else:
             dtype = None
-        return scalar_w(interp.space, dtype, w_res)
+        return W_NDimArray.new_scalar(interp.space, dtype, w_res)
 
 _REGEXES = [
     ('-?[\d\.]+', 'number'),

File pypy/module/micronumpy/interp_numarray.py

                 self._prepare_array_index(space, w_index)
         shape = res_shape + self.get_shape()[len(indexes):]
         res = W_NDimArray.from_shape(shape, self.get_dtype(), self.get_order())
+        if not res.get_size():
+            return res
         return loop.getitem_array_int(space, self, res, iter_shape, indexes,
                                       prefix)
 
             if self.get_size() == 0:
                 raise OperationError(space.w_ValueError,
                     space.wrap("Can't call %s on zero-size arrays" % op_name))
-            return space.wrap(loop.argmin_argmax(op_name, self))
+            return space.wrap(getattr(loop, 'arg' + op_name)(self))
         return func_with_new_name(impl, "reduce_arg%s_impl" % op_name)
 
     descr_argmax = _reduce_argmax_argmin_impl("max")

File pypy/module/micronumpy/interp_ufuncs.py

             return out
         shape = shape_agreement(space, w_obj.get_shape(), out,
                                 broadcast_down=False)
-        return loop.call1(shape, self.func, self.name, calc_dtype, res_dtype,
+        return loop.call1(shape, self.func, calc_dtype, res_dtype,
                           w_obj, out)
 
 
             return out
         new_shape = shape_agreement(space, w_lhs.get_shape(), w_rhs)
         new_shape = shape_agreement(space, new_shape, out, broadcast_down=False)
-        return loop.call2(new_shape, self.func, self.name, calc_dtype,
+        return loop.call2(new_shape, self.func, calc_dtype,
                           res_dtype, w_lhs, w_rhs, out)
 
 

File pypy/module/micronumpy/loop.py

 
 """ This file is the main run loop as well as evaluation loops for various
-signatures
+operations. This is the place to look for all the computations that iterate
+over all the array elements.
 """
 
-from pypy.rlib.objectmodel import specialize
 from pypy.rlib.rstring import StringBuilder
 from pypy.rlib import jit
 from pypy.rpython.lltypesystem import lltype, rffi
 from pypy.module.micronumpy.base import W_NDimArray
 
-def call2(shape, func, name, calc_dtype, res_dtype, w_lhs, w_rhs, out):
+call2_driver = jit.JitDriver(name='numpy_call2',
+                             greens = ['shapelen', 'func', 'calc_dtype',
+                                       'res_dtype'],
+                             reds = ['shape', 'w_lhs', 'w_rhs', 'out',
+                                     'left_iter', 'right_iter', 'out_iter'])
+
+def call2(shape, func, calc_dtype, res_dtype, w_lhs, w_rhs, out):
     if out is None:
         out = W_NDimArray.from_shape(shape, res_dtype)
     left_iter = w_lhs.create_iter(shape)
     right_iter = w_rhs.create_iter(shape)
     out_iter = out.create_iter(shape)
+    shapelen = len(shape)
     while not out_iter.done():
+        call2_driver.jit_merge_point(shapelen=shapelen, func=func,
+                                     calc_dtype=calc_dtype, res_dtype=res_dtype,
+                                     shape=shape, w_lhs=w_lhs, w_rhs=w_rhs,
+                                     out=out,
+                                     left_iter=left_iter, right_iter=right_iter,
+                                     out_iter=out_iter)
         w_left = left_iter.getitem().convert_to(calc_dtype)
         w_right = right_iter.getitem().convert_to(calc_dtype)
         out_iter.setitem(func(calc_dtype, w_left, w_right).convert_to(
         out_iter.next()
     return out
 
-def call1(shape, func, name, calc_dtype, res_dtype, w_obj, out):
+call1_driver = jit.JitDriver(name='numpy_call1',
+                             greens = ['shapelen', 'func', 'calc_dtype',
+                                       'res_dtype'],
+                             reds = ['shape', 'w_obj', 'out', 'obj_iter',
+                                     'out_iter'])
+
+def call1(shape, func, calc_dtype, res_dtype, w_obj, out):
     if out is None:
         out = W_NDimArray.from_shape(shape, res_dtype)
     obj_iter = w_obj.create_iter(shape)
     out_iter = out.create_iter(shape)
+    shapelen = len(shape)
     while not out_iter.done():
+        call1_driver.jit_merge_point(shapelen=shapelen, func=func,
+                                     calc_dtype=calc_dtype, res_dtype=res_dtype,
+                                     shape=shape, w_obj=w_obj, out=out,
+                                     obj_iter=obj_iter, out_iter=out_iter)
         elem = obj_iter.getitem().convert_to(calc_dtype)
         out_iter.setitem(func(calc_dtype, elem).convert_to(res_dtype))
         out_iter.next()
         obj_iter.next()
     return out
 
+setslice_driver = jit.JitDriver(name='numpy_setslice',
+                                greens = ['shapelen', 'dtype'],
+                                reds = ['target', 'source', 'target_iter',
+                                        'source_iter'])
+
 def setslice(shape, target, source):
     # note that unlike everything else, target and source here are
     # array implementations, not arrays
     target_iter = target.create_iter(shape)
     source_iter = source.create_iter(shape)
     dtype = target.dtype
+    shapelen = len(shape)
     while not target_iter.done():
+        setslice_driver.jit_merge_point(shapelen=shapelen, dtype=dtype,
+                                        target=target, source=source,
+                                        target_iter=target_iter,
+                                        source_iter=source_iter)
         target_iter.setitem(source_iter.getitem().convert_to(dtype))
         target_iter.next()
         source_iter.next()
     return target
 
+reduce_driver = jit.JitDriver(name='numpy_reduce',
+                              greens = ['shapelen', 'func', 'done_func',
+                                        'calc_dtype', 'identity'],
+                              reds = ['obj', 'obj_iter', 'cur_value'])
+
 def compute_reduce(obj, calc_dtype, func, done_func, identity):
     obj_iter = obj.create_iter(obj.get_shape())
     if identity is None:
         obj_iter.next()
     else:
         cur_value = identity.convert_to(calc_dtype)
+    shapelen = len(obj.get_shape())
     while not obj_iter.done():
+        reduce_driver.jit_merge_point(shapelen=shapelen, func=func,
+                                      calc_dtype=calc_dtype, identity=identity,
+                                      done_func=done_func, obj=obj,
+                                      obj_iter=obj_iter, cur_value=cur_value)
         rval = obj_iter.getitem().convert_to(calc_dtype)
         if done_func is not None and done_func(calc_dtype, rval):
             return rval
         arr_iter.setitem(box)
         arr_iter.next()
 
+where_driver = jit.JitDriver(name='numpy_where',
+                             greens = ['shapelen', 'dtype', 'arr_dtype'],
+                             reds = ['shape', 'arr', 'x', 'y','arr_iter', 'out',
+                                     'x_iter', 'y_iter', 'iter', 'out_iter'])
+
 def where(out, shape, arr, x, y, dtype):
     out_iter = out.create_iter(shape)
     arr_iter = arr.create_iter(shape)
             iter = y_iter
     else:
         iter = x_iter
+    shapelen = len(shape)
     while not iter.done():
+        where_driver.jit_merge_point(shapelen=shapelen, shape=shape,
+                                     dtype=dtype, iter=iter, x_iter=x_iter,
+                                     y_iter=y_iter, arr_iter=arr_iter,
+                                     arr=arr, x=x, y=y, arr_dtype=arr_dtype,
+                                     out_iter=out_iter, out=out)
         w_cond = arr_iter.getitem()
         if arr_dtype.itemtype.bool(w_cond):
             w_val = x_iter.getitem().convert_to(dtype)
         y_iter.next()
     return out
 
+axis_reduce__driver = jit.JitDriver(name='numpy_axis_reduce',
+                                    greens=['shapelen', 'func', 'dtype',
+                                            'identity'],
+                                    reds=['axis', 'arr', 'out', 'shape',
+                                          'out_iter', 'arr_iter'])
+
 def do_axis_reduce(shape, func, arr, dtype, axis, out, identity):
     out_iter = out.create_axis_iter(arr.get_shape(), axis)
     arr_iter = arr.create_iter(arr.get_shape())
     if identity is not None:
         identity = identity.convert_to(dtype)
+    shapelen = len(shape)
     while not out_iter.done():
+        axis_reduce__driver.jit_merge_point(shapelen=shapelen, func=func,
+                                            dtype=dtype, identity=identity,
+                                            axis=axis, arr=arr, out=out,
+                                            shape=shape, out_iter=out_iter,
+                                            arr_iter=arr_iter)
         w_val = arr_iter.getitem().convert_to(dtype)
         if out_iter.first_line:
             if identity is not None:
         out_iter.next()
     return out
 
-@specialize.arg(0)
-def argmin_argmax(op_name, arr):
-    result = 0
-    idx = 1
-    dtype = arr.get_dtype()
-    iter = arr.create_iter(arr.get_shape())
-    cur_best = iter.getitem()
-    iter.next()
-    while not iter.done():
-        w_val = iter.getitem()
-        new_best = getattr(dtype.itemtype, op_name)(cur_best, w_val)
-        if dtype.itemtype.ne(new_best, cur_best):
-            result = idx
-            cur_best = new_best
+
+def _new_argmin_argmax(op_name):
+    arg_driver = jit.JitDriver(name='numpy_' + op_name,
+                               greens = ['shapelen', 'dtype'],
+                               reds = ['result', 'idx', 'cur_best', 'arr',
+                                       'iter'])
+    
+    def argmin_argmax(arr):
+        result = 0
+        idx = 1
+        dtype = arr.get_dtype()
+        iter = arr.create_iter(arr.get_shape())
+        cur_best = iter.getitem()
         iter.next()
-        idx += 1
-    return result
+        shapelen = len(arr.get_shape())
+        while not iter.done():
+            arg_driver.jit_merge_point(shapelen=shapelen, dtype=dtype,
+                                       result=result, idx=idx,
+                                       cur_best=cur_best, arr=arr, iter=iter)
+            w_val = iter.getitem()
+            new_best = getattr(dtype.itemtype, op_name)(cur_best, w_val)
+            if dtype.itemtype.ne(new_best, cur_best):
+                result = idx
+                cur_best = new_best
+            iter.next()
+            idx += 1
+        return result
+    return argmin_argmax
+argmin = _new_argmin_argmax('min')
+argmax = _new_argmin_argmax('max')
+
+# note that shapelen == 2 always
+dot_driver = jit.JitDriver(name = 'numpy_dot',
+                           greens = ['dtype'],
+                           reds = ['outi', 'lefti', 'righti', 'result'])
 
 def multidim_dot(space, left, right, result, dtype, right_critical_dim):
     ''' assumes left, right are concrete arrays
     lefti = left.create_dot_iter(broadcast_shape, left_skip)
     righti = right.create_dot_iter(broadcast_shape, right_skip)
     while not outi.done():
+        dot_driver.jit_merge_point(dtype=dtype, outi=outi, lefti=lefti,
+                                   righti=righti, result=result)
         lval = lefti.getitem().convert_to(dtype) 
         rval = righti.getitem().convert_to(dtype) 
         outval = outi.getitem().convert_to(dtype) 
         lefti.next()
     return result
 
+count_all_true_driver = jit.JitDriver(name = 'numpy_count',
+                                      greens = ['shapelen', 'dtype'],
+                                      reds = ['s', 'iter'])
+
 def count_all_true(arr):
     s = 0
     if arr.is_scalar():
         return arr.get_dtype().itemtype.bool(arr.get_scalar_value())
     iter = arr.create_iter()
+    shapelen = len(arr.get_shape())
+    dtype = arr.get_dtype()
     while not iter.done():
+        count_all_true_driver.jit_merge_point(shapelen=shapelen, iter=iter,
+                                              s=s, dtype=dtype)
         s += iter.getitem_bool()
         iter.next()
     return s
 
+getitem_filter_driver = jit.JitDriver(name = 'numpy_getitem_bool',
+                                      greens = ['shapelen', 'arr_dtype',
+                                                'index_dtype'],
+                                      reds = ['res', 'index_iter', 'res_iter',
+                                              'arr_iter'])
+
 def getitem_filter(res, arr, index):
     res_iter = res.create_iter()
     index_iter = index.create_iter()
     arr_iter = arr.create_iter()
+    shapelen = len(arr.get_shape())
+    arr_dtype = arr.get_dtype()
+    index_dtype = index.get_dtype()
+    # XXX length of shape of index as well?
     while not index_iter.done():
+        getitem_filter_driver.jit_merge_point(shapelen=shapelen,
+                                              index_dtype=index_dtype,
+                                              arr_dtype=arr_dtype,
+                                              res=res, index_iter=index_iter,
+                                              res_iter=res_iter,
+                                              arr_iter=arr_iter)
         if index_iter.getitem_bool():
             res_iter.setitem(arr_iter.getitem())
             res_iter.next()
         arr_iter.next()
     return res
 
+setitem_filter_driver = jit.JitDriver(name = 'numpy_setitem_bool',
+                                      greens = ['shapelen', 'arr_dtype',
+                                                'index_dtype'],
+                                      reds = ['index_iter', 'value_iter',
+                                              'arr_iter'])
+
 def setitem_filter(arr, index, value):
     arr_iter = arr.create_iter()
     index_iter = index.create_iter()
     value_iter = value.create_iter()
+    shapelen = len(arr.get_shape())
+    index_dtype = index.get_dtype()
+    arr_dtype = arr.get_dtype()
     while not index_iter.done():
+        setitem_filter_driver.jit_merge_point(shapelen=shapelen,
+                                              index_dtype=index_dtype,
+                                              arr_dtype=arr_dtype,
+                                              index_iter=index_iter,
+                                              value_iter=value_iter,
+                                              arr_iter=arr_iter)
         if index_iter.getitem_bool():
             arr_iter.setitem(value_iter.getitem())
             value_iter.next()
         arr_iter.next()
         index_iter.next()
 
+flatiter_getitem_driver = jit.JitDriver(name = 'numpy_flatiter_getitem',
+                                        greens = ['dtype'],
+                                        reds = ['step', 'ri', 'res',
+                                                'base_iter'])
+
 def flatiter_getitem(res, base_iter, step):
     ri = res.create_iter()
+    dtype = res.get_dtype()
     while not ri.done():
+        flatiter_getitem_driver.jit_merge_point(dtype=dtype,
+                                                base_iter=base_iter,
+                                                ri=ri, res=res, step=step)
         ri.setitem(base_iter.getitem())
         base_iter.next_skip_x(step)
         ri.next()
     return res
 
+flatiter_setitem_driver = jit.JitDriver(name = 'numpy_flatiter_setitem',
+                                        greens = ['dtype'],
+                                        reds = ['length', 'step', 'arr_iter',
+                                                'val_iter'])
+
 def flatiter_setitem(arr, val, start, step, length):
     dtype = arr.get_dtype()
     arr_iter = arr.create_iter()
     val_iter = val.create_iter()
     arr_iter.next_skip_x(start)
     while length > 0:
+        flatiter_setitem_driver.jit_merge_point(dtype=dtype, length=length,
+                                                step=step, arr_iter=arr_iter,
+                                                val_iter=val_iter)
         arr_iter.setitem(val_iter.getitem().convert_to(dtype))
         # need to repeat i_nput values until all assignments are done
         arr_iter.next_skip_x(step)
         # WTF numpy?
         val_iter.reset()
 
+fromstring_driver = jit.JitDriver(name = 'numpy_fromstring',
+                                  greens = ['itemsize', 'dtype'],
+                                  reds = ['i', 's', 'ai'])
+
 def fromstring_loop(a, dtype, itemsize, s):
     i = 0
     ai = a.create_iter()
     while not ai.done():
+        fromstring_driver.jit_merge_point(dtype=dtype, s=s, ai=ai, i=i,
+                                          itemsize=itemsize)
         val = dtype.itemtype.runpack_str(s[i*itemsize:i*itemsize + itemsize])
         ai.setitem(val)
         ai.next()
         else:
             self._done = True
 
+    @jit.unroll_safe
     def get_index(self, space):
         return [space.wrap(i) for i in self.indexes]
 
+getitem_int_driver = jit.JitDriver(name = 'numpy_getitem_int',
+                                   greens = ['shapelen', 'indexlen', 'dtype'],
+                                   reds = ['arr', 'res', 'iter', 'indexes_w',
+                                           'prefix_w'])
+
 def getitem_array_int(space, arr, res, iter_shape, indexes_w, prefix_w):
+    shapelen = len(iter_shape)
+    indexlen = len(indexes_w)
+    dtype = arr.get_dtype()
     iter = PureShapeIterator(iter_shape, indexes_w)
     while not iter.done():
+        getitem_int_driver.jit_merge_point(shapelen=shapelen, indexlen=indexlen,
+                                           dtype=dtype, arr=arr, res=res,
+                                           iter=iter, indexes_w=indexes_w,
+                                           prefix_w=prefix_w)
         # prepare the index
         index_w = [None] * len(indexes_w)
         for i in range(len(indexes_w)):
         iter.next()
     return res
 
+setitem_int_driver = jit.JitDriver(name = 'numpy_setitem_int',
+                                   greens = ['shapelen', 'indexlen', 'dtype'],
+                                   reds = ['arr', 'iter', 'indexes_w',
+                                           'prefix_w', 'val_arr'])
+
 def setitem_array_int(space, arr, iter_shape, indexes_w, val_arr,
                       prefix_w):
+    shapelen = len(iter_shape)
+    indexlen = len(indexes_w)
+    dtype = arr.get_dtype()
     iter = PureShapeIterator(iter_shape, indexes_w)
     while not iter.done():
+        setitem_int_driver.jit_merge_point(shapelen=shapelen, indexlen=indexlen,
+                                           dtype=dtype, arr=arr,
+                                           iter=iter, indexes_w=indexes_w,
+                                           prefix_w=prefix_w, val_arr=val_arr)
         # prepare the index
         index_w = [None] * len(indexes_w)
         for i in range(len(indexes_w)):

File pypy/module/micronumpy/test/test_compile.py

+
 import py
-py.test.skip("this is going away")
-
 from pypy.module.micronumpy.compile import (numpy_compile, Assignment,
     ArrayConstant, FloatConstant, Operator, Variable, RangeConstant, Execute,
     FunctionCall, FakeSpace)
         r
         """
         interp = self.run(code)
-        assert interp.results[0].value.value == 15
+        assert interp.results[0].get_scalar_value().value == 15
 
     def test_sum2(self):
         code = """
         sum(b)
         """
         interp = self.run(code)
-        assert interp.results[0].value.value == 30 * (30 - 1)
+        assert interp.results[0].get_scalar_value().value == 30 * (30 - 1)
 
 
     def test_array_write(self):
         b = a + a
         min(b)
         """)
-        assert interp.results[0].value.value == -24
+        assert interp.results[0].get_scalar_value().value == -24
 
     def test_max(self):
         interp = self.run("""
         b = a + a
         max(b)
         """)
-        assert interp.results[0].value.value == 256
+        assert interp.results[0].get_scalar_value().value == 256
 
     def test_slice(self):
         interp = self.run("""
         assert interp.results[0].value == 3
 
     def test_take(self):
+        py.test.skip("unsupported")
         interp = self.run("""
         a = |10|
         b = take(a, [1, 1, 3, 2])

File pypy/module/micronumpy/test/test_numarray.py

         assert (a == [1, 1]).all()
 
     def test_int_array_index(self):
-        from numpypy import array, arange
+        from numpypy import array, arange, zeros
         b = arange(10)[array([3, 2, 1, 5])]
         assert (b == [3, 2, 1, 5]).all()
         raises(IndexError, "arange(10)[array([10])]")
         a = arange(1)
         a[[0, 0]] += 1
         assert a[0] == 1
+        assert (zeros(1)[[]] == []).all()
 
     def test_int_array_index_setitem(self):
         from numpypy import array, arange, zeros
 
     def test_int_array_index(self):
         from _numpypy import array
+        assert (array([])[[]] == []).all()
         a = array([[1, 2], [3, 4], [5, 6]])
         assert (a[slice(0, 3), [0, 0]] == [[1, 1], [3, 3], [5, 5]]).all()
         assert (a[array([0, 2]), slice(0, 2)] == [[1, 2], [5, 6]]).all()

File pypy/module/micronumpy/test/test_zjit.py

 """
 
 import py
-py.test.skip("this is going away")
-
 from pypy.jit.metainterp import pyjitpl
 from pypy.jit.metainterp.test.support import LLJitMixin
 from pypy.jit.metainterp.warmspot import reset_stats
 from pypy.module.micronumpy import interp_boxes
-from pypy.module.micronumpy.compile import (FakeSpace,
-    IntObject, Parser, InterpreterState)
-from pypy.module.micronumpy.interp_numarray import (W_NDimArray,
-     BaseArray, W_FlatIterator)
-from pypy.rlib.nonconst import NonConstant
-
+from pypy.module.micronumpy.compile import FakeSpace, Parser, InterpreterState
+from pypy.module.micronumpy.base import W_NDimArray
 
 class TestNumpyJIt(LLJitMixin):
     graph = None
             if not len(interp.results):
                 raise Exception("need results")
             w_res = interp.results[-1]
-            if isinstance(w_res, BaseArray):
-                concr = w_res.get_concrete_or_scalar()
-                sig = concr.find_sig()
-                frame = sig.create_frame(concr)
-                w_res = sig.eval(frame, concr)
+            if isinstance(w_res, W_NDimArray):
+                w_res = w_res.create_iter().getitem()
             if isinstance(w_res, interp_boxes.W_Float64Box):
                 return w_res.value
             if isinstance(w_res, interp_boxes.W_Int64Box):
             self.__class__.graph = graph
         reset_stats()
         pyjitpl._warmrunnerdesc.memory_manager.alive_loops.clear()
+        py.test.skip("don't run for now")
         return self.interp.eval_graph(self.graph, [i])
 
     def define_add():

File pypy/module/pypyjit/interp_jit.py

         except ExitFrame:
             return self.popvalue()
 
-    def jump_absolute(self, jumpto, _, ec=None):
+    def jump_absolute(self, jumpto, ec):
         if we_are_jitted():
             #
             # assume that only threads are using the bytecode counter

File pypy/module/pypyjit/test_pypy_c/test_exception.py

     def test_continue_in_finally(self):
         # check that 'continue' inside a try:finally: block is correctly
         # detected as closing a loop
-        py.test.skip("is this case important?")
         def f(n):
             i = 0
             while 1:
         assert log.result == 2001
         loop, = log.loops_by_filename(self.filepath)
         assert loop.match("""
-            i40 = int_add_ovf(i31, 1)
-            guard_no_overflow(descr=...)
-            i41 = int_lt(i40, i33)
-            guard_true(i41, descr=...)
+            i3 = int_lt(i1, i2)
+            guard_true(i3, descr=...)
+            i4 = int_add(i1, 1)
             --TICK--
             jump(..., descr=...)
         """)

File pypy/objspace/flow/bytecode.py

 """
 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
     """
     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``.

File pypy/objspace/flow/flowcontext.py

 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.rlib import jit
 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"""
         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
     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
 
 
 # ____________________________________________________________
 
+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):
                 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:
                     # 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"))
             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):
             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
         # 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)
         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.
     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)

File pypy/objspace/flow/framestate.py

-from pypy.interpreter.pyopcode import SuspendedUnroller
 from pypy.rlib.unroll import SpecTag
 from pypy.objspace.flow.model import *
 
 UNPICKLE_TAGS = {}
 
 def recursively_flatten(space, lst):
+    from pypy.objspace.flow.flowcontext import SuspendedUnroller
     i = 0
     while i < len(lst):
         item = lst[i]

File pypy/objspace/flow/objspace.py

 # ______________________________________________________________________
 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
     }
 
 # ______________________________________________________________________
-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
     py3k = False # the RPython bytecode is still python2
-    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))
     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))
                 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):
         """