[pypy-svn] r35184 - in pypy/branch/jit-real-world/pypy: annotation config interpreter interpreter/test module/_pickle_support objspace/flow tool

arigo at codespeak.net arigo at codespeak.net
Fri Dec 1 03:44:42 CET 2006


Author: arigo
Date: Fri Dec  1 03:43:34 2006
New Revision: 35184

Added:
   pypy/branch/jit-real-world/pypy/tool/pairtype.py
      - copied unchanged from r35175, pypy/branch/jit-real-world/pypy/annotation/pairtype.py
Removed:
   pypy/branch/jit-real-world/pypy/interpreter/opcodeorder.py
Modified:
   pypy/branch/jit-real-world/pypy/annotation/pairtype.py
   pypy/branch/jit-real-world/pypy/config/pypyoption.py
   pypy/branch/jit-real-world/pypy/interpreter/baseobjspace.py
   pypy/branch/jit-real-world/pypy/interpreter/eval.py
   pypy/branch/jit-real-world/pypy/interpreter/function.py
   pypy/branch/jit-real-world/pypy/interpreter/generator.py
   pypy/branch/jit-real-world/pypy/interpreter/nestedscope.py
   pypy/branch/jit-real-world/pypy/interpreter/pycode.py
   pypy/branch/jit-real-world/pypy/interpreter/pyframe.py
   pypy/branch/jit-real-world/pypy/interpreter/pyopcode.py
   pypy/branch/jit-real-world/pypy/interpreter/test/test_interpreter.py
   pypy/branch/jit-real-world/pypy/interpreter/test/test_pyframe.py
   pypy/branch/jit-real-world/pypy/interpreter/typedef.py
   pypy/branch/jit-real-world/pypy/module/_pickle_support/maker.py
   pypy/branch/jit-real-world/pypy/objspace/flow/flowcontext.py
   pypy/branch/jit-real-world/pypy/objspace/flow/framestate.py
   pypy/branch/jit-real-world/pypy/tool/stdlib_opcode.py
Log:
(pedronis, arigo)

Intermediate check-in #2.

More seriously, we rewrote the interpreter main loop in a style that
should be easier for the JIT to grasp, but also -- possibly -- easier
for human beings to grasp.  A bit.  Many levels of wrapping of stuff
into other stuff are avoided now, and the PyFrame class hierarchy was
completely removed.  There is a possibly nice way to add opcodes from
outside, with config options to enable them.  The drawback is that the
core main loop uses modern RPython magic.

Translation not tested.  It makes py.py slower by 30% but we hope that
pypy-c will be faster.



Modified: pypy/branch/jit-real-world/pypy/annotation/pairtype.py
==============================================================================
--- pypy/branch/jit-real-world/pypy/annotation/pairtype.py	(original)
+++ pypy/branch/jit-real-world/pypy/annotation/pairtype.py	Fri Dec  1 03:43:34 2006
@@ -1,63 +1,4 @@
-"""
-Two magic tricks for classes:
+# no longer there, sorry
+# XXX fix all these imports
 
-    class X:
-        __metaclass__ = extendabletype
-        ...
-
-    # in some other file...
-    class __extend__(X):
-        ...      # and here you can add new methods and class attributes to X
-
-Mostly useful together with the second trick, which lets you build
-methods whose 'self' is a pair of objects instead of just one:
-
-    class __extend__(pairtype(X, Y)):
-        attribute = 42
-        def method((x, y), other, arguments):
-            ...
-
-    pair(x, y).attribute
-    pair(x, y).method(other, arguments)
-
-This finds methods and class attributes based on the actual
-class of both objects that go into the pair(), with the usual
-rules of method/attribute overriding in (pairs of) subclasses.
-
-For more information, see test_pairtype.
-"""
-
-class extendabletype(type):
-    """A type with a syntax trick: 'class __extend__(t)' actually extends
-    the definition of 't' instead of creating a new subclass."""
-    def __new__(cls, name, bases, dict):
-        if name == '__extend__':
-            for cls in bases:
-                for key, value in dict.items():
-                    if key == '__module__':
-                        continue
-                    # XXX do we need to provide something more for pickling?
-                    setattr(cls, key, value)
-            return None
-        else:
-            return super(extendabletype, cls).__new__(cls, name, bases, dict)
-
-
-def pair(a, b):
-    """Return a pair object."""
-    tp = pairtype(a.__class__, b.__class__)
-    return tp((a, b))   # tp is a subclass of tuple
-
-pairtypecache = {}
-
-def pairtype(cls1, cls2):
-    """type(pair(a,b)) is pairtype(a.__class__, b.__class__)."""
-    try:
-        pair = pairtypecache[cls1, cls2]
-    except KeyError:
-        name = 'pairtype(%s, %s)' % (cls1.__name__, cls2.__name__)
-        bases1 = [pairtype(base1, cls2) for base1 in cls1.__bases__]
-        bases2 = [pairtype(cls1, base2) for base2 in cls2.__bases__]
-        bases = tuple(bases1 + bases2) or (tuple,)  # 'tuple': ultimate base
-        pair = pairtypecache[cls1, cls2] = extendabletype(name, bases, {})
-    return pair
+from pypy.tool.pairtype import *

Modified: pypy/branch/jit-real-world/pypy/config/pypyoption.py
==============================================================================
--- pypy/branch/jit-real-world/pypy/config/pypyoption.py	(original)
+++ pypy/branch/jit-real-world/pypy/config/pypyoption.py	Fri Dec  1 03:43:34 2006
@@ -37,6 +37,9 @@
                      ["cpython", "ast"], "ast",
                      cmdline='--compiler'),
 
+        OptionDescription("opcodes", "opcodes to enable in the interpreter", [
+            ]),
+
         BoolOption("nofaking", "disallow faking in the object space",
                    default=False,
                    requires=[

Modified: pypy/branch/jit-real-world/pypy/interpreter/baseobjspace.py
==============================================================================
--- pypy/branch/jit-real-world/pypy/interpreter/baseobjspace.py	(original)
+++ pypy/branch/jit-real-world/pypy/interpreter/baseobjspace.py	Fri Dec  1 03:43:34 2006
@@ -174,6 +174,10 @@
             from pypy.config.pypyoption import pypy_optiondescription
             config = Config(pypy_optiondescription)
         self.config = config
+
+        # import extra modules for side-effects, possibly based on config
+        import pypy.interpreter.nestedscope     # register *_DEREF bytecodes
+
         self.interned_strings = {}
         self.pending_actions = []
         self.setoptions(**kw)

Modified: pypy/branch/jit-real-world/pypy/interpreter/eval.py
==============================================================================
--- pypy/branch/jit-real-world/pypy/interpreter/eval.py	(original)
+++ pypy/branch/jit-real-world/pypy/interpreter/eval.py	Fri Dec  1 03:43:34 2006
@@ -147,28 +147,3 @@
                 new_fastlocals_w[i] = w_value
 
         self.setfastscope(new_fastlocals_w)
-
-
-class EvalFrame(Frame):
-
-    def resume(self):
-        "Resume the execution of the frame from its current state."
-        executioncontext = self.space.getexecutioncontext()
-        executioncontext.enter(self)
-        try:
-            result = self.eval(executioncontext)
-            rstack.resume_point("evalframe", self, executioncontext, returns=result)
-        finally:
-            executioncontext.leave(self)
-        return result
-
-    # running a frame is usually the same as resuming it from its
-    # initial state, but not for generator frames
-    run = resume
-
-    def eval(self, executioncontext):
-        "Abstract method to override."
-        raise TypeError, "abstract"
-
-    def hide(self):
-        return False

Modified: pypy/branch/jit-real-world/pypy/interpreter/function.py
==============================================================================
--- pypy/branch/jit-real-world/pypy/interpreter/function.py	(original)
+++ pypy/branch/jit-real-world/pypy/interpreter/function.py	Fri Dec  1 03:43:34 2006
@@ -9,7 +9,6 @@
 from pypy.interpreter.error import OperationError
 from pypy.interpreter.baseobjspace import Wrappable
 from pypy.interpreter.eval import Code
-from pypy.interpreter.pyframe import PyFrame
 from pypy.interpreter.argument import Arguments, ArgumentsFromValuestack
 
 class Function(Wrappable):

Modified: pypy/branch/jit-real-world/pypy/interpreter/generator.py
==============================================================================
--- pypy/branch/jit-real-world/pypy/interpreter/generator.py	(original)
+++ pypy/branch/jit-real-world/pypy/interpreter/generator.py	Fri Dec  1 03:43:34 2006
@@ -1,38 +1,5 @@
 from pypy.interpreter.error import OperationError
 from pypy.interpreter.baseobjspace import Wrappable
-from pypy.interpreter.eval import EvalFrame
-from pypy.interpreter.pyframe import ControlFlowException, ExitFrame
-
-#
-# Generator support. Note that GeneratorFrame is not a subclass of PyFrame.
-# PyCode objects use a custom subclass of both PyFrame and GeneratorFrame
-# when they need to interpret Python bytecode that is a generator.
-# Otherwise, GeneratorFrame could also be used to define, say,
-# built-in generators (which are usually done in CPython as functions
-# that return iterators).
-#
-
-class GeneratorFrameMixin(object):
-    "A frame attached to a generator."
-    _mixin_ = True
-
-    def run(self):
-        "Build a generator-iterator."
-        return self.space.wrap(GeneratorIterator(self))
-
-    ### extra opcodes ###
-
-    # XXX mmmh, GeneratorFrame is supposed to be independent from
-    # Python bytecode... Well, it is. These are not used when
-    # GeneratorFrame is used with other kinds of Code subclasses.
-
-    def RETURN_VALUE(f):  # overridden
-        raise SGeneratorReturn()
-
-    def YIELD_VALUE(f):
-        w_yieldedvalue = f.valuestack.pop()
-        raise SYieldValue(w_yieldedvalue)
-    YIELD_STMT = YIELD_VALUE  # misnamed in old versions of dis.opname
 
 
 class GeneratorIterator(Wrappable):
@@ -42,7 +9,6 @@
         self.space = frame.space
         self.frame = frame
         self.running = False
-        self.exhausted = False
 
     def descr__reduce__(self, space):
         from pypy.interpreter.mixedmodule import MixedModule
@@ -54,7 +20,6 @@
         tup = [
             w(self.frame),
             w(self.running),
-            w(self.exhausted),
             ]
 
         return space.newtuple([new_inst, space.newtuple(tup)])
@@ -69,34 +34,21 @@
         if self.running:
             raise OperationError(space.w_ValueError,
                                  space.wrap('generator already executing'))
-        if self.exhausted:
+        if self.frame.frame_finished_execution:
             raise OperationError(space.w_StopIteration, space.w_None) 
         self.running = True
         try:
             try:
-                return self.frame.resume()
+                w_result = self.frame.execute_frame()
             except OperationError:
-                self.exhausted = True
+                # errors finish a frame
+                self.frame.frame_finished_execution = True
                 raise
+            # if the frame is now marked as finished, it was RETURNed from
+            if self.frame.frame_finished_execution:
+                raise OperationError(space.w_StopIteration, space.w_None) 
+            else:
+                return w_result     # YIELDed
         finally:
             self.frame.f_back = None
             self.running = False
-
-#
-# the specific ControlFlowExceptions used by generators
-#
-
-class SYieldValue(ControlFlowException):
-    """Signals a 'yield' statement.
-    Argument is the wrapped object to return."""
-
-    def __init__(self, w_yieldvalue):
-        self.w_yieldvalue = w_yieldvalue
-
-    def action(self, frame):
-        raise ExitFrame(self.w_yieldvalue)
-
-class SGeneratorReturn(ControlFlowException):
-    """Signals a 'return' statement inside a generator."""
-    def emptystack(self, frame):
-        raise OperationError(frame.space.w_StopIteration, frame.space.w_None) 

Modified: pypy/branch/jit-real-world/pypy/interpreter/nestedscope.py
==============================================================================
--- pypy/branch/jit-real-world/pypy/interpreter/nestedscope.py	(original)
+++ pypy/branch/jit-real-world/pypy/interpreter/nestedscope.py	Fri Dec  1 03:43:34 2006
@@ -1,5 +1,4 @@
 from pypy.interpreter.error import OperationError
-from pypy.interpreter.pyopcode import PyInterpFrame
 from pypy.interpreter import function, pycode, pyframe
 from pypy.interpreter.baseobjspace import Wrappable
 from pypy.interpreter.mixedmodule import MixedModule
@@ -59,7 +58,12 @@
                                      content, uid(self))
 
 
-class PyNestedScopeFrame(PyInterpFrame):
+super_initialize_frame_scopes = pyframe.PyFrame.initialize_frame_scopes
+super_fast2locals             = pyframe.PyFrame.fast2locals
+super_locals2fast             = pyframe.PyFrame.locals2fast
+
+
+class __extend__(pyframe.PyFrame):
     """This class enhances a standard frame with nested scope abilities,
     i.e. handling of cell/free variables."""
 
@@ -69,28 +73,47 @@
     #     variables coming from a parent function in which i'm nested
     # 'closure' is a list of Cell instances: the received free vars.
 
-    def __init__(self, space, code, w_globals, closure):
-        PyInterpFrame.__init__(self, space, code, w_globals, closure)
+    cells = None
+
+    def initialize_frame_scopes(self, closure):
+        super_initialize_frame_scopes(self, closure)
+        code = self.pycode
         ncellvars = len(code.co_cellvars)
         nfreevars = len(code.co_freevars)
-        if closure is None:
-            if nfreevars:
-                raise OperationError(space.w_TypeError,
-                                     space.wrap("directly executed code object "
-                                                "may not contain free variables"))
-            closure = []
-        else:
-            if len(closure) != nfreevars:
-                raise ValueError("code object received a closure with "
+        if not nfreevars:
+            if not ncellvars:
+                return            # no self.cells needed - fast path
+            if closure is None:
+                closure = []
+        elif closure is None:
+            space = self.space
+            raise OperationError(space.w_TypeError,
+                                 space.wrap("directly executed code object "
+                                            "may not contain free variables"))
+        if len(closure) != nfreevars:
+            raise ValueError("code object received a closure with "
                                  "an unexpected number of free variables")
         self.cells = [Cell() for i in range(ncellvars)] + closure
 
     def getclosure(self):
+        if self.cells is None:
+            return None
         ncellvars = len(self.pycode.co_cellvars)  # not part of the closure
         return self.cells[ncellvars:]
 
+    def _getcells(self):
+        return self.cells
+
+    def _setcellvars(self, cellvars):
+        ncellvars = len(self.pycode.co_cellvars)
+        if len(cellvars) != ncellvars:
+            raise OperationError(self.space.w_TypeError,
+                                 self.space.wrap("bad cellvars"))
+        if self.cells is not None:
+            self.cells[:ncellvars] = cellvars
+
     def fast2locals(self):
-        PyInterpFrame.fast2locals(self)
+        super_fast2locals(self)
         # cellvars are values exported to inner scopes
         # freevars are values coming from outer scopes 
         freevarnames = self.pycode.co_cellvars + self.pycode.co_freevars
@@ -106,7 +129,7 @@
                 self.space.setitem(self.w_locals, w_name, w_value)
 
     def locals2fast(self):
-        PyInterpFrame.locals2fast(self)
+        super_locals2fast(self)
         freevarnames = self.pycode.co_cellvars + self.pycode.co_freevars
         for i in range(len(freevarnames)):
             name = freevarnames[i]
@@ -121,6 +144,8 @@
                 cell.set(w_value)
 
     def init_cells(self):
+        if self.cells is None:
+            return
         args_to_copy = self.pycode._args_as_cellvars
         for i in range(len(args_to_copy)):
             argnum = args_to_copy[i]
@@ -136,13 +161,13 @@
 
     ### extra opcodes ###
 
-    def LOAD_CLOSURE(f, varindex):
+    def LOAD_CLOSURE(f, varindex, *ignored):
         # nested scopes: access the cell object
         cell = f.cells[varindex]
         w_value = f.space.wrap(cell)
         f.valuestack.push(w_value)
 
-    def LOAD_DEREF(f, varindex):
+    def LOAD_DEREF(f, varindex, *ignored):
         # nested scopes: access a variable through its cell object
         cell = f.cells[varindex]
         try:
@@ -160,7 +185,7 @@
         else:
             f.valuestack.push(w_value)
 
-    def STORE_DEREF(f, varindex):
+    def STORE_DEREF(f, varindex, *ignored):
         # nested scopes: access a variable through its cell object
         w_newvalue = f.valuestack.pop()
         #try:
@@ -170,7 +195,7 @@
         #    raise
         cell.set(w_newvalue)
 
-    def MAKE_CLOSURE(f, numdefaults):
+    def MAKE_CLOSURE(f, numdefaults, *ignored):
         w_codeobj = f.valuestack.pop()
         codeobj = f.space.interp_w(pycode.PyCode, w_codeobj)
         if codeobj.magic >= 0xa0df281:    # CPython 2.5 AST branch merge

Modified: pypy/branch/jit-real-world/pypy/interpreter/pycode.py
==============================================================================
--- pypy/branch/jit-real-world/pypy/interpreter/pycode.py	(original)
+++ pypy/branch/jit-real-world/pypy/interpreter/pycode.py	Fri Dec  1 03:43:34 2006
@@ -9,7 +9,7 @@
 from pypy.interpreter import eval
 from pypy.interpreter.error import OperationError
 from pypy.interpreter.gateway import NoneNotWrapped 
-from pypy.interpreter.baseobjspace import ObjSpace, W_Root 
+from pypy.interpreter.baseobjspace import ObjSpace, W_Root
 from pypy.rlib.rarithmetic import intmask
 
 # helper
@@ -49,29 +49,6 @@
 
 cpython_magic, = struct.unpack("<i", imp.get_magic())
 
-NESTED    = 1
-GENERATOR = 2
-
-frame_classes = []
-
-def setup_frame_classes():
-    "NOT_RPYTHON"
-    from pypy.interpreter.pyopcode import PyInterpFrame
-    from pypy.interpreter.nestedscope import PyNestedScopeFrame
-    from pypy.interpreter.generator import GeneratorFrameMixin
-
-    class PyGeneratorFrame(GeneratorFrameMixin, PyInterpFrame):
-        pass
-
-    class PyNestedScopeGeneratorFrame(GeneratorFrameMixin, PyNestedScopeFrame):
-        pass
-
-    frame_classes.extend([None]*4)
-    frame_classes[0]                = PyInterpFrame
-    frame_classes[NESTED]           = PyNestedScopeFrame
-    frame_classes[GENERATOR]        = PyGeneratorFrame
-    frame_classes[NESTED|GENERATOR] = PyNestedScopeGeneratorFrame
-
 
 class PyCode(eval.Code):
     "CPython-style code objects."
@@ -248,21 +225,10 @@
         frame.init_cells()
         return frame.run()
 
-    def get_frame_class(self):
-        # select the appropriate kind of frame
-        if not frame_classes:
-            setup_frame_classes()   # lazily
-        choose = 0
-        if self.co_cellvars or self.co_freevars:
-            choose |= NESTED
-        if self.co_flags & CO_GENERATOR:
-            choose |= GENERATOR
-        Frame = frame_classes[choose]
-        return Frame
-
     def create_frame(self, space, w_globals, closure=None):
         "Create an empty PyFrame suitable for this code object."
-        return self.get_frame_class()(space, self, w_globals, closure)
+        from pypy.interpreter import pyframe
+        return pyframe.PyFrame(space, self, w_globals, closure)
 
     def getvarnames(self):
         return self.co_varnames
@@ -277,20 +243,6 @@
         else:
             return None
 
-    def initialize_frame_scopes(self, frame): 
-        # regular functions always have CO_OPTIMIZED and CO_NEWLOCALS.
-        # class bodies only have CO_NEWLOCALS.
-        # CO_NEWLOCALS: make a locals dict unless optimized is also set
-        # CO_OPTIMIZED: no locals dict needed at all 
-        flags = self.co_flags
-        if flags & CO_OPTIMIZED: 
-            return 
-        if flags & CO_NEWLOCALS:
-            frame.w_locals = frame.space.newdict()
-        else:
-            assert frame.w_globals is not None
-            frame.w_locals = frame.w_globals 
-        
     def getjoinpoints(self):
         """Compute the bytecode positions that are potential join points
         (for FlowObjSpace)"""

Modified: pypy/branch/jit-real-world/pypy/interpreter/pyframe.py
==============================================================================
--- pypy/branch/jit-real-world/pypy/interpreter/pyframe.py	(original)
+++ pypy/branch/jit-real-world/pypy/interpreter/pyframe.py	Fri Dec  1 03:43:34 2006
@@ -1,11 +1,11 @@
 """ PyFrame class implementation with the interpreter main loop.
 """
 
-from pypy.interpreter import eval, baseobjspace
+from pypy.tool.pairtype import extendabletype
+from pypy.interpreter import eval, baseobjspace, pycode
 from pypy.interpreter.miscutils import Stack, FixedStack
 from pypy.interpreter.error import OperationError
 from pypy.interpreter import pytraceback
-from pypy.rlib.rarithmetic import r_uint, intmask
 import opcode
 from pypy.rlib.objectmodel import we_are_translated, instantiate
 from pypy.rlib import rstack # for resume points
@@ -19,13 +19,7 @@
 HAVE_ARGUMENT = opcode.HAVE_ARGUMENT
 
 
-def cpython_tb():
-   """NOT_RPYTHON"""
-   import sys
-   return sys.exc_info()[2]   
-cpython_tb._annspecialcase_ = "override:ignore"
-
-class PyFrame(eval.EvalFrame):
+class PyFrame(eval.Frame):
     """Represents a frame for a regular Python function
     that needs to be interpreted.
 
@@ -37,9 +31,21 @@
      * 'w_locals' is the locals dictionary to use
      * 'w_globals' is the attached globals dictionary
      * 'builtin' is the attached built-in module
-     * 'valuestack', 'blockstack', 'next_instr' control the interpretation
+     * 'valuestack', 'blockstack', control the interpretation
     """
 
+    __metaclass__ = extendabletype
+
+    frame_finished_execution = False
+    last_instr               = -1
+    last_exception           = None
+    f_back                   = None
+    w_f_trace                = None
+    # For tracing
+    instr_lb                 = 0
+    instr_ub                 = -1
+    instr_prev               = -1
+
     def __init__(self, space, code, w_globals, closure):
         self.pycode = code
         eval.Frame.__init__(self, space, w_globals, code.co_nlocals)
@@ -51,37 +57,72 @@
         else:
             self.valuestack = Stack()
         self.blockstack = Stack()
-        self.last_exception = None
-        self.next_instr = r_uint(0) # Force it unsigned for performance reasons.
         self.builtin = space.builtin.pick_builtin(w_globals)
         # regular functions always have CO_OPTIMIZED and CO_NEWLOCALS.
         # class bodies only have CO_NEWLOCALS.
-        code.initialize_frame_scopes(self)
+        self.initialize_frame_scopes(closure)
         self.fastlocals_w = [None]*self.numlocals
-        self.w_f_trace = None
-        self.last_instr = -1
-        self.f_back = None
         self.f_lineno = self.pycode.co_firstlineno
         
-        # For tracing
-        self.instr_lb = 0
-        self.instr_ub = -1
-        self.instr_prev = -1
+    def initialize_frame_scopes(self, closure): 
+        # regular functions always have CO_OPTIMIZED and CO_NEWLOCALS.
+        # class bodies only have CO_NEWLOCALS.
+        # CO_NEWLOCALS: make a locals dict unless optimized is also set
+        # CO_OPTIMIZED: no locals dict needed at all
+        # NB: this method is overridden in nestedscope.py
+        flags = self.pycode.co_flags
+        if flags & pycode.CO_OPTIMIZED: 
+            return 
+        if flags & pycode.CO_NEWLOCALS:
+            self.w_locals = self.space.newdict()
+        else:
+            assert self.w_globals is not None
+            self.w_locals = self.w_globals
+
+    def run(self):
+        """Start this frame's execution."""
+        if self.pycode.co_flags & pycode.CO_GENERATOR:
+            from pypy.interpreter.generator import GeneratorIterator
+            return self.space.wrap(GeneratorIterator(self))
+        else:
+            return self.execute_frame()
+
+    def execute_frame(self):
+        """Execute this frame.  Main entry point to the interpreter."""
+        executioncontext = self.space.getexecutioncontext()
+        executioncontext.enter(self)
+        try:
+            executioncontext.call_trace(self)
+            code = self.pycode.co_code
+            # Execution starts just after the last_instr.  Initially,
+            # last_instr is -1.  After a generator suspends it points to
+            # the YIELD_VALUE instruction.
+            next_instr = self.last_instr + 1
+            w_exitvalue = self.dispatch(code, next_instr, executioncontext)
+            executioncontext.return_trace(self, w_exitvalue)
+            # on exit, we try to release self.last_exception -- breaks an
+            # obvious reference cycle, so it helps refcounting implementations
+            self.last_exception = None
+        finally:
+            executioncontext.leave(self)
+        return w_exitvalue
+    execute_frame.insert_stack_check_here = True
+
 
     def descr__reduce__(self, space):
         from pypy.interpreter.mixedmodule import MixedModule
         from pypy.module._pickle_support import maker # helper fns
-        from pypy.interpreter.nestedscope import PyNestedScopeFrame
         w_mod    = space.getbuiltinmodule('_pickle_support')
         mod      = space.interp_w(MixedModule, w_mod)
         new_inst = mod.get('frame_new')
         w        = space.wrap
         nt = space.newtuple
 
-        if isinstance(self, PyNestedScopeFrame):
-            w_cells = space.newlist([w(cell) for cell in self.cells])
-        else:
+        cells = self._getcells()
+        if cells is None:
             w_cells = space.w_None
+        else:
+            w_cells = space.newlist([space.wrap(cell) for cell in cells])
 
         if self.w_f_trace is None:
             f_lineno = self.get_last_lineno()
@@ -114,7 +155,7 @@
             w_tb,        #
             self.w_globals,
             w(self.last_instr),
-            w(self.next_instr),
+            w(self.frame_finished_execution),
             w(f_lineno),
             w_fastlocals,
             space.w_None,           #XXX placeholder for f_locals
@@ -134,20 +175,28 @@
         from pypy.module._pickle_support import maker # helper fns
         from pypy.interpreter.pycode import PyCode
         from pypy.interpreter.module import Module
-        from pypy.interpreter.nestedscope import PyNestedScopeFrame, Cell
         args_w = space.unpackiterable(w_args)
         w_f_back, w_builtin, w_pycode, w_valuestack, w_blockstack, w_exc_value, w_tb,\
-            w_globals, w_last_instr, w_next_instr, w_f_lineno, w_fastlocals, w_f_locals, \
+            w_globals, w_last_instr, w_finished, w_f_lineno, w_fastlocals, w_f_locals, \
             w_f_trace, w_instr_lb, w_instr_ub, w_instr_prev, w_cells = args_w
 
-        #new_frame = PyFrame(space, pycode, w(globals), None)
-        # let the code object create the right kind of frame
-        # the distinction is a little over-done but computable
         new_frame = self
         pycode = space.interp_w(PyCode, w_pycode)
+
+        if space.is_w(w_cells, space.w_None):
+            closure = None
+            cellvars = []
+        else:
+            from pypy.interpreter.nestedscope import Cell
+            cells_w = space.unpackiterable(w_cells)
+            cells = [space.interp_w(Cell, w_cell) for w_cell in cells_w]
+            ncellvars = len(pycode.co_cellvars)
+            cellvars = cells[:ncellvars]
+            closure = cells[ncellvars:]
+        
         # do not use the instance's __init__ but the base's, because we set
         # everything like cells from here
-        PyFrame.__init__(self, space, pycode, w_globals, None)
+        PyFrame.__init__(self, space, pycode, w_globals, closure)
         new_frame.f_back = space.interp_w(PyFrame, w_f_back, can_be_None=True)
         new_frame.builtin = space.interp_w(Module, w_builtin)
         new_frame.blockstack.items = [unpickle_block(space, w_blk)
@@ -165,7 +214,7 @@
                                                       w_exc_value, tb
                                                       )
         new_frame.last_instr = space.int_w(w_last_instr)
-        new_frame.next_instr = space.int_w(w_next_instr)
+        new_frame.frame_finished_execution = space.is_true(w_finished)
         new_frame.f_lineno = space.int_w(w_f_lineno)
         new_frame.fastlocals_w = maker.slp_from_tuple_with_nulls(space, w_fastlocals)
 
@@ -178,9 +227,7 @@
         new_frame.instr_ub = space.int_w(w_instr_ub)
         new_frame.instr_prev = space.int_w(w_instr_prev)
 
-        if isinstance(self, PyNestedScopeFrame):
-            cells_w = space.unpackiterable(w_cells)
-            self.cells = [space.interp_w(Cell, w_cell) for w_cell in cells_w]
+        self._setcellvars(cellvars)
 
     def hide(self):
         return self.pycode.hidden_applevel
@@ -203,67 +250,18 @@
 
     def init_cells(self):
         """Initialize cellvars from self.fastlocals_w
-        This is overridden in PyNestedScopeFrame"""
+        This is overridden in nestedscope.py"""
         pass
     
     def getclosure(self):
         return None
 
-    def eval(self, executioncontext):
-        "Interpreter main loop!"
-        try:
-            executioncontext.call_trace(self)
-            self.last_instr = 0
-            while True:
-                try:
-                    try:
-                        try:
-                            if we_are_translated():
-                                # always raising, put the resume point just before!
-                                rstack.resume_point("eval", self, executioncontext)
-                                code = self.pycode.co_code
-                                self.dispatch_translated(code,
-                                                         executioncontext)
-                            else:
-                                self.dispatch(executioncontext)
-                        # catch asynchronous exceptions and turn them
-                        # into OperationErrors
-                        except KeyboardInterrupt:
-                            tb = cpython_tb()
-                            raise OperationError, OperationError(self.space.w_KeyboardInterrupt,
-                                                   self.space.w_None), tb
-                        except MemoryError:
-                            tb = cpython_tb()
-                            raise OperationError, OperationError(self.space.w_MemoryError,
-                                                   self.space.w_None), tb
-                        except RuntimeError, e:
-                            tb = cpython_tb()
-                            raise OperationError, OperationError(self.space.w_RuntimeError,
-                                self.space.wrap("internal error: " + str(e))), tb
-
-                    except OperationError, e:
-                        pytraceback.record_application_traceback(
-                            self.space, e, self, self.last_instr)
-                        executioncontext.exception_trace(self, e)
-                        # convert an OperationError into a control flow
-                        # exception
-                        raise SApplicationException(e)
-
-                except ControlFlowException, ctlflowexc:
-                    # we have a reason to change the control flow
-                    # (typically unroll the stack)
-                    ctlflowexc.action(self)
-            
-        except ExitFrame, e:
-            # leave that frame
-            w_exitvalue = e.w_exitvalue
-            executioncontext.return_trace(self, w_exitvalue)
-            # on exit, we try to release self.last_exception -- breaks an
-            # obvious reference cycle, so it helps refcounting implementations
-            self.last_exception = None
-            return w_exitvalue
-    eval.insert_stack_check_here = True
-    
+    def _getcells(self):
+        return None
+
+    def _setcellvars(self, cellvars):
+        pass
+
     ### line numbers ###
 
     # for f*_f_* unwrapping through unwrap_spec in typedef.py
@@ -401,11 +399,7 @@
             
     def get_last_lineno(self):
         "Returns the line number of the instruction currently being executed."
-        return pytraceback.offset2lineno(self.pycode, intmask(self.next_instr)-1)
-
-    def get_next_lineno(self):
-        "Returns the line number of the next instruction to execute."
-        return pytraceback.offset2lineno(self.pycode, intmask(self.next_instr))
+        return pytraceback.offset2lineno(self.pycode, self.last_instr)
 
     def fget_f_builtins(space, self):
         return self.builtin.getdict()
@@ -459,251 +453,11 @@
     def fget_f_restricted(space, self):
         return space.wrap(self.builtin is not space.builtin)
 
-### Frame Blocks ###
-
-class FrameBlock:
-
-    """Abstract base class for frame blocks from the blockstack,
-    used by the SETUP_XXX and POP_BLOCK opcodes."""
-
-    def __init__(self, frame, handlerposition):
-        self.handlerposition = handlerposition
-        self.valuestackdepth = frame.valuestack.depth()
-
-    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):
-        for i in range(self.valuestackdepth, frame.valuestack.depth()):
-            frame.valuestack.pop()
-
-    def cleanup(self, frame):
-        "Clean up a frame when we normally exit the block."
-        self.cleanupstack(frame)
-
-    def unroll(self, frame, unroller):
-        "Clean up a frame when we abnormally exit the block."
-        self.cleanupstack(frame)
-        return False  # continue to unroll
-
-    # internal pickling interface, not using the standard protocol
-    def _get_state_(self, space):
-        w = space.wrap
-        return space.newtuple([w(self._opname), w(self.handlerposition),
-                               w(self.valuestackdepth)])
-
-class LoopBlock(FrameBlock):
-    """A loop block.  Stores the end-of-loop pointer in case of 'break'."""
-
-    _opname = 'SETUP_LOOP'
-
-    def unroll(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.blockstack.push(self)
-            frame.next_instr = unroller.jump_to
-            return True  # stop unrolling
-        self.cleanupstack(frame)
-        if isinstance(unroller, SBreakLoop):
-            # jump to the end of the loop
-            frame.next_instr = self.handlerposition
-            return True  # stop unrolling
-        return False
-
-
-class ExceptBlock(FrameBlock):
-    """An try:except: block.  Stores the position of the exception handler."""
-
-    _opname = 'SETUP_EXCEPT'
-
-    def unroll(self, frame, unroller):
-        self.cleanupstack(frame)
-        if isinstance(unroller, SApplicationException):
-            # push the exception to the value stack for inspection by the
-            # exception handler (the code after the except:)
-            operationerr = unroller.operr
-            if frame.space.full_exceptions:
-                operationerr.normalize_exception(frame.space)
-            # the stack setup is slightly different than in CPython:
-            # instead of the traceback, we store the unroller object,
-            # wrapped.
-            frame.valuestack.push(unroller.wrap(frame.space))
-            frame.valuestack.push(operationerr.w_value)
-            frame.valuestack.push(operationerr.w_type)
-            frame.next_instr = self.handlerposition   # jump to the handler
-            return True  # stop unrolling
-        return False
-
-
-class FinallyBlock(FrameBlock):
-    """A try:finally: block.  Stores the position of the exception handler."""
-
-    _opname = 'SETUP_FINALLY'
-
-    def cleanup(self, frame):
-        # upon normal entry into the finally: part, the standard Python
-        # bytecode pushes a single None for END_FINALLY.  In our case we
-        # always push three values into the stack: the wrapped ctlflowexc,
-        # the exception value and the exception type (which are all None
-        # here).
-        self.cleanupstack(frame)
-        # one None already pushed by the bytecode
-        frame.valuestack.push(frame.space.w_None)
-        frame.valuestack.push(frame.space.w_None)
-
-    def unroll(self, frame, unroller):
-        # any abnormal reason for unrolling a finally: triggers the end of
-        # the block unrolling and the entering the finally: handler.
-        # see comments in cleanup().
-        self.cleanupstack(frame)
-        frame.valuestack.push(unroller.wrap(frame.space))
-        frame.valuestack.push(frame.space.w_None)
-        frame.valuestack.push(frame.space.w_None)
-        frame.next_instr = self.handlerposition   # jump to the handler
-        return True  # stop unrolling
-
-
-### Internal exceptions that change the control flow ###
-### and (typically) unroll the block stack           ###
-
-class ControlFlowException(Exception):
-    """Abstract base class for interpreter-level exceptions 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,    we don't think this is needed
-                WHY_RETURN,     SReturnValue
-                WHY_BREAK,      SBreakLoop
-                WHY_CONTINUE,   SContinueLoop
-                WHY_YIELD       SYieldValue
-
-    """
-    def action(self, frame):
-        "Default unroller implementation."
-        while not frame.blockstack.empty():
-            block = frame.blockstack.pop()
-            if block.unroll(frame, self):
-                break
-        else:
-            self.emptystack(frame)
-
-    def emptystack(self, frame):
-        "Default behavior when the block stack is exhausted."
-        # could occur e.g. when a BREAK_LOOP is not actually within a loop
-        raise BytecodeCorruption, "block stack exhausted"
-
-    def wrap(self, space):
-        return space.wrap(SuspendedUnroller(self))
-
-    # for the flow object space, a way to "pickle" and "unpickle" the
-    # ControlFlowException by enumerating the Variables it contains.
-    def state_unpack_variables(self, space):
-        return []     # by default, overridden below
-    def state_pack_variables(self, space, *values_w):
-        assert len(values_w) == 0
-
-class SuspendedUnroller(baseobjspace.Wrappable):
-    """A wrappable box around a ControlFlowException."""
-    def __init__(self, flowexc):
-        self.flowexc = flowexc
-
-class SApplicationException(ControlFlowException):
-    """Unroll the stack because of an application-level exception
-    (i.e. an OperationException)."""
-
-    def __init__(self, operr):
-        self.operr = operr
-
-    def action(self, frame):
-        frame.last_exception = self.operr
-        ControlFlowException.action(self, frame)
-
-    def emptystack(self, frame):
-        # propagate the exception to the caller
-        from pypy.rlib.objectmodel import we_are_translated
-        if we_are_translated():
-            raise self.operr
-        else:
-            # try to preserve the interp-level traceback
-            if self.operr.debug_excs:
-                _, _, tb = self.operr.debug_excs[-1]
-            else:
-                tb = None
-            raise OperationError, self.operr, tb
-
-    def state_unpack_variables(self, space):
-        return [self.operr.w_type, self.operr.w_value]
-    def state_pack_variables(self, space, w_type, w_value):
-        self.operr = OperationError(w_type, w_value)
-
-class SBreakLoop(ControlFlowException):
-    """Signals a 'break' statement."""
-
-class SContinueLoop(ControlFlowException):
-    """Signals a 'continue' statement.
-    Argument is the bytecode position of the beginning of the loop."""
-
-    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(self, space, w_jump_to):
-        self.jump_to = space.int_w(w_jump_to)
-
-class SReturnValue(ControlFlowException):
-    """Signals a 'return' statement.
-    Argument is the wrapped object to return."""
-
-    def __init__(self, w_returnvalue):
-        self.w_returnvalue = w_returnvalue
-
-    def emptystack(self, frame):
-        raise ExitFrame(self.w_returnvalue)
-
-    def state_unpack_variables(self, space):
-        return [self.w_returnvalue]
-    def state_pack_variables(self, space, w_returnvalue):
-        self.w_returnvalue = w_returnvalue
-
-class ExitFrame(Exception):
-    """Signals the end of the frame execution.
-    The argument is the returned or yielded value, already wrapped."""
-    def __init__(self, w_exitvalue):
-        self.w_exitvalue = w_exitvalue
-
-class BytecodeCorruption(ValueError):
-    """Detected bytecode corruption.  Never caught; it's an error."""
-
 # ____________________________________________________________
 
-def setup_block_classes():
-    "NOT_RPYTHON"
-    import types
-    for cls in globals().values():
-        if isinstance(cls, (types.ClassType,type)):
-            if issubclass(cls, FrameBlock) and hasattr(cls, '_opname'):
-                block_classes[cls._opname] = cls
-block_classes = {}
-setup_block_classes()
-
 def get_block_class(opname):
     # select the appropriate kind of block
+    from pypy.interpreter.pyopcode import block_classes
     return block_classes[opname]
 
 def unpickle_block(space, w_tup):

Modified: pypy/branch/jit-real-world/pypy/interpreter/pyopcode.py
==============================================================================
--- pypy/branch/jit-real-world/pypy/interpreter/pyopcode.py	(original)
+++ pypy/branch/jit-real-world/pypy/interpreter/pyopcode.py	Fri Dec  1 03:43:34 2006
@@ -5,22 +5,22 @@
 """
 
 from pypy.interpreter.error import OperationError
-from pypy.interpreter.baseobjspace import UnpackValueError
+from pypy.interpreter.baseobjspace import UnpackValueError, Wrappable
 from pypy.interpreter import gateway, function, eval
 from pypy.interpreter import pyframe, pytraceback
-from pypy.interpreter.miscutils import InitializedClass
 from pypy.interpreter.argument import Arguments, ArgumentsFromValuestack
 from pypy.interpreter.pycode import PyCode
-from pypy.interpreter.opcodeorder import opcodeorder
 from pypy.tool.sourcetools import func_with_new_name
 from pypy.rlib.objectmodel import we_are_translated, hint
-from pypy.rlib.rarithmetic import intmask
-from pypy.tool import stdlib_opcode as pythonopcode
+from pypy.rlib.rarithmetic import r_uint, intmask
+from pypy.tool.stdlib_opcode import opcodedesc, HAVE_ARGUMENT
+from pypy.tool.stdlib_opcode import unrolling_opcode_descs
+from pypy.tool.stdlib_opcode import opcode_method_names
 from pypy.rlib import rstack # for resume points
 
 def unaryoperation(operationname):
     """NOT_RPYTHON"""
-    def opimpl(f):
+    def opimpl(f, *ignored):
         operation = getattr(f.space, operationname)
         w_1 = f.valuestack.pop()
         w_result = operation(w_1)
@@ -30,7 +30,7 @@
 
 def binaryoperation(operationname):
     """NOT_RPYTHON"""    
-    def opimpl(f):
+    def opimpl(f, *ignored):
         operation = getattr(f.space, operationname)
         w_2 = f.valuestack.pop()
         w_1 = f.valuestack.pop()
@@ -40,52 +40,167 @@
     return func_with_new_name(opimpl, "opcode_impl_for_%s" % operationname)        
 
 
-class PyInterpFrame(pyframe.PyFrame):
+class __extend__(pyframe.PyFrame):
     """A PyFrame that knows about interpretation of standard Python opcodes
     minus the ones related to nested scopes."""
     
     ### opcode dispatch ###
- 
-    # 'opcode_has_arg' is a class attribute: list of True/False whether opcode takes arg
-    # 'dispatch_table_no_arg: list of functions/None
-    # 'dispatch_table_w_arg: list of functions/None 
-    # Currently, they are always setup in pyopcode.py
-    # but it could be a custom table.
 
-    def dispatch(self, ec):
+    def dispatch(self, co_code, next_instr, ec):
         while True:
-            self.last_instr = intmask(self.next_instr)
+            try:
+                return self.dispatch_bytecode(co_code, next_instr, ec)
+            except OperationError, operr:
+                next_instr = self.handle_operation_error(ec, operr)
+            except Reraise:
+                operr = self.last_exception
+                next_instr = self.handle_operation_error(ec, operr,
+                                                         attach_tb=False)
+            except KeyboardInterrupt:
+                next_instr = self.handle_asynchronous_error(ec,
+                    self.space.w_KeyboardInterrupt)
+            except MemoryError:
+                next_instr = self.handle_asynchronous_error(ec,
+                    self.space.w_MemoryError)
+            except RuntimeError:
+                if we_are_translated():
+                    # stack overflows should be the only kind of RuntimeErrors
+                    # in translated PyPy
+                    msg = "internal error (stack overflow?)"
+                else:
+                    msg = str(e)
+                next_instr = self.handle_asynchronous_error(ec,
+                    self.space.w_RuntimeError,
+                    self.space.wrap(msg))
+
+    def handle_asynchronous_error(self, ec, w_type, w_value=None):
+        # catch asynchronous exceptions and turn them
+        # into OperationErrors
+        if w_value is None:
+            w_value = self.space.w_None
+        operr = OperationError(w_type, w_value)
+        return self.handle_operation_error(ec, operr)
+
+    def handle_operation_error(self, ec, operr, attach_tb=True):
+        self.last_exception = operr
+        if attach_tb:
+            pytraceback.record_application_traceback(
+                self.space, operr, self, self.last_instr)
+            ec.exception_trace(self, operr)
+
+        block = self.unrollstack(SApplicationException.kind)
+        if block is None:
+            # no handler found for the OperationError
+            tb = cpython_tb()
+            raise OperationError, operr, tb
+        else:
+            unroller = SApplicationException(operr)
+            next_instr = block.handle(self, unroller)
+            return next_instr
+
+    def dispatch_bytecode(self, co_code, next_instr, ec):
+        space = self.space
+        while True:
+            self.last_instr = intmask(next_instr)
             ec.bytecode_trace(self)
-            self.next_instr = self.last_instr
-            opcode = self.nextop()
-            if self.space.config.objspace.logbytecodes:
-                self.space.bytecodecounts[opcode] = self.space.bytecodecounts.get(opcode, 0) + 1
-            if opcode >= pythonopcode.HAVE_ARGUMENT:
-                oparg = self.nextarg()
-                while True:
-                    if opcode == pythonopcode.EXTENDED_ARG:
-                        opcode = self.nextop()
-                        oparg = oparg<<16 | self.nextarg()
-                        if opcode < pythonopcode.HAVE_ARGUMENT:
-                            raise pyframe.BytecodeCorruption
-                        continue
-                    else:
-                        fn = self.dispatch_table_w_arg[opcode]
-                        fn(self, oparg)                    
-                    break
+            # For the sequel, force 'next_instr' to be unsigned for performance
+            next_instr = r_uint(self.last_instr)
+            opcode = ord(co_code[next_instr])
+            next_instr += 1
+            if space.config.objspace.logbytecodes:
+                space.bytecodecounts[opcode] = space.bytecodecounts.get(opcode, 0) + 1
+
+            if opcode >= HAVE_ARGUMENT:
+                lo = ord(co_code[next_instr])
+                hi = ord(co_code[next_instr+1])
+                next_instr += 2
+                oparg = (hi << 8) | lo
             else:
-                fn = self.dispatch_table_no_arg[opcode] 
-                fn(self)
+                oparg = 0
 
-    def nextop(self):
-        c = self.pycode.co_code[self.next_instr]
-        self.next_instr += 1
-        return ord(c)
-
-    def nextarg(self):
-        lo = self.nextop()
-        hi = self.nextop()
-        return (hi<<8) + lo
+            while opcode == opcodedesc.EXTENDED_ARG.index:
+                opcode = ord(co_code[next_instr])
+                if opcode < HAVE_ARGUMENT:
+                    raise BytecodeCorruption
+                lo = ord(co_code[next_instr+1])
+                hi = ord(co_code[next_instr+2])
+                next_instr += 3
+                oparg = (oparg << 16) | (hi << 8) | lo
+
+            if opcode == opcodedesc.RETURN_VALUE.index:
+                w_returnvalue = self.valuestack.pop()
+                block = self.unrollstack(SReturnValue.kind)
+                if block is None:
+                    self.frame_finished_execution = True  # for generators
+                    return w_returnvalue
+                else:
+                    unroller = SReturnValue(w_returnvalue)
+                    next_instr = block.handle(self, unroller)
+                    continue    # now inside a 'finally' block
+
+            if opcode == opcodedesc.YIELD_VALUE.index:
+                w_yieldvalue = self.valuestack.pop()
+                return w_yieldvalue
+
+            if opcode == opcodedesc.END_FINALLY.index:
+                # unlike CPython, when we reach this opcode the value stack has
+                # always been set up as follows (topmost first):
+                #   [exception type  or None]
+                #   [exception value or None]
+                #   [wrapped stack unroller ]
+                self.valuestack.pop()   # ignore the exception type
+                self.valuestack.pop()   # ignore the exception value
+                w_unroller = self.valuestack.pop()
+                unroller = self.space.interpclass_w(w_unroller)
+                if isinstance(unroller, SuspendedUnroller):
+                    # go on unrolling the stack
+                    block = self.unrollstack(unroller.kind)
+                    if block is None:
+                        self.frame_finished_execution = True  # for generators
+                        return unroller.nomoreblocks()
+                    else:
+                        next_instr = block.handle(self, unroller)
+                continue
+
+            if we_are_translated():
+                for opdesc in unrolling_opcode_descs:
+                    # static checks to skip this whole case if necessary
+                    if not opdesc.is_enabled(space):
+                        continue
+                    if not hasattr(pyframe.PyFrame, opdesc.methodname):
+                        continue   # e.g. for JUMP_FORWARD, implemented above
+
+                    if opcode == opdesc.index:
+                        # dispatch to the opcode method
+                        meth = getattr(self, opdesc.methodname)
+                        res = meth(oparg, next_instr)
+                        # !! warning, for the annotator the next line is not
+                        # comparing an int and None - you can't do that.
+                        # Instead, it's constant-folded to either True or False
+                        if res is not None:
+                            next_instr = res
+                        break
+                else:
+                    self.MISSING_OPCODE(oparg, next_instr)
+
+            else:  # when we are not translated, a list lookup is much faster
+                methodname = opcode_method_names[opcode]
+                res = getattr(self, methodname)(oparg, next_instr)
+                if res is not None:
+                    next_instr = res
+
+    def unrollstack(self, unroller_kind):
+        while not self.blockstack.empty():
+            block = self.blockstack.pop()
+            if (block.handling_mask & unroller_kind) != 0:
+                return block
+        return None
+
+    def unrollstack_and_jump(self, unroller):
+        block = self.unrollstack(unroller.kind)
+        if block is None:
+            raise BytecodeCorruption("misplaced bytecode - should not return")
+        return block.handle(self, unroller)
 
     ### accessor functions ###
 
@@ -110,10 +225,10 @@
     #  the 'self' argument of opcode implementations is called 'f'
     #  for historical reasons
 
-    def NOP(f):
+    def NOP(f, *ignored):
         pass
 
-    def LOAD_FAST(f, varindex):
+    def LOAD_FAST(f, varindex, *ignored):
         # access a local variable directly
         w_value = f.fastlocals_w[varindex]
         if w_value is None:
@@ -122,11 +237,11 @@
             raise OperationError(f.space.w_UnboundLocalError, f.space.wrap(message))
         f.valuestack.push(w_value)
 
-    def LOAD_CONST(f, constindex):
+    def LOAD_CONST(f, constindex, *ignored):
         w_const = f.getconstant_w(constindex)
         f.valuestack.push(w_const)
 
-    def STORE_FAST(f, varindex):
+    def STORE_FAST(f, varindex, *ignored):
         w_newvalue = f.valuestack.pop()
         f.fastlocals_w[varindex] = w_newvalue
         #except:
@@ -139,16 +254,16 @@
         #    print "co_nlocals", f.pycode.co_nlocals
         #    raise
 
-    def POP_TOP(f):
+    def POP_TOP(f, *ignored):
         f.valuestack.pop()
 
-    def ROT_TWO(f):
+    def ROT_TWO(f, *ignored):
         w_1 = f.valuestack.pop()
         w_2 = f.valuestack.pop()
         f.valuestack.push(w_1)
         f.valuestack.push(w_2)
 
-    def ROT_THREE(f):
+    def ROT_THREE(f, *ignored):
         w_1 = f.valuestack.pop()
         w_2 = f.valuestack.pop()
         w_3 = f.valuestack.pop()
@@ -156,7 +271,7 @@
         f.valuestack.push(w_3)
         f.valuestack.push(w_2)
 
-    def ROT_FOUR(f):
+    def ROT_FOUR(f, *ignored):
         w_1 = f.valuestack.pop()
         w_2 = f.valuestack.pop()
         w_3 = f.valuestack.pop()
@@ -166,11 +281,11 @@
         f.valuestack.push(w_3)
         f.valuestack.push(w_2)
 
-    def DUP_TOP(f):
+    def DUP_TOP(f, *ignored):
         w_1 = f.valuestack.top()
         f.valuestack.push(w_1)
 
-    def DUP_TOPX(f, itemcount):
+    def DUP_TOPX(f, itemcount, *ignored):
         assert 1 <= itemcount <= 5, "limitation of the current interpreter"
         for i in range(itemcount):
             w_1 = f.valuestack.top(itemcount-1)
@@ -182,7 +297,7 @@
     UNARY_CONVERT  = unaryoperation("repr")
     UNARY_INVERT   = unaryoperation("invert")
 
-    def BINARY_POWER(f):
+    def BINARY_POWER(f, *ignored):
         w_2 = f.valuestack.pop()
         w_1 = f.valuestack.pop()
         w_result = f.space.pow(w_1, w_2, f.space.w_None)
@@ -203,7 +318,7 @@
     BINARY_XOR = binaryoperation("xor")
     BINARY_OR  = binaryoperation("or_")
 
-    def INPLACE_POWER(f):
+    def INPLACE_POWER(f, *ignored):
         w_2 = f.valuestack.pop()
         w_1 = f.valuestack.pop()
         w_result = f.space.inplace_pow(w_1, w_2)
@@ -228,18 +343,18 @@
         w_result = f.space.getslice(w_obj, w_start, w_end)
         f.valuestack.push(w_result)
 
-    def SLICE_0(f):
+    def SLICE_0(f, *ignored):
         f.slice(f.space.w_None, f.space.w_None)
 
-    def SLICE_1(f):
+    def SLICE_1(f, *ignored):
         w_start = f.valuestack.pop()
         f.slice(w_start, f.space.w_None)
 
-    def SLICE_2(f):
+    def SLICE_2(f, *ignored):
         w_end = f.valuestack.pop()
         f.slice(f.space.w_None, w_end)
 
-    def SLICE_3(f):
+    def SLICE_3(f, *ignored):
         w_end = f.valuestack.pop()
         w_start = f.valuestack.pop()
         f.slice(w_start, w_end)
@@ -249,18 +364,18 @@
         w_newvalue = f.valuestack.pop()
         f.space.setslice(w_obj, w_start, w_end, w_newvalue)
 
-    def STORE_SLICE_0(f):
+    def STORE_SLICE_0(f, *ignored):
         f.storeslice(f.space.w_None, f.space.w_None)
 
-    def STORE_SLICE_1(f):
+    def STORE_SLICE_1(f, *ignored):
         w_start = f.valuestack.pop()
         f.storeslice(w_start, f.space.w_None)
 
-    def STORE_SLICE_2(f):
+    def STORE_SLICE_2(f, *ignored):
         w_end = f.valuestack.pop()
         f.storeslice(f.space.w_None, w_end)
 
-    def STORE_SLICE_3(f):
+    def STORE_SLICE_3(f, *ignored):
         w_end = f.valuestack.pop()
         w_start = f.valuestack.pop()
         f.storeslice(w_start, w_end)
@@ -269,69 +384,69 @@
         w_obj = f.valuestack.pop()
         f.space.delslice(w_obj, w_start, w_end)
 
-    def DELETE_SLICE_0(f):
+    def DELETE_SLICE_0(f, *ignored):
         f.deleteslice(f.space.w_None, f.space.w_None)
 
-    def DELETE_SLICE_1(f):
+    def DELETE_SLICE_1(f, *ignored):
         w_start = f.valuestack.pop()
         f.deleteslice(w_start, f.space.w_None)
 
-    def DELETE_SLICE_2(f):
+    def DELETE_SLICE_2(f, *ignored):
         w_end = f.valuestack.pop()
         f.deleteslice(f.space.w_None, w_end)
 
-    def DELETE_SLICE_3(f):
+    def DELETE_SLICE_3(f, *ignored):
         w_end = f.valuestack.pop()
         w_start = f.valuestack.pop()
         f.deleteslice(w_start, w_end)
 
-    def STORE_SUBSCR(f):
+    def STORE_SUBSCR(f, *ignored):
         "obj[subscr] = newvalue"
         w_subscr = f.valuestack.pop()
         w_obj = f.valuestack.pop()
         w_newvalue = f.valuestack.pop()
         f.space.setitem(w_obj, w_subscr, w_newvalue)
 
-    def DELETE_SUBSCR(f):
+    def DELETE_SUBSCR(f, *ignored):
         "del obj[subscr]"
         w_subscr = f.valuestack.pop()
         w_obj = f.valuestack.pop()
         f.space.delitem(w_obj, w_subscr)
 
-    def PRINT_EXPR(f):
+    def PRINT_EXPR(f, *ignored):
         w_expr = f.valuestack.pop()
         print_expr(f.space, w_expr)
 
-    def PRINT_ITEM_TO(f):
+    def PRINT_ITEM_TO(f, *ignored):
         w_stream = f.valuestack.pop()
         w_item = f.valuestack.pop()
         if f.space.is_w(w_stream, f.space.w_None):
             w_stream = sys_stdout(f.space)   # grumble grumble special cases
         print_item_to(f.space, w_item, w_stream)
 
-    def PRINT_ITEM(f):
+    def PRINT_ITEM(f, *ignored):
         w_item = f.valuestack.pop()
         print_item(f.space, w_item)
 
-    def PRINT_NEWLINE_TO(f):
+    def PRINT_NEWLINE_TO(f, *ignored):
         w_stream = f.valuestack.pop()
         if f.space.is_w(w_stream, f.space.w_None):
             w_stream = sys_stdout(f.space)   # grumble grumble special cases
         print_newline_to(f.space, w_stream)
 
-    def PRINT_NEWLINE(f):
+    def PRINT_NEWLINE(f, *ignored):
         print_newline(f.space)
 
-    def BREAK_LOOP(f):
-        raise pyframe.SBreakLoop
-
-    def CONTINUE_LOOP(f, startofloop):
-        raise pyframe.SContinueLoop(startofloop)
+    def BREAK_LOOP(f, *ignored):
+        next_instr = f.unrollstack_and_jump(SBreakLoop.singleton)
+        return next_instr
+
+    def CONTINUE_LOOP(f, startofloop, *ignored):
+        unroller = SContinueLoop(startofloop)
+        next_instr = f.unrollstack_and_jump(unroller)
+        return next_instr
 
-    def RAISE_VARARGS(f, nbargs):
-        # we use the .app.py file to prepare the exception/value/traceback
-        # but not to actually raise it, because we cannot use the 'raise'
-        # statement to implement RAISE_VARARGS
+    def RAISE_VARARGS(f, nbargs, *ignored):
         space = f.space
         if nbargs == 0:
             operror = space.getexecutioncontext().sys_exc_info()
@@ -339,7 +454,9 @@
                 raise OperationError(space.w_TypeError,
                     space.wrap("raise: no active exception to re-raise"))
             # re-raise, no new traceback obj will be attached
-            raise pyframe.SApplicationException(operror)
+            f.last_exception = operror
+            raise Reraise
+
         w_value = w_traceback = space.w_None
         if nbargs >= 3: w_traceback = f.valuestack.pop()
         if nbargs >= 2: w_value     = f.valuestack.pop()
@@ -357,16 +474,13 @@
                       space.wrap("raise: arg 3 must be a traceback or None"))
             operror.application_traceback = tb
             # re-raise, no new traceback obj will be attached
-            raise pyframe.SApplicationException(operror) 
+            f.last_exception = operror
+            raise Reraise
 
-    def LOAD_LOCALS(f):
+    def LOAD_LOCALS(f, *ignored):
         f.valuestack.push(f.w_locals)
 
-    def RETURN_VALUE(f):
-        w_returnvalue = f.valuestack.pop()
-        raise pyframe.SReturnValue(w_returnvalue)
-
-    def EXEC_STMT(f):
+    def EXEC_STMT(f, *ignored):
         w_locals  = f.valuestack.pop()
         w_globals = f.valuestack.pop()
         w_prog    = f.valuestack.pop()
@@ -386,25 +500,11 @@
         if plain:
             f.setdictscope(w_locals)
 
-    def POP_BLOCK(f):
+    def POP_BLOCK(f, *ignored):
         block = f.blockstack.pop()
         block.cleanup(f)  # the block knows how to clean up the value stack
 
-    def END_FINALLY(f):
-        # unlike CPython, when we reach this opcode the value stack has
-        # always been set up as follows (topmost first):
-        #   [exception type  or None]
-        #   [exception value or None]
-        #   [wrapped stack unroller ]
-        f.valuestack.pop()   # ignore the exception type
-        f.valuestack.pop()   # ignore the exception value
-        w_unroller = f.valuestack.pop()
-        unroller = f.space.interpclass_w(w_unroller)
-        if isinstance(unroller, pyframe.SuspendedUnroller):
-            # re-raise the unroller, if any
-            raise unroller.flowexc
-
-    def BUILD_CLASS(f):
+    def BUILD_CLASS(f, *ignored):
         w_methodsdict = f.valuestack.pop()
         w_bases       = f.valuestack.pop()
         w_name        = f.valuestack.pop()
@@ -415,12 +515,12 @@
                                            w_bases, w_methodsdict)
         f.valuestack.push(w_newclass)
 
-    def STORE_NAME(f, varindex):
+    def STORE_NAME(f, varindex, *ignored):
         w_varname = f.getname_w(varindex)
         w_newvalue = f.valuestack.pop()
         f.space.set_str_keyed_item(f.w_locals, w_varname, w_newvalue)
 
-    def DELETE_NAME(f, varindex):
+    def DELETE_NAME(f, varindex, *ignored):
         w_varname = f.getname_w(varindex)
         try:
             f.space.delitem(f.w_locals, w_varname)
@@ -431,7 +531,7 @@
             message = "name '%s' is not defined" % f.space.str_w(w_varname)
             raise OperationError(f.space.w_NameError, f.space.wrap(message))
 
-    def UNPACK_SEQUENCE(f, itemcount):
+    def UNPACK_SEQUENCE(f, itemcount, *ignored):
         w_iterable = f.valuestack.pop()
         try:
             items = f.space.unpackiterable(w_iterable, itemcount)
@@ -441,29 +541,29 @@
         for item in items:
             f.valuestack.push(item)
 
-    def STORE_ATTR(f, nameindex):
+    def STORE_ATTR(f, nameindex, *ignored):
         "obj.attributename = newvalue"
         w_attributename = f.getname_w(nameindex)
         w_obj = f.valuestack.pop()
         w_newvalue = f.valuestack.pop()
         f.space.setattr(w_obj, w_attributename, w_newvalue)
 
-    def DELETE_ATTR(f, nameindex):
+    def DELETE_ATTR(f, nameindex, *ignored):
         "del obj.attributename"
         w_attributename = f.getname_w(nameindex)
         w_obj = f.valuestack.pop()
         f.space.delattr(w_obj, w_attributename)
 
-    def STORE_GLOBAL(f, nameindex):
+    def STORE_GLOBAL(f, nameindex, *ignored):
         w_varname = f.getname_w(nameindex)
         w_newvalue = f.valuestack.pop()
         f.space.set_str_keyed_item(f.w_globals, w_varname, w_newvalue)
 
-    def DELETE_GLOBAL(f, nameindex):
+    def DELETE_GLOBAL(f, nameindex, *ignored):
         w_varname = f.getname_w(nameindex)
         f.space.delitem(f.w_globals, w_varname)
 
-    def LOAD_NAME(f, nameindex):
+    def LOAD_NAME(f, nameindex, *ignored):
         if f.w_locals is not f.w_globals:
             w_varname = f.getname_w(nameindex)
             w_value = f.space.finditem(f.w_locals, w_varname)
@@ -472,7 +572,7 @@
                 return
         f.LOAD_GLOBAL(nameindex)    # fall-back
 
-    def LOAD_GLOBAL(f, nameindex):
+    def LOAD_GLOBAL(f, nameindex, *ignored):
         w_varname = f.getname_w(nameindex)
         w_value = f.space.finditem(f.w_globals, w_varname)
         if w_value is None:
@@ -485,7 +585,7 @@
                                      f.space.wrap(message))
         f.valuestack.push(w_value)
 
-    def DELETE_FAST(f, varindex):
+    def DELETE_FAST(f, varindex, *ignored):
         if f.fastlocals_w[varindex] is None:
             varname = f.getlocalvarname(varindex)
             message = "local variable '%s' referenced before assignment" % varname
@@ -493,25 +593,25 @@
         f.fastlocals_w[varindex] = None
         
 
-    def BUILD_TUPLE(f, itemcount):
+    def BUILD_TUPLE(f, itemcount, *ignored):
         items = [f.valuestack.pop() for i in range(itemcount)]
         items.reverse()
         w_tuple = f.space.newtuple(items)
         f.valuestack.push(w_tuple)
 
-    def BUILD_LIST(f, itemcount):
+    def BUILD_LIST(f, itemcount, *ignored):
         items = [f.valuestack.pop() for i in range(itemcount)]
         items.reverse()
         w_list = f.space.newlist(items)
         f.valuestack.push(w_list)
 
-    def BUILD_MAP(f, zero):
+    def BUILD_MAP(f, zero, *ignored):
         if zero != 0:
-            raise pyframe.BytecodeCorruption
+            raise BytecodeCorruption
         w_dict = f.space.newdict()
         f.valuestack.push(w_dict)
 
-    def LOAD_ATTR(f, nameindex):
+    def LOAD_ATTR(f, nameindex, *ignored):
         "obj.attributename"
         w_attributename = f.getname_w(nameindex)
         w_obj = f.valuestack.pop()
@@ -549,17 +649,17 @@
         cmp_is_not,
         cmp_exc_match,
         ]
-    def COMPARE_OP(f, testnum):
+    def COMPARE_OP(f, testnum, *ignored):
         w_2 = f.valuestack.pop()
         w_1 = f.valuestack.pop()
         try:
             testfn = f.compare_dispatch_table[testnum]
         except IndexError:
-            raise pyframe.BytecodeCorruption, "bad COMPARE_OP oparg"
+            raise BytecodeCorruption, "bad COMPARE_OP oparg"
         w_result = testfn(f, w_1, w_2)
         f.valuestack.push(w_result)
 
-    def IMPORT_NAME(f, nameindex):
+    def IMPORT_NAME(f, nameindex, *ignored):
         space = f.space
         w_modulename = f.getname_w(nameindex)
         modulename = f.space.str_w(w_modulename)
@@ -575,13 +675,13 @@
                                     f.w_globals, w_locals, w_fromlist)
         f.valuestack.push(w_obj)
 
-    def IMPORT_STAR(f):
+    def IMPORT_STAR(f, *ignored):
         w_module = f.valuestack.pop()
         w_locals = f.getdictscope()
         import_all_from(f.space, w_module, w_locals)
         f.setdictscope(w_locals)
 
-    def IMPORT_FROM(f, nameindex):
+    def IMPORT_FROM(f, nameindex, *ignored):
         w_name = f.getname_w(nameindex)
         w_module = f.valuestack.top()
         try:
@@ -593,29 +693,31 @@
                              f.space.wrap("cannot import name '%s'" % f.space.str_w(w_name) ))
         f.valuestack.push(w_obj)
 
-    def JUMP_FORWARD(f, stepby):
-        f.next_instr += stepby
-    JUMP_FORWARD.can_jump = True
+    def JUMP_FORWARD(f, jumpby, next_instr, *ignored):
+        next_instr += jumpby
+        return next_instr
 
-    def JUMP_IF_FALSE(f, stepby):
+    def JUMP_IF_FALSE(f, stepby, next_instr, *ignored):
         w_cond = f.valuestack.top()
         if not f.space.is_true(w_cond):
-            f.next_instr += stepby
+            next_instr += stepby
+        return next_instr
 
-    def JUMP_IF_TRUE(f, stepby):
+    def JUMP_IF_TRUE(f, stepby, next_instr, *ignored):
         w_cond = f.valuestack.top()
         if f.space.is_true(w_cond):
-            f.next_instr += stepby
+            next_instr += stepby
+        return next_instr
 
-    def JUMP_ABSOLUTE(f, jumpto):
-        f.next_instr = jumpto
+    def JUMP_ABSOLUTE(f, jumpto, next_instr, *ignored):
+        return jumpto
 
-    def GET_ITER(f):
+    def GET_ITER(f, *ignored):
         w_iterable = f.valuestack.pop()
         w_iterator = f.space.iter(w_iterable)
         f.valuestack.push(w_iterator)
 
-    def FOR_ITER(f, jumpby):
+    def FOR_ITER(f, jumpby, next_instr, *ignored):
         w_iterator = f.valuestack.top()
         try:
             w_nextitem = f.space.next(w_iterator)
@@ -624,33 +726,33 @@
                 raise 
             # iterator exhausted
             f.valuestack.pop()
-            f.next_instr += jumpby
+            next_instr += jumpby
         else:
             f.valuestack.push(w_nextitem)
+        return next_instr
 
-    def FOR_LOOP(f, oparg):
-        raise pyframe.BytecodeCorruption, "old opcode, no longer in use"
+    def FOR_LOOP(f, oparg, *ignored):
+        raise BytecodeCorruption, "old opcode, no longer in use"
 
-    def SETUP_LOOP(f, offsettoend):
-        block = pyframe.LoopBlock(f, f.next_instr + offsettoend)
+    def SETUP_LOOP(f, offsettoend, next_instr, *ignored):
+        block = LoopBlock(f, next_instr + offsettoend)
         f.blockstack.push(block)
 
-    def SETUP_EXCEPT(f, offsettoend):
-        block = pyframe.ExceptBlock(f, f.next_instr + offsettoend)
+    def SETUP_EXCEPT(f, offsettoend, next_instr, *ignored):
+        block = ExceptBlock(f, next_instr + offsettoend)
         f.blockstack.push(block)
 
-    def SETUP_FINALLY(f, offsettoend):
-        block = pyframe.FinallyBlock(f, f.next_instr + offsettoend)
+    def SETUP_FINALLY(f, offsettoend, next_instr, *ignored):
+        block = FinallyBlock(f, next_instr + offsettoend)
         f.blockstack.push(block)
 
-    def WITH_CLEANUP(f):
+    def WITH_CLEANUP(f, *ignored):
         # see comment in END_FINALLY for stack state
         w_exitfunc = f.valuestack.pop()
         w_unroller = f.valuestack.top(2)
         unroller = f.space.interpclass_w(w_unroller)
-        if (isinstance(unroller, pyframe.SuspendedUnroller)
-            and isinstance(unroller.flowexc, pyframe.SApplicationException)):
-            operr = unroller.flowexc.operr
+        if isinstance(unroller, SApplicationException):
+            operr = unroller.operr
             w_result = f.space.call_function(w_exitfunc,
                                              operr.w_type,
                                              operr.w_value,
@@ -684,7 +786,7 @@
         rstack.resume_point("call_function", f, returns=w_result)
         f.valuestack.push(w_result)
         
-    def CALL_FUNCTION(f, oparg):
+    def CALL_FUNCTION(f, oparg, *ignored):
         # XXX start of hack for performance
         if (oparg >> 8) & 0xff == 0:
             # Only positional arguments
@@ -701,20 +803,20 @@
             # general case
             f.call_function(oparg)
 
-    def CALL_FUNCTION_VAR(f, oparg):
+    def CALL_FUNCTION_VAR(f, oparg, *ignored):
         w_varargs = f.valuestack.pop()
         f.call_function(oparg, w_varargs)
 
-    def CALL_FUNCTION_KW(f, oparg):
+    def CALL_FUNCTION_KW(f, oparg, *ignored):
         w_varkw = f.valuestack.pop()
         f.call_function(oparg, None, w_varkw)
 
-    def CALL_FUNCTION_VAR_KW(f, oparg):
+    def CALL_FUNCTION_VAR_KW(f, oparg, *ignored):
         w_varkw = f.valuestack.pop()
         w_varargs = f.valuestack.pop()
         f.call_function(oparg, w_varargs, w_varkw)
 
-    def MAKE_FUNCTION(f, numdefaults):
+    def MAKE_FUNCTION(f, numdefaults, *ignored):
         w_codeobj = f.valuestack.pop()
         codeobj = f.space.interp_w(PyCode, w_codeobj)
         defaultarguments = [f.valuestack.pop() for i in range(numdefaults)]
@@ -722,169 +824,244 @@
         fn = function.Function(f.space, codeobj, f.w_globals, defaultarguments)
         f.valuestack.push(f.space.wrap(fn))
 
-    def BUILD_SLICE(f, numargs):
+    def BUILD_SLICE(f, numargs, *ignored):
         if numargs == 3:
             w_step = f.valuestack.pop()
         elif numargs == 2:
             w_step = f.space.w_None
         else:
-            raise pyframe.BytecodeCorruption
+            raise BytecodeCorruption
         w_end   = f.valuestack.pop()
         w_start = f.valuestack.pop()
         w_slice = f.space.newslice(w_start, w_end, w_step)
         f.valuestack.push(w_slice)
 
-    def LIST_APPEND(f):
+    def LIST_APPEND(f, *ignored):
         w = f.valuestack.pop()
         v = f.valuestack.pop()
         f.space.call_method(v, 'append', w)
 
-    def SET_LINENO(f, lineno):
+    def SET_LINENO(f, lineno, *ignored):
         pass
 
-##     def EXTENDED_ARG(f, oparg):
+##     def EXTENDED_ARG(f, oparg, *ignored):
 ##         opcode = f.nextop()
 ##         oparg = oparg<<16 | f.nextarg()
 ##         fn = f.dispatch_table_w_arg[opcode]
 ##         if fn is None:
-##             raise pyframe.BytecodeCorruption
+##             raise BytecodeCorruption
 ##         fn(f, oparg)
 
-    def MISSING_OPCODE(f):
-        ofs = f.next_instr - 1
+    def MISSING_OPCODE(f, oparg, next_instr, *ignored):
+        ofs = next_instr - 1
         c = f.pycode.co_code[ofs]
         name = f.pycode.co_name
-        raise pyframe.BytecodeCorruption("unknown opcode, ofs=%d, code=%d, name=%s" %
-                                           (ofs, ord(c), name) )
-
-    def MISSING_OPCODE_W_ARG(f, oparg):
-        ofs = f.next_instr - 3
-        c = f.pycode.co_code[ofs]
-        name = f.pycode.co_name
-        raise pyframe.BytecodeCorruption("unknown opcode, ofs=%d, code=%d, name=%s" %
-                                           (ofs, ord(c), name) )
+        raise BytecodeCorruption("unknown opcode, ofs=%d, code=%d, name=%s" %
+                                 (ofs, ord(c), name) )
 
     STOP_CODE = MISSING_OPCODE
 
-    ### dispatch_table ###
-
-    # 'opcode_has_arg' is a class attribute: list of True/False whether opcode takes arg
-    # 'dispatch_table_no_arg: list of functions/None
-    # 'dispatch_table_w_arg: list of functions/None
-
-    __metaclass__ = InitializedClass
-    def __initclass__(cls):
-        "NOT_RPYTHON"
-        # create the 'cls.dispatch_table' attribute
-        opcode_has_arg = []
-        dispatch_table_no_arg = []
-        dispatch_table_w_arg = []
-        missing_opcode = cls.MISSING_OPCODE.im_func
-        missing_opcode_w_arg = cls.MISSING_OPCODE_W_ARG.im_func
-        for i in range(256):
-            opname = pythonopcode.opname[i].replace('+', '_')
-            fn = getattr(cls, opname, None)
-            fn = getattr(fn, 'im_func',fn)
-            has_arg = i >= pythonopcode.HAVE_ARGUMENT
-            #if fn is missing_opcode and not opname.startswith('<') and i>0:
-            #    import warnings
-            #    warnings.warn("* Warning, missing opcode %s" % opname)
-            opcode_has_arg.append(has_arg)
-            if has_arg:
-                fn = fn or missing_opcode_w_arg
-                dispatch_table_w_arg.append(fn)
-                dispatch_table_no_arg.append(None)
-            else:
-                fn = fn or missing_opcode
-                dispatch_table_no_arg.append(fn)
-                dispatch_table_w_arg.append(None)
-
-        cls.opcode_has_arg = opcode_has_arg
-        cls.dispatch_table_no_arg = dispatch_table_no_arg
-        cls.dispatch_table_w_arg = dispatch_table_w_arg
-
-        #XXX performance hack!
-        ### Create dispatch with a lot of if,elifs ###
-        ### (this gets optimized for translated pypy by the merge_if_blocks transformation) ###
-        if cls.__name__ != 'PyInterpFrame':
-            return
-        import py
-        
-        dispatch_code  = '''
-def dispatch_translated(self, code, ec):
-    hint(None, global_merge_point=True)
-    next_instr = hint(self.next_instr, promote=True)
-    while True:
-        hint(None, global_merge_point=True)
-        self.last_instr = intmask(next_instr)
-        #ec.bytecode_trace(self)            JJJ
-        #self.next_instr = self.last_instr  JJJ
-        opcode = ord(code[next_instr])
-        opcode = hint(opcode, concrete=True)
-        if self.space.config.objspace.logbytecodes:
-            self.space.bytecodecounts[opcode] = self.space.bytecodecounts.get(opcode, 0) + 1
-        next_instr += 1
-        self.next_instr = next_instr
-        if opcode >= %s:
-            oparg = ord(code[next_instr]) | ord(code[next_instr + 1]) << 8
-            oparg = hint(oparg, concrete=True)
-            next_instr += 2
-            self.next_instr = next_instr
-            while True:
-                if opcode == %s:
-                    opcode = ord(code[next_instr])
-                    opcode = hint(opcode, concrete=True)
-                    oparg = oparg << 16 | ord(code[next_instr + 1]) | ord(code[next_instr + 2]) << 8
-                    oparg = hint(oparg, concrete=True)
-                    next_instr += 3
-                    self.next_instr = next_instr
-                    if opcode < %s:
-                        raise pyframe.BytecodeCorruption
-                    continue
-''' % (pythonopcode.HAVE_ARGUMENT,
-        pythonopcode.EXTENDED_ARG,
-        pythonopcode.HAVE_ARGUMENT)
-
-        def sortkey(opcode, opcodeorder=opcodeorder, ValueError=ValueError):
-            try:
-                index = opcodeorder.index(opcode)
-            except ValueError:
-                index = 1000000
-            return index, opcode
-        opcases = [(sortkey(i), i, opname)
-                   for opname, i in pythonopcode.opmap.iteritems()]
-        opcases.sort()    # for predictable results
 
-        for _, i, opname in opcases:
-            if i == pythonopcode.EXTENDED_ARG or i < pythonopcode.HAVE_ARGUMENT:
-                continue
-            opname         = opname.replace('+', '_')
-            dispatch_code += '                elif opcode == %d:\n' % i
-            dispatch_code += '                    self.%s(oparg)\n'  % opname
-            if opname == 'CALL_FUNCTION':
-                dispatch_code += '                    rstack.resume_point("dispatch_call", self, code, ec)\n'
-        dispatch_code +=     '                else:\n'
-        dispatch_code +=     '                    self.MISSING_OPCODE_W_ARG(oparg)\n'
-        dispatch_code +=     '                break\n'
+### ____________________________________________________________ ###
 
-        for _, i, opname in opcases:
-            if i >= pythonopcode.HAVE_ARGUMENT:
-                continue
-            opname         = opname.replace('+', '_')
-            dispatch_code += '        elif opcode == %d:\n' % i
-            dispatch_code += '            self.%s()\n'  % opname
-        dispatch_code +=     '        else:\n'
-        dispatch_code +=     '            self.MISSING_OPCODE()\n'
-        exec py.code.Source(dispatch_code).compile()
 
-        cls.dispatch_translated = dispatch_translated        
-    
+def cpython_tb():
+   """NOT_RPYTHON"""
+   import sys
+   return sys.exc_info()[2]   
+cpython_tb._annspecialcase_ = "override:ignore"
+
+class Reraise(Exception):
+    """Signal an application-level OperationError that should not grow
+    a new traceback entry nor trigger the trace hook."""
+
+class BytecodeCorruption(Exception):
+    """Detected bytecode corruption.  Never caught; it's an error."""
+
+
+### Frame Blocks ###
+
+class SuspendedUnroller(Wrappable):
+    """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")
+    # for the flow object space, a way to "pickle" and "unpickle" the
+    # ControlFlowException by enumerating the Variables it contains.
+    def state_unpack_variables(self, space):
+        return []     # by default, overridden below
+    def state_pack_variables(self, space, *values_w):
+        assert len(values_w) == 0
+
+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]
+    def state_pack_variables(self, space, w_returnvalue):
+        self.w_returnvalue = 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]
+    def state_pack_variables(self, space, w_type, w_value):
+        self.operr = OperationError(w_type, w_value)
+
+class SBreakLoop(SuspendedUnroller):
+    """Signals a 'break' statement."""
+    kind = 0x04
+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)]
+    def state_pack_variables(self, space, w_jump_to):
+        self.jump_to = space.int_w(w_jump_to)
+
+
+class FrameBlock:
+
+    """Abstract base class for frame blocks from the blockstack,
+    used by the SETUP_XXX and POP_BLOCK opcodes."""
+
+    def __init__(self, frame, handlerposition):
+        self.handlerposition = handlerposition
+        self.valuestackdepth = frame.valuestack.depth()
+
+    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):
+        for i in range(self.valuestackdepth, frame.valuestack.depth()):
+            frame.valuestack.pop()
+
+    def cleanup(self, frame):
+        "Clean up a frame when we normally exit the block."
+        self.cleanupstack(frame)
+
+    # internal pickling interface, not using the standard protocol
+    def _get_state_(self, space):
+        w = space.wrap
+        return space.newtuple([w(self._opname), w(self.handlerposition),
+                               w(self.valuestackdepth)])
+
+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.blockstack.push(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
+        if frame.space.full_exceptions:
+            operationerr.normalize_exception(frame.space)
+        # the stack setup is slightly different than in CPython:
+        # instead of the traceback, we store the unroller object,
+        # wrapped.
+        frame.valuestack.push(frame.space.wrap(unroller))
+        frame.valuestack.push(operationerr.w_value)
+        frame.valuestack.push(operationerr.w_type)
+        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 cleanup(self, frame):
+        # upon normal entry into the finally: part, the standard Python
+        # bytecode pushes a single None for END_FINALLY.  In our case we
+        # always push three values into the stack: the wrapped ctlflowexc,
+        # the exception value and the exception type (which are all None
+        # here).
+        self.cleanupstack(frame)
+        # one None already pushed by the bytecode
+        frame.valuestack.push(frame.space.w_None)
+        frame.valuestack.push(frame.space.w_None)
+
+    def handle(self, frame, unroller):
+        # any abnormal reason for unrolling a finally: triggers the end of
+        # the block unrolling and the entering the finally: handler.
+        # see comments in cleanup().
+        self.cleanupstack(frame)
+        frame.valuestack.push(frame.space.wrap(unroller))
+        frame.valuestack.push(frame.space.w_None)
+        frame.valuestack.push(frame.space.w_None)
+        return self.handlerposition   # jump to the handler
+
+
+block_classes = {'SETUP_LOOP': LoopBlock,
+                 'SETUP_EXCEPT': ExceptBlock,
+                 'SETUP_FINALLY': FinallyBlock}
 
 ### helpers written at the application-level ###
 # Some of these functions are expected to be generally useful if other
 # parts of the code need to do the same thing as a non-trivial opcode,
 # like finding out which metaclass a new class should have.
-# This is why they are not methods of PyInterpFrame.
+# This is why they are not methods of PyFrame.
 # There are also a couple of helpers that are methods, defined in the
 # class above.
 

Modified: pypy/branch/jit-real-world/pypy/interpreter/test/test_interpreter.py
==============================================================================
--- pypy/branch/jit-real-world/pypy/interpreter/test/test_interpreter.py	(original)
+++ pypy/branch/jit-real-world/pypy/interpreter/test/test_interpreter.py	Fri Dec  1 03:43:34 2006
@@ -150,7 +150,7 @@
                           1+2+3 + 5+6+7+8+900)
 
     def test_import(self):
-        # Regression test for a bug in PyInterpFrame.IMPORT_NAME: when an
+        # Regression test for a bug in PyFrame.IMPORT_NAME: when an
         # import statement was executed in a function without a locals dict, a
         # plain unwrapped None could be passed into space.call_function causing
         # assertion errors later on.

Modified: pypy/branch/jit-real-world/pypy/interpreter/test/test_pyframe.py
==============================================================================
--- pypy/branch/jit-real-world/pypy/interpreter/test/test_pyframe.py	(original)
+++ pypy/branch/jit-real-world/pypy/interpreter/test/test_pyframe.py	Fri Dec  1 03:43:34 2006
@@ -94,6 +94,53 @@
         assert len(l) == 1
         assert isinstance(l[0][1], Exception)
 
+    def test_dont_trace_on_reraise(self):
+        import sys
+        l = []
+        def ltrace(a,b,c): 
+            if b == 'exception':
+                l.append(c)
+            return ltrace
+        def trace(a,b,c): return ltrace
+        def f():
+            try:
+                1/0
+            except:
+                try:
+                    raise
+                except:
+                    pass
+        sys.settrace(trace)
+        f()
+        sys.settrace(None)
+        assert len(l) == 1
+        assert issubclass(l[0][0], Exception)
+
+    def test_dont_trace_on_raise_with_tb(self):
+        import sys
+        l = []
+        def ltrace(a,b,c): 
+            if b == 'exception':
+                l.append(c)
+            return ltrace
+        def trace(a,b,c): return ltrace
+        def f():
+            try:
+                raise Exception
+            except:
+                return sys.exc_info()
+        def g():
+            exc, val, tb = f()
+            try:
+                raise exc, val, tb
+            except:
+                pass
+        sys.settrace(trace)
+        g()
+        sys.settrace(None)
+        assert len(l) == 1
+        assert isinstance(l[0][1], Exception)
+
     def test_trace_changes_locals(self):
         import sys
         def trace(frame, what, arg):

Modified: pypy/branch/jit-real-world/pypy/interpreter/typedef.py
==============================================================================
--- pypy/branch/jit-real-world/pypy/interpreter/typedef.py	(original)
+++ pypy/branch/jit-real-world/pypy/interpreter/typedef.py	Fri Dec  1 03:43:34 2006
@@ -442,7 +442,8 @@
 
 from pypy.interpreter.eval import Code, Frame
 from pypy.interpreter.pycode import PyCode, CO_VARARGS, CO_VARKEYWORDS
-from pypy.interpreter.pyframe import PyFrame, ControlFlowException
+from pypy.interpreter.pyframe import PyFrame
+from pypy.interpreter.pyopcode import SuspendedUnroller
 from pypy.interpreter.module import Module
 from pypy.interpreter.function import Function, Method, StaticMethod
 from pypy.interpreter.function import BuiltinFunction, descr_function_get
@@ -696,7 +697,7 @@
     __repr__   = interp2app(NotImplemented.descr__repr__),
 )
 
-ControlFlowException.typedef = TypeDef("ControlFlowException")
+SuspendedUnroller.typedef = TypeDef("SuspendedUnroller")
 
 
 interptypes = [ val.typedef for name,val in globals().items() if hasattr(val,'__bases__') and hasattr(val,'typedef')  ]

Modified: pypy/branch/jit-real-world/pypy/module/_pickle_support/maker.py
==============================================================================
--- pypy/branch/jit-real-world/pypy/module/_pickle_support/maker.py	(original)
+++ pypy/branch/jit-real-world/pypy/module/_pickle_support/maker.py	Fri Dec  1 03:43:34 2006
@@ -61,11 +61,7 @@
     w_pycode, = args_w
     pycode = space.interp_w(PyCode, w_pycode)
     w = space.wrap
-
-    # let the code object create the right kind of frame
-    # the distinction is a little over-done but computable
-    Klass = pycode.get_frame_class()
-    new_frame = instantiate(Klass)
+    new_frame = instantiate(PyFrame)
     return space.wrap(new_frame)
 frame_new.unwrap_spec = [ObjSpace, Arguments]
 
@@ -76,13 +72,11 @@
 
 def generator_new(space, __args__):
     args_w, kwds_w = __args__.unpack()  #stolen from std/fake.py
-    w_frame, w_running, w_exhausted = args_w
+    w_frame, w_running = args_w
     frame = space.interp_w(PyFrame, w_frame)
     running = space.int_w(w_running)
-    exhausted = space.int_w(w_exhausted)
     new_generator = GeneratorIterator(frame)
     new_generator.running = running
-    new_generator.exhausted = exhausted
     return space.wrap(new_generator)
 generator_new.unwrap_spec = [ObjSpace, Arguments]
 

Modified: pypy/branch/jit-real-world/pypy/objspace/flow/flowcontext.py
==============================================================================
--- pypy/branch/jit-real-world/pypy/objspace/flow/flowcontext.py	(original)
+++ pypy/branch/jit-real-world/pypy/objspace/flow/flowcontext.py	Fri Dec  1 03:43:34 2006
@@ -95,7 +95,7 @@
 
     def bytecode_trace(self, ec, frame):
         assert frame is ec.crnt_frame, "seeing an unexpected frame!"
-        ec.crnt_offset = frame.next_instr      # save offset for opcode
+        ec.crnt_offset = frame.last_instr      # save offset for opcode
         if self.enterspamblock:
             # If we have a SpamBlock, the first call to bytecode_trace()
             # occurs as soon as frame.resume() starts, before interpretation
@@ -218,8 +218,10 @@
         # create an empty frame suitable for the code object
         # while ignoring any operation like the creation of the locals dict
         self.recorder = []
-        return self.code.create_frame(self.space, self.w_globals,
-                                      self.closure)
+        frame = self.code.create_frame(self.space, self.w_globals,
+                                       self.closure)
+        frame.last_instr = 0
+        return frame
 
     def bytecode_trace(self, frame):
         self.recorder.bytecode_trace(self, frame)
@@ -256,11 +258,15 @@
             except StopFlowing:
                 continue   # restarting a dead SpamBlock
             try:
+                self.framestack.push(frame)
                 self.crnt_frame = frame
                 try:
-                    w_result = frame.resume()
+                    w_result = frame.dispatch(frame.pycode.co_code,
+                                              frame.last_instr,
+                                              self)
                 finally:
                     self.crnt_frame = None
+                    self.framestack.pop()
 
             except OperationThatShouldNotBePropagatedError, e:
                 raise Exception(

Modified: pypy/branch/jit-real-world/pypy/objspace/flow/framestate.py
==============================================================================
--- pypy/branch/jit-real-world/pypy/objspace/flow/framestate.py	(original)
+++ pypy/branch/jit-real-world/pypy/objspace/flow/framestate.py	Fri Dec  1 03:43:34 2006
@@ -1,4 +1,5 @@
-from pypy.interpreter.pyframe import PyFrame, SuspendedUnroller
+from pypy.interpreter.pyframe import PyFrame
+from pypy.interpreter.pyopcode import SuspendedUnroller
 from pypy.interpreter.error import OperationError
 from pypy.rlib.objectmodel import instantiate
 from pypy.rlib.unroll import SpecTag
@@ -21,7 +22,7 @@
             self.mergeable = data
             self.nonmergeable = (
                 state.blockstack.items[:],
-                state.next_instr,
+                state.last_instr,   # == next_instr when between bytecodes
                 state.w_locals,
             )
         elif isinstance(state, tuple):
@@ -48,7 +49,7 @@
                 frame.last_exception = OperationError(data[-2], data[-1])
             (
                 frame.blockstack.items[:],
-                frame.next_instr,
+                frame.last_instr,
                 frame.w_locals,
             ) = self.nonmergeable
         else:
@@ -157,9 +158,9 @@
                 isinstance(item.value, SuspendedUnroller)):
             i += 1
         else:
-            flowexc = item.value.flowexc
-            vars = flowexc.state_unpack_variables(space)
-            key = flowexc.__class__, len(vars)
+            unroller = item.value
+            vars = unroller.state_unpack_variables(space)
+            key = unroller.__class__, len(vars)
             try:
                 tag = PICKLE_TAGS[key]
             except:
@@ -171,9 +172,9 @@
     for i in range(len(lst)-1, -1, -1):
         item = lst[i]
         if item in UNPICKLE_TAGS:
-            flowexcclass, argcount = UNPICKLE_TAGS[item]
+            unrollerclass, argcount = UNPICKLE_TAGS[item]
             arguments = lst[i+1: i+1+argcount]
             del lst[i+1: i+1+argcount]
-            flowexc = instantiate(flowexcclass)
-            flowexc.state_pack_variables(space, *arguments)
-            lst[i] = flowexc.wrap(space)
+            unroller = instantiate(unrollerclass)
+            unroller.state_pack_variables(space, *arguments)
+            lst[i] = space.wrap(unroller)

Modified: pypy/branch/jit-real-world/pypy/tool/stdlib_opcode.py
==============================================================================
--- pypy/branch/jit-real-world/pypy/tool/stdlib_opcode.py	(original)
+++ pypy/branch/jit-real-world/pypy/tool/stdlib_opcode.py	Fri Dec  1 03:43:34 2006
@@ -1,9 +1,76 @@
 # load opcode.py as pythonopcode from our own lib
-# This should handle missing local copy
+
+__all__ = ['opmap', 'opname', 'HAVE_ARGUMENT',
+           'hasjrel', 'hasjabs', 'cmp_op']
+
 def load_opcode():
     import py
     opcode_path = py.path.local(__file__).dirpath().dirpath().dirpath('lib-python/modified-2.4.1/opcode.py')
-    execfile(str(opcode_path), globals())
+    d = {}
+    execfile(str(opcode_path), d)
+    return d
 
-load_opcode()
+opcode_dict = load_opcode()
 del load_opcode
+
+# copy some stuff from opcode.py directly into our globals
+for name in __all__:
+    if name in opcode_dict:
+        globals()[name] = opcode_dict[name]
+
+opcode_method_names = ['MISSING_OPCODE'] * 256
+for name, index in opmap.items():
+    opcode_method_names[index] = name.replace('+', '_')
+
+# ____________________________________________________________
+# RPython-friendly helpers and structures
+
+from pypy.rlib.unroll import unrolling_iterable
+
+
+class OpcodeDesc(object):
+    def __init__(self, name, index):
+        self.name = name
+        self.methodname = opcode_method_names[index]
+        self.index = index
+        self.hasarg = index >= HAVE_ARGUMENT
+
+    def _freeze_(self):
+        return True
+
+    def is_enabled(self, space):
+        """Check if the opcode should be enabled in the space's configuration.
+        (Returns True for all standard opcodes.)"""
+        opt = space.config.objspace.opcodes
+        return getattr(opt, self.name, True)
+    is_enabled._annspecialcase_ = 'specialize:memo'
+
+    # for predictable results, we try to order opcodes most-used-first
+    opcodeorder = [124, 125, 100, 105, 1, 131, 116, 111, 106, 83, 23, 93, 113, 25, 95, 64, 112, 66, 102, 110, 60, 92, 62, 120, 68, 87, 32, 136, 4, 103, 24, 63, 18, 65, 15, 55, 121, 3, 101, 22, 12, 80, 86, 135, 126, 90, 140, 104, 2, 33, 20, 108, 107, 31, 134, 132, 88, 30, 133, 130, 137, 141, 61, 122, 11, 40, 74, 73, 51, 96, 21, 42, 56, 85, 82, 89, 142, 77, 78, 79, 91, 76, 97, 57, 19, 43, 84, 50, 41, 99, 53, 26]
+
+    def sortkey(self):
+        try:
+            i = self.opcodeorder.index(self.index)
+        except ValueError:
+            i = 1000000
+        return i, self.index
+
+    def __cmp__(self, other):
+        return cmp(self.sortkey(), other.sortkey())
+
+
+opdescmap = {}
+
+class opcodedesc:
+    """A namespace mapping OPCODE_NAME to OpcodeDescs."""
+
+for name, index in opmap.items():
+    desc = OpcodeDesc(name, index)
+    setattr(opcodedesc, name, desc)
+    opdescmap[index] = desc
+
+lst = opdescmap.values()
+lst.sort()
+unrolling_opcode_descs = unrolling_iterable(lst)
+
+del name, index, desc, lst


More information about the pypy-svn mailing list