[pypy-commit] pypy default: merge heads

arigo noreply at buildbot.pypy.org
Tue Oct 16 16:15:23 CEST 2012


Author: Armin Rigo <arigo at tunes.org>
Branch: 
Changeset: r58138:b9b11f265aff
Date: 2012-10-16 16:14 +0200
http://bitbucket.org/pypy/pypy/changeset/b9b11f265aff/

Log:	merge heads

diff too long, truncating to 2000 out of 14821 lines

diff --git a/pypy/module/micronumpy/interp_numarray.py b/pypy/module/micronumpy/interp_numarray.py
--- a/pypy/module/micronumpy/interp_numarray.py
+++ b/pypy/module/micronumpy/interp_numarray.py
@@ -661,7 +661,7 @@
             raise operationerrfmt(space.w_ValueError, "Unknown order: %s",
                                   order)
     if isinstance(w_object, W_NDimArray):
-        if (not space.is_w(w_dtype, space.w_None) and
+        if (not space.is_none(w_dtype) and
             w_object.get_dtype() is not w_dtype):
             raise OperationError(space.w_NotImplementedError, space.wrap(
                                   "copying over different dtypes unsupported"))
diff --git a/pypy/module/micronumpy/loop.py b/pypy/module/micronumpy/loop.py
--- a/pypy/module/micronumpy/loop.py
+++ b/pypy/module/micronumpy/loop.py
@@ -424,39 +424,44 @@
             self._done = True
 
     @jit.unroll_safe
-    def get_index(self, space):
-        return [space.wrap(i) for i in self.indexes]
+    def get_index(self, space, shapelen):
+        return [space.wrap(self.indexes[i]) for i in range(shapelen)]
 
 getitem_int_driver = jit.JitDriver(name = 'numpy_getitem_int',
-                                   greens = ['shapelen', 'indexlen', 'dtype'],
+                                   greens = ['shapelen', 'indexlen',
+                                             'prefixlen', 'dtype'],
                                    reds = ['arr', 'res', 'iter', 'indexes_w',
                                            'prefix_w'])
 
 def getitem_array_int(space, arr, res, iter_shape, indexes_w, prefix_w):
     shapelen = len(iter_shape)
+    prefixlen = len(prefix_w)
     indexlen = len(indexes_w)
     dtype = arr.get_dtype()
     iter = PureShapeIterator(iter_shape, indexes_w)
+    indexlen = len(indexes_w)
     while not iter.done():
         getitem_int_driver.jit_merge_point(shapelen=shapelen, indexlen=indexlen,
                                            dtype=dtype, arr=arr, res=res,
                                            iter=iter, indexes_w=indexes_w,
-                                           prefix_w=prefix_w)
+                                           prefix_w=prefix_w,
+                                           prefixlen=prefixlen)
         # prepare the index
-        index_w = [None] * len(indexes_w)
-        for i in range(len(indexes_w)):
+        index_w = [None] * indexlen
+        for i in range(indexlen):
             if iter.idx_w[i] is not None:
                 index_w[i] = iter.idx_w[i].getitem()
             else:
                 index_w[i] = indexes_w[i]
-        res.descr_setitem(space, space.newtuple(prefix_w +
-                                                iter.get_index(space)),
+        res.descr_setitem(space, space.newtuple(prefix_w[:prefixlen] +
+                                            iter.get_index(space, shapelen)),
                           arr.descr_getitem(space, space.newtuple(index_w)))
         iter.next()
     return res
 
 setitem_int_driver = jit.JitDriver(name = 'numpy_setitem_int',
-                                   greens = ['shapelen', 'indexlen', 'dtype'],
+                                   greens = ['shapelen', 'indexlen',
+                                             'prefixlen', 'dtype'],
                                    reds = ['arr', 'iter', 'indexes_w',
                                            'prefix_w', 'val_arr'])
 
@@ -464,21 +469,24 @@
                       prefix_w):
     shapelen = len(iter_shape)
     indexlen = len(indexes_w)
+    prefixlen = len(prefix_w)
     dtype = arr.get_dtype()
     iter = PureShapeIterator(iter_shape, indexes_w)
     while not iter.done():
         setitem_int_driver.jit_merge_point(shapelen=shapelen, indexlen=indexlen,
                                            dtype=dtype, arr=arr,
                                            iter=iter, indexes_w=indexes_w,
-                                           prefix_w=prefix_w, val_arr=val_arr)
+                                           prefix_w=prefix_w, val_arr=val_arr,
+                                           prefixlen=prefixlen)
         # prepare the index
-        index_w = [None] * len(indexes_w)
-        for i in range(len(indexes_w)):
+        index_w = [None] * indexlen
+        for i in range(indexlen):
             if iter.idx_w[i] is not None:
                 index_w[i] = iter.idx_w[i].getitem()
             else:
                 index_w[i] = indexes_w[i]
-        w_idx = space.newtuple(prefix_w + iter.get_index(space))
+        w_idx = space.newtuple(prefix_w[:prefixlen] + iter.get_index(space,
+                                                                  shapelen))
         arr.descr_setitem(space, space.newtuple(index_w),
                           val_arr.descr_getitem(space, w_idx))
         iter.next()
diff --git a/pypy/module/oracle/interp_cursor.py b/pypy/module/oracle/interp_cursor.py
--- a/pypy/module/oracle/interp_cursor.py
+++ b/pypy/module/oracle/interp_cursor.py
@@ -1,5 +1,4 @@
 from pypy.interpreter.baseobjspace import Wrappable
-from pypy.interpreter.gateway import NoneNotWrapped
 from pypy.interpreter.typedef import TypeDef, GetSetProperty
 from pypy.interpreter.typedef import interp_attrproperty, interp_attrproperty_w
 from pypy.interpreter.gateway import interp2app, unwrap_spec
diff --git a/pypy/objspace/flow/bytecode.py b/pypy/objspace/flow/bytecode.py
--- a/pypy/objspace/flow/bytecode.py
+++ b/pypy/objspace/flow/bytecode.py
@@ -1,24 +1,22 @@
 """
 Bytecode handling classes and functions for use by the flow space.
 """
-from pypy.interpreter.pycode import (PyCode, BytecodeCorruption, cpython_magic,
+from pypy.interpreter.pycode import (BytecodeCorruption,
         cpython_code_signature)
 from pypy.tool.stdlib_opcode import (host_bytecode_spec, EXTENDED_ARG,
         HAVE_ARGUMENT)
 from pypy.interpreter.astcompiler.consts import CO_GENERATOR
 
-class HostCode(PyCode):
+class HostCode(object):
     """
     A wrapper around a native code object of the host interpreter
     """
     opnames = host_bytecode_spec.method_names
 
-    def __init__(self, space,  argcount, nlocals, stacksize, flags,
+    def __init__(self, argcount, nlocals, stacksize, flags,
                      code, consts, names, varnames, filename,
-                     name, firstlineno, lnotab, freevars, cellvars,
-                     hidden_applevel=False, magic=cpython_magic):
+                     name, firstlineno, lnotab, freevars):
         """Initialize a new code object"""
-        self.space = space
         self.co_name = name
         assert nlocals >= 0
         self.co_argcount = argcount
@@ -26,43 +24,39 @@
         self.co_stacksize = stacksize
         self.co_flags = flags
         self.co_code = code
-        self.co_consts_w = consts
-        self.co_names_w = [space.wrap(aname) for aname in names]
+        self.consts = consts
+        self.names = names
         self.co_varnames = varnames
         self.co_freevars = freevars
-        self.co_cellvars = cellvars
         self.co_filename = filename
         self.co_name = name
         self.co_firstlineno = firstlineno
         self.co_lnotab = lnotab
-        self.hidden_applevel = hidden_applevel
-        self.magic = magic
-        self._signature = cpython_code_signature(self)
-        self._initialize()
+        self.signature = cpython_code_signature(self)
 
-    def _initialize(self):
-        # Precompute what arguments need to be copied into cellvars
-        self._args_as_cellvars = []
+    @classmethod
+    def _from_code(cls, code):
+        """Initialize the code object from a real (CPython) one.
+        """
+        return cls(code.co_argcount,
+                      code.co_nlocals,
+                      code.co_stacksize,
+                      code.co_flags,
+                      code.co_code,
+                      list(code.co_consts),
+                      list(code.co_names),
+                      list(code.co_varnames),
+                      code.co_filename,
+                      code.co_name,
+                      code.co_firstlineno,
+                      code.co_lnotab,
+                      list(code.co_freevars))
 
-        if self.co_cellvars:
-            argcount = self.co_argcount
-            assert argcount >= 0     # annotator hint
-            if self.co_flags & CO_VARARGS:
-                argcount += 1
-            if self.co_flags & CO_VARKEYWORDS:
-                argcount += 1
-            # Cell vars could shadow already-set arguments.
-            # See comment in PyCode._initialize()
-            argvars  = self.co_varnames
-            cellvars = self.co_cellvars
-            for i in range(len(cellvars)):
-                cellname = cellvars[i]
-                for j in range(argcount):
-                    if cellname == argvars[j]:
-                        # argument j has the same name as the cell var i
-                        while len(self._args_as_cellvars) <= i:
-                            self._args_as_cellvars.append(-1)   # pad
-                        self._args_as_cellvars[i] = j
+    @property
+    def formalargcount(self):
+        """Total number of arguments passed into the frame, including *vararg
+        and **varkwarg, if they exist."""
+        return self.signature.scope_length()
 
     def read(self, pos):
         """
diff --git a/pypy/objspace/flow/flowcontext.py b/pypy/objspace/flow/flowcontext.py
--- a/pypy/objspace/flow/flowcontext.py
+++ b/pypy/objspace/flow/flowcontext.py
@@ -1,15 +1,18 @@
+"""Implements the core parts of flow graph creation, in tandem
+with pypy.objspace.flow.objspace.
+"""
+
+import sys
 import collections
+
 from pypy.tool.error import source_lines
 from pypy.interpreter import pyframe
-from pypy.interpreter.nestedscope import Cell
-from pypy.interpreter.pycode import CO_NEWLOCALS
 from pypy.interpreter.argument import ArgumentsForTranslation
 from pypy.interpreter.pyopcode import Return, BytecodeCorruption
 from pypy.objspace.flow.model import (Constant, Variable, Block, Link,
-    UnwrapException, SpaceOperation, FunctionGraph, c_last_exception)
+    UnwrapException, c_last_exception)
 from pypy.objspace.flow.framestate import (FrameState, recursively_unflatten,
         recursively_flatten)
-from pypy.objspace.flow.bytecode import HostCode
 from pypy.objspace.flow.specialcase import (rpython_print_item,
         rpython_print_newline)
 
@@ -67,6 +70,14 @@
         self.last_exception = last_exception
 
 def fixeggblocks(graph):
+    varnames = graph.func.func_code.co_varnames
+    for block in graph.iterblocks():
+        if isinstance(block, SpamBlock):
+            for name, w_value in zip(varnames, block.framestate.mergeable):
+                if isinstance(w_value, Variable):
+                    w_value.rename(name)
+            del block.framestate     # memory saver
+
     # EggBlocks reuse the variables of their previous block,
     # which is deemed not acceptable for simplicity of the operations
     # that will be performed later on the flow graph.
@@ -87,9 +98,6 @@
                 for a in block.inputargs:
                     mapping[a] = Variable(a)
                 block.renamevariables(mapping)
-    for block in graph.iterblocks():
-        if isinstance(link, SpamBlock):
-            del link.framestate     # memory saver
 
 # ____________________________________________________________
 
@@ -98,9 +106,6 @@
     def append(self, operation):
         raise NotImplementedError
 
-    def bytecode_trace(self, frame):
-        pass
-
     def guessbool(self, frame, w_condition, **kwds):
         raise AssertionError, "cannot guessbool(%s)" % (w_condition,)
 
@@ -110,31 +115,13 @@
 
     def __init__(self, block):
         self.crnt_block = block
-        # saved state at the join point most recently seen
-        self.last_join_point = None
-        self.enterspamblock = isinstance(block, SpamBlock)
+        # Final frame state after the operations in the block
+        # If this is set, no new space op may be recorded.
+        self.final_state = None
 
     def append(self, operation):
         self.crnt_block.operations.append(operation)
 
-    def bytecode_trace(self, frame):
-        if self.enterspamblock:
-            # If we have a SpamBlock, the first call to bytecode_trace()
-            # occurs as soon as frame.resume() starts, before interpretation
-            # really begins.
-            varnames = frame.pycode.getvarnames()
-            for name, w_value in zip(varnames, frame.getfastscope()):
-                if isinstance(w_value, Variable):
-                    w_value.rename(name)
-            self.enterspamblock = False
-        else:
-            # At this point, we progress to the next bytecode.  When this
-            # occurs, we no longer allow any more operations to be recorded in
-            # the same block.  We will continue, to figure out where the next
-            # such operation *would* appear, and we make a join point just
-            # before.
-            self.last_join_point = frame.getstate()
-
     def guessbool(self, frame, w_condition):
         block = self.crnt_block
         vars = block.getvariables()
@@ -235,69 +222,45 @@
 
 class FlowSpaceFrame(pyframe.CPythonFrame):
 
-    def __init__(self, space, func, constargs=None):
-        code = HostCode._from_code(space, func.func_code)
+    def __init__(self, space, graph, code):
+        self.graph = graph
+        func = graph.func
         self.pycode = code
         self.space = space
         self.w_globals = Constant(func.func_globals)
-        self.locals_stack_w = [None] * (code.co_nlocals + code.co_stacksize)
-        self.valuestackdepth = code.co_nlocals
         self.lastblock = None
 
-        if func.func_closure is not None:
-            cl = [c.cell_contents for c in func.func_closure]
-            closure = [Cell(Constant(value)) for value in cl]
-        else:
-            closure = []
-        self.initialize_frame_scopes(closure, code)
+        self.init_closure(func.func_closure)
         self.f_lineno = code.co_firstlineno
         self.last_instr = 0
 
-        if constargs is None:
-            constargs = {}
-        formalargcount = code.getformalargcount()
-        arg_list = [Variable() for i in range(formalargcount)]
-        for position, value in constargs.items():
-            arg_list[position] = Constant(value)
-        self.setfastscope(arg_list)
-
+        self.init_locals_stack(code)
         self.w_locals = None # XXX: only for compatibility with PyFrame
 
         self.joinpoints = {}
-        self._init_graph(func)
-        self.pendingblocks = collections.deque([self.graph.startblock])
 
-    def initialize_frame_scopes(self, closure, code):
-        if not (code.co_flags & CO_NEWLOCALS):
-            raise ValueError("The code object for a function should have "
-                    "the flag CO_NEWLOCALS set.")
-        if len(closure) != len(code.co_freevars):
-            raise ValueError("code object received a closure with "
-                                 "an unexpected number of free variables")
-        self.cells = [Cell() for _ in code.co_cellvars] + closure
+    def init_closure(self, closure):
+        if closure is None:
+            self.closure = []
+        else:
+            self.closure = [self.space.wrap(c.cell_contents) for c in closure]
+        assert len(self.closure) == len(self.pycode.co_freevars)
 
-    def _init_graph(self, func):
-        # CallableFactory.pycall may add class_ to functions that are methods
-        name = func.func_name
-        class_ = getattr(func, 'class_', None)
-        if class_ is not None:
-            name = '%s.%s' % (class_.__name__, name)
-        for c in "<>&!":
-            name = name.replace(c, '_')
+    def init_locals_stack(self, code):
+        """
+        Initialize the locals and the stack.
 
-        initialblock = SpamBlock(self.getstate())
-        if self.pycode.is_generator:
-            initialblock.operations.append(
-                SpaceOperation('generator_mark', [], Variable()))
-        graph = FunctionGraph(name, initialblock)
-        graph.func = func
-        # attach a signature and defaults to the graph
-        # so that it becomes even more interchangeable with the function
-        # itself
-        graph.signature = self.pycode.signature()
-        graph.defaults = func.func_defaults or ()
-        graph.is_generator = self.pycode.is_generator
-        self.graph = graph
+        The locals are ordered according to self.pycode.signature.
+        """
+        self.valuestackdepth = code.co_nlocals
+        self.locals_stack_w = [None] * (code.co_stacksize + code.co_nlocals)
+
+    def save_locals_stack(self):
+        return self.locals_stack_w[:self.valuestackdepth]
+
+    def restore_locals_stack(self, items_w):
+        self.locals_stack_w[:len(items_w)] = items_w
+        self.dropvaluesuntil(len(items_w))
 
     def getstate(self):
         # getfastscope() can return real None, for undefined locals
@@ -309,9 +272,7 @@
             data.append(self.last_exception.w_type)
             data.append(self.last_exception.w_value)
         recursively_flatten(self.space, data)
-        nonmergeable = (self.get_blocklist(),
-            self.last_instr)   # == next_instr when between bytecodes
-        return FrameState(data, nonmergeable)
+        return FrameState(data, self.get_blocklist(), self.last_instr)
 
     def setstate(self, state):
         """ Reset the frame to the given state. """
@@ -323,8 +284,8 @@
             self.last_exception = None
         else:
             self.last_exception = FSException(data[-2], data[-1])
-        blocklist, self.last_instr = state.nonmergeable
-        self.set_blocklist(blocklist)
+        self.last_instr = state.next_instr
+        self.set_blocklist(state.blocklist)
 
     def recording(self, block):
         """ Setup recording of the block and return the recorder. """
@@ -347,8 +308,8 @@
     def record(self, spaceop):
         """Record an operation into the active block"""
         recorder = self.recorder
-        if getattr(recorder, 'last_join_point', None) is not None:
-            self.mergeblock(recorder.crnt_block, recorder.last_join_point)
+        if getattr(recorder, 'final_state', None) is not None:
+            self.mergeblock(recorder.crnt_block, recorder.final_state)
             raise StopFlowing
         recorder.append(spaceop)
 
@@ -369,14 +330,16 @@
         return self.recorder.guessexception(self, *exceptions)
 
     def build_flow(self):
+        graph = self.graph
+        self.pendingblocks = collections.deque([graph.startblock])
         while self.pendingblocks:
             block = self.pendingblocks.popleft()
             try:
                 self.recorder = self.recording(block)
                 self.frame_finished_execution = False
-                next_instr = self.last_instr
                 while True:
-                    next_instr = self.handle_bytecode(next_instr)
+                    self.last_instr = self.handle_bytecode(self.last_instr)
+                    self.recorder.final_state = self.getstate()
 
             except ImplicitOperationError, e:
                 if isinstance(e.w_type, Constant):
@@ -386,14 +349,14 @@
                 msg = "implicit %s shouldn't occur" % exc_cls.__name__
                 w_type = Constant(AssertionError)
                 w_value = Constant(AssertionError(msg))
-                link = Link([w_type, w_value], self.graph.exceptblock)
+                link = Link([w_type, w_value], graph.exceptblock)
                 self.recorder.crnt_block.closeblock(link)
 
             except FSException, e:
                 if e.w_type is self.space.w_ImportError:
                     msg = 'import statement always raises %s' % e
                     raise ImportError(msg)
-                link = Link([e.w_type, e.w_value], self.graph.exceptblock)
+                link = Link([e.w_type, e.w_value], graph.exceptblock)
                 self.recorder.crnt_block.closeblock(link)
 
             except StopFlowing:
@@ -402,7 +365,7 @@
             except Return:
                 w_result = self.popvalue()
                 assert w_result is not None
-                link = Link([w_result], self.graph.returnblock)
+                link = Link([w_result], graph.returnblock)
                 self.recorder.crnt_block.closeblock(link)
 
         del self.recorder
@@ -414,37 +377,35 @@
         candidates = self.joinpoints.setdefault(next_instr, [])
         for block in candidates:
             newstate = block.framestate.union(currentstate)
-            if newstate is not None:
-                # yes
-                finished = newstate == block.framestate
+            if newstate is None:
+                continue
+            elif newstate == block.framestate:
+                outputargs = currentstate.getoutputargs(newstate)
+                currentblock.closeblock(Link(outputargs, block))
+                return
+            else:
                 break
         else:
-            # no
             newstate = currentstate.copy()
-            finished = False
             block = None
 
-        if finished:
-            newblock = block
-        else:
-            newblock = SpamBlock(newstate)
+        newblock = SpamBlock(newstate)
         # unconditionally link the current block to the newblock
         outputargs = currentstate.getoutputargs(newstate)
         link = Link(outputargs, newblock)
         currentblock.closeblock(link)
-        # phew
-        if not finished:
-            if block is not None:
-                # to simplify the graph, we patch the old block to point
-                # directly at the new block which is its generalization
-                block.dead = True
-                block.operations = ()
-                block.exitswitch = None
-                outputargs = block.framestate.getoutputargs(newstate)
-                block.recloseblock(Link(outputargs, newblock))
-                candidates.remove(block)
-            candidates.insert(0, newblock)
-            self.pendingblocks.append(newblock)
+
+        if block is not None:
+            # to simplify the graph, we patch the old block to point
+            # directly at the new block which is its generalization
+            block.dead = True
+            block.operations = ()
+            block.exitswitch = None
+            outputargs = block.framestate.getoutputargs(newstate)
+            block.recloseblock(Link(outputargs, newblock))
+            candidates.remove(block)
+        candidates.insert(0, newblock)
+        self.pendingblocks.append(newblock)
 
     # hack for unrolling iterables, don't use this
     def replace_in_stack(self, oldvalue, newvalue):
@@ -460,17 +421,12 @@
                     break
 
     def handle_bytecode(self, next_instr):
+        next_instr, methodname, oparg = self.pycode.read(next_instr)
         try:
-            while True:
-                self.last_instr = next_instr
-                self.recorder.bytecode_trace(self)
-                next_instr, methodname, oparg = self.pycode.read(next_instr)
-                res = getattr(self, methodname)(oparg, next_instr)
-                if res is not None:
-                    next_instr = res
+            res = getattr(self, methodname)(oparg, next_instr)
+            return res if res is not None else next_instr
         except FSException, operr:
-            next_instr = self.handle_operation_error(operr)
-        return next_instr
+            return self.handle_operation_error(operr)
 
     def handle_operation_error(self, operr):
         block = self.unrollstack(SApplicationException.kind)
@@ -481,6 +437,18 @@
             next_instr = block.handle(self, unroller)
             return next_instr
 
+    def getlocalvarname(self, index):
+        return self.pycode.co_varnames[index]
+
+    def getconstant_w(self, index):
+        return self.space.wrap(self.pycode.consts[index])
+
+    def getname_u(self, index):
+        return self.pycode.names[index]
+
+    def getname_w(self, index):
+        return Constant(self.pycode.names[index])
+
     def BAD_OPCODE(self, _, next_instr):
         raise FlowingError(self, "This operation is not RPython")
 
@@ -685,19 +653,13 @@
         # Note: RPython context managers receive None in lieu of tracebacks
         # and cannot suppress the exception.
         # This opcode changed a lot between CPython versions
-        if (self.pycode.magic >= 0xa0df2ef
-            # Implementation since 2.7a0: 62191 (introduce SETUP_WITH)
-            or self.pycode.magic >= 0xa0df2d1):
-            # implementation since 2.6a1: 62161 (WITH_CLEANUP optimization)
+        if sys.version_info >= (2, 6):
             w_unroller = self.popvalue()
             w_exitfunc = self.popvalue()
             self.pushvalue(w_unroller)
-        elif self.pycode.magic >= 0xa0df28c:
-            # Implementation since 2.5a0: 62092 (changed WITH_CLEANUP opcode)
+        else:
             w_exitfunc = self.popvalue()
             w_unroller = self.peekvalue(0)
-        else:
-            raise NotImplementedError("WITH_CLEANUP for CPython <= 2.4")
 
         unroller = self.space.unwrap(w_unroller)
         w_None = self.space.w_None
@@ -710,6 +672,12 @@
         else:
             self.space.call_function(w_exitfunc, w_None, w_None, w_None)
 
+    def LOAD_FAST(self, varindex, next_instr):
+        w_value = self.locals_stack_w[varindex]
+        if w_value is None:
+            raise FlowingError(self, "Local variable referenced before assignment")
+        self.pushvalue(w_value)
+
     def LOAD_GLOBAL(self, nameindex, next_instr):
         w_result = self.space.find_global(self.w_globals, self.getname_u(nameindex))
         self.pushvalue(w_result)
@@ -722,6 +690,9 @@
         self.pushvalue(w_value)
     LOOKUP_METHOD = LOAD_ATTR
 
+    def LOAD_DEREF(self, varindex, next_instr):
+        self.pushvalue(self.closure[varindex])
+
     def BUILD_LIST_FROM_ARG(self, _, next_instr):
         # This opcode was added with pypy-1.8.  Here is a simpler
         # version, enough for annotation.
@@ -729,6 +700,12 @@
         self.pushvalue(self.space.newlist([]))
         self.pushvalue(last_val)
 
+    def MAKE_FUNCTION(self, numdefaults, next_instr):
+        w_codeobj = self.popvalue()
+        defaults = self.popvalues(numdefaults)
+        fn = self.space.newfunction(w_codeobj, self.w_globals, defaults)
+        self.pushvalue(fn)
+
     # XXX Unimplemented 2.7 opcodes ----------------
 
     # Set literals, set comprehensions
@@ -744,6 +721,12 @@
     def MAP_ADD(self, oparg, next_instr):
         raise NotImplementedError("MAP_ADD")
 
+    # Closures
+
+    STORE_DEREF = BAD_OPCODE
+    LOAD_CLOSURE = BAD_OPCODE
+    MAKE_CLOSURE = BAD_OPCODE
+
     def make_arguments(self, nargs):
         return ArgumentsForTranslation(self.space, self.peekvalues(nargs))
     def argument_factory(self, *args):
diff --git a/pypy/objspace/flow/framestate.py b/pypy/objspace/flow/framestate.py
--- a/pypy/objspace/flow/framestate.py
+++ b/pypy/objspace/flow/framestate.py
@@ -2,10 +2,10 @@
 from pypy.objspace.flow.model import *
 
 class FrameState:
-    def __init__(self, mergeable, nonmergeable):
+    def __init__(self, mergeable, blocklist, next_instr):
         self.mergeable = mergeable
-        self.nonmergeable = nonmergeable
-        self.next_instr = self.nonmergeable[1]
+        self.blocklist = blocklist
+        self.next_instr = next_instr
         for w1 in self.mergeable:
             assert isinstance(w1, (Variable, Constant)) or w1 is None, (
                 '%r found in frame state' % w1)
@@ -17,7 +17,7 @@
             if isinstance(w, Variable):
                 w = Variable()
             newstate.append(w)
-        return FrameState(newstate, self.nonmergeable)
+        return FrameState(newstate, self.blocklist, self.next_instr)
 
     def getvariables(self):
         return [w for w in self.mergeable if isinstance(w, Variable)]
@@ -29,7 +29,8 @@
         # nonmergeable states
         assert isinstance(other, FrameState)
         assert len(self.mergeable) == len(other.mergeable)
-        assert self.nonmergeable == other.nonmergeable
+        assert self.blocklist == other.blocklist
+        assert self.next_instr == other.next_instr
         for w1, w2 in zip(self.mergeable, other.mergeable):
             if not (w1 == w2 or (isinstance(w1, Variable) and
                                  isinstance(w2, Variable))):
@@ -50,7 +51,7 @@
                 newstate.append(union(w1, w2))
         except UnionError:
             return None
-        return FrameState(newstate, self.nonmergeable)
+        return FrameState(newstate, self.blocklist, self.next_instr)
 
     def getoutputargs(self, targetstate):
         "Return the output arguments needed to link self to targetstate."
diff --git a/pypy/objspace/flow/generator.py b/pypy/objspace/flow/generator.py
new file mode 100644
--- /dev/null
+++ b/pypy/objspace/flow/generator.py
@@ -0,0 +1,186 @@
+"""Flow graph building for generators"""
+
+from pypy.objspace.flow.model import Block, Link, SpaceOperation, checkgraph
+from pypy.objspace.flow.model import Variable, Constant
+from pypy.translator.unsimplify import insert_empty_startblock
+from pypy.translator.unsimplify import split_block
+from pypy.translator.simplify import eliminate_empty_blocks, simplify_graph
+from pypy.tool.sourcetools import func_with_new_name
+from pypy.interpreter.argument import Signature
+
+
+class AbstractPosition(object):
+    _immutable_ = True
+    _attrs_ = ()
+
+def bootstrap_generator(graph):
+    # This is the first copy of the graph.  We replace it with
+    # a small bootstrap graph.
+    GeneratorIterator = make_generatoriterator_class(graph)
+    replace_graph_with_bootstrap(GeneratorIterator, graph)
+    # We attach a 'next' method to the GeneratorIterator class
+    # that will invoke the real function, based on a second
+    # copy of the graph.
+    attach_next_method(GeneratorIterator, graph)
+    return graph
+
+def tweak_generator_graph(graph):
+    # This is the second copy of the graph.  Tweak it.
+    GeneratorIterator = graph.func._generator_next_method_of_
+    tweak_generator_body_graph(GeneratorIterator.Entry, graph)
+
+
+def make_generatoriterator_class(graph):
+    class GeneratorIterator(object):
+        class Entry(AbstractPosition):
+            _immutable_ = True
+            varnames = get_variable_names(graph.startblock.inputargs)
+
+        def __init__(self, entry):
+            self.current = entry
+
+        def __iter__(self):
+            return self
+
+    return GeneratorIterator
+
+def replace_graph_with_bootstrap(GeneratorIterator, graph):
+    Entry = GeneratorIterator.Entry
+    newblock = Block(graph.startblock.inputargs)
+    v_generator = Variable('generator')
+    v_entry = Variable('entry')
+    newblock.operations.append(
+        SpaceOperation('simple_call', [Constant(Entry)], v_entry))
+    assert len(graph.startblock.inputargs) == len(Entry.varnames)
+    for v, name in zip(graph.startblock.inputargs, Entry.varnames):
+        newblock.operations.append(
+            SpaceOperation('setattr', [v_entry, Constant(name), v],
+                           Variable()))
+    newblock.operations.append(
+        SpaceOperation('simple_call', [Constant(GeneratorIterator), v_entry],
+                       v_generator))
+    newblock.closeblock(Link([v_generator], graph.returnblock))
+    graph.startblock = newblock
+
+def attach_next_method(GeneratorIterator, graph):
+    func = graph.func
+    func = func_with_new_name(func, '%s__next' % (func.func_name,))
+    func._generator_next_method_of_ = GeneratorIterator
+    func._always_inline_ = True
+    #
+    def next(self):
+        entry = self.current
+        self.current = None
+        assert entry is not None      # else, recursive generator invocation
+        (next_entry, return_value) = func(entry)
+        self.current = next_entry
+        return return_value
+    GeneratorIterator.next = next
+    return func   # for debugging
+
+def get_variable_names(variables):
+    seen = set()
+    result = []
+    for v in variables:
+        name = v._name.strip('_')
+        while name in seen:
+            name += '_'
+        result.append('g_' + name)
+        seen.add(name)
+    return result
+
+def _insert_reads(block, varnames):
+    assert len(varnames) == len(block.inputargs)
+    v_entry1 = Variable('entry')
+    for i, name in enumerate(varnames):
+        block.operations.insert(i,
+            SpaceOperation('getattr', [v_entry1, Constant(name)],
+                           block.inputargs[i]))
+    block.inputargs = [v_entry1]
+
+def tweak_generator_body_graph(Entry, graph):
+    # First, always run simplify_graph in order to reduce the number of
+    # variables passed around
+    simplify_graph(graph)
+    #
+    assert graph.startblock.operations[0].opname == 'generator_mark'
+    graph.startblock.operations.pop(0)
+    #
+    insert_empty_startblock(None, graph)
+    _insert_reads(graph.startblock, Entry.varnames)
+    Entry.block = graph.startblock
+    #
+    mappings = [Entry]
+    #
+    stopblock = Block([])
+    v0 = Variable(); v1 = Variable()
+    stopblock.operations = [
+        SpaceOperation('simple_call', [Constant(StopIteration)], v0),
+        SpaceOperation('type', [v0], v1),
+        ]
+    stopblock.closeblock(Link([v1, v0], graph.exceptblock))
+    #
+    for block in list(graph.iterblocks()):
+        for exit in block.exits:
+            if exit.target is graph.returnblock:
+                exit.args = []
+                exit.target = stopblock
+        assert block is not stopblock
+        for index in range(len(block.operations)-1, -1, -1):
+            op = block.operations[index]
+            if op.opname == 'yield':
+                [v_yielded_value] = op.args
+                del block.operations[index]
+                newlink = split_block(None, block, index)
+                newblock = newlink.target
+                #
+                class Resume(AbstractPosition):
+                    _immutable_ = True
+                    block = newblock
+                Resume.__name__ = 'Resume%d' % len(mappings)
+                mappings.append(Resume)
+                varnames = get_variable_names(newlink.args)
+                #
+                _insert_reads(newblock, varnames)
+                #
+                v_resume = Variable('resume')
+                block.operations.append(
+                    SpaceOperation('simple_call', [Constant(Resume)],
+                                   v_resume))
+                for i, name in enumerate(varnames):
+                    block.operations.append(
+                        SpaceOperation('setattr', [v_resume, Constant(name),
+                                                   newlink.args[i]],
+                                       Variable()))
+                v_pair = Variable('pair')
+                block.operations.append(
+                    SpaceOperation('newtuple', [v_resume, v_yielded_value],
+                                   v_pair))
+                newlink.args = [v_pair]
+                newlink.target = graph.returnblock
+    #
+    regular_entry_block = Block([Variable('entry')])
+    block = regular_entry_block
+    for Resume in mappings:
+        v_check = Variable()
+        block.operations.append(
+            SpaceOperation('simple_call', [Constant(isinstance),
+                                           block.inputargs[0],
+                                           Constant(Resume)],
+                           v_check))
+        block.exitswitch = v_check
+        link1 = Link([block.inputargs[0]], Resume.block)
+        link1.exitcase = True
+        nextblock = Block([Variable('entry')])
+        link2 = Link([block.inputargs[0]], nextblock)
+        link2.exitcase = False
+        block.closeblock(link1, link2)
+        block = nextblock
+    block.closeblock(Link([Constant(AssertionError),
+                           Constant(AssertionError("bad generator class"))],
+                          graph.exceptblock))
+    graph.startblock = regular_entry_block
+    graph.signature = Signature(['entry'])
+    graph.defaults = ()
+    checkgraph(graph)
+    eliminate_empty_blocks(graph)
diff --git a/pypy/objspace/flow/objspace.py b/pypy/objspace/flow/objspace.py
--- a/pypy/objspace/flow/objspace.py
+++ b/pypy/objspace/flow/objspace.py
@@ -1,14 +1,23 @@
-# ______________________________________________________________________
+"""Implements the core parts of flow graph creation, in tandem
+with pypy.objspace.flow.flowcontext.
+"""
+
 import __builtin__
 import sys
 import types
+from inspect import CO_NEWLOCALS
+
 from pypy.interpreter.baseobjspace import ObjSpace
 from pypy.interpreter.argument import ArgumentsForTranslation
 from pypy.objspace.flow.model import (Constant, Variable, WrapException,
     UnwrapException, checkgraph, SpaceOperation)
+from pypy.objspace.flow.bytecode import HostCode
 from pypy.objspace.flow import operation
 from pypy.objspace.flow.flowcontext import (FlowSpaceFrame, fixeggblocks,
     FSException, FlowingError)
+from pypy.objspace.flow.generator import (tweak_generator_graph,
+        bootstrap_generator)
+from pypy.objspace.flow.pygraph import PyGraph
 from pypy.objspace.flow.specialcase import SPECIAL_CASES
 from pypy.rlib.unroll import unrolling_iterable, _unroller
 from pypy.rlib import rstackovf, rarithmetic
@@ -37,6 +46,17 @@
         }
     }
 
+def _assert_rpythonic(func):
+    """Raise ValueError if ``func`` is obviously not RPython"""
+    if func.func_doc and func.func_doc.lstrip().startswith('NOT_RPYTHON'):
+        raise ValueError("%r is tagged as NOT_RPYTHON" % (func,))
+    if func.func_code.co_cellvars:
+        raise ValueError("RPython functions cannot create closures")
+    if not (func.func_code.co_flags & CO_NEWLOCALS):
+        raise ValueError("The code object for a RPython function should have "
+                "the flag CO_NEWLOCALS set.")
+
+
 # ______________________________________________________________________
 class FlowObjSpace(object):
     """NOT_RPYTHON.
@@ -94,6 +114,17 @@
         else:
             return self.w_False
 
+    def newfunction(self, w_code, w_globals, defaults_w):
+        try:
+            code = self.unwrap(w_code)
+            globals = self.unwrap(w_globals)
+            defaults = tuple([self.unwrap(value) for value in defaults_w])
+        except UnwrapException:
+            raise FlowingError(self.frame, "Dynamically created function must"
+                    " have constant default values.")
+        fn = types.FunctionType(code, globals, code.co_name, defaults)
+        return Constant(fn)
+
     def wrap(self, obj):
         if isinstance(obj, (Variable, Constant)):
             raise TypeError("already wrapped: " + repr(obj))
@@ -232,18 +263,25 @@
             w_type = w_instclass
         return FSException(w_type, w_value)
 
-    def build_flow(self, func, constargs={}, tweak_for_generator=True):
+    def build_flow(self, func):
         """
         """
-        if func.func_doc and func.func_doc.lstrip().startswith('NOT_RPYTHON'):
-            raise Exception, "%r is tagged as NOT_RPYTHON" % (func,)
-        frame = self.frame = FlowSpaceFrame(self, func, constargs)
+        _assert_rpythonic(func)
+        code = HostCode._from_code(func.func_code)
+        if (code.is_generator and
+                not hasattr(func, '_generator_next_method_of_')):
+            graph = PyGraph(func, code)
+            block = graph.startblock
+            for name, w_value in zip(code.co_varnames, block.framestate.mergeable):
+                if isinstance(w_value, Variable):
+                    w_value.rename(name)
+            return bootstrap_generator(graph)
+        graph = PyGraph(func, code)
+        frame = self.frame = FlowSpaceFrame(self, graph, code)
         frame.build_flow()
-        graph = frame.graph
         fixeggblocks(graph)
         checkgraph(graph)
-        if graph.is_generator and tweak_for_generator:
-            from pypy.translator.generator import tweak_generator_graph
+        if code.is_generator:
             tweak_generator_graph(graph)
         return graph
 
diff --git a/pypy/objspace/flow/pygraph.py b/pypy/objspace/flow/pygraph.py
new file mode 100644
--- /dev/null
+++ b/pypy/objspace/flow/pygraph.py
@@ -0,0 +1,39 @@
+"""
+Implements flow graphs for Python callables
+"""
+from pypy.objspace.flow.model import (FunctionGraph, Constant, Variable,
+        SpaceOperation)
+from pypy.objspace.flow.framestate import FrameState
+
+class PyGraph(FunctionGraph):
+    """
+    Flow graph for a Python function
+    """
+
+    def __init__(self, func, code):
+        from pypy.objspace.flow.flowcontext import SpamBlock
+        data = [None] * code.co_nlocals
+        for i in range(code.formalargcount):
+            data[i] = Variable()
+        state = FrameState(data + [Constant(None), Constant(None)], [], 0)
+        initialblock = SpamBlock(state)
+        if code.is_generator:
+            initialblock.operations.append(
+                SpaceOperation('generator_mark', [], Variable()))
+
+        super(PyGraph, self).__init__(self._sanitize_funcname(func), initialblock)
+        self.func = func
+        self.signature = code.signature
+        self.defaults = func.func_defaults or ()
+
+    @staticmethod
+    def _sanitize_funcname(func):
+        # CallableFactory.pycall may add class_ to functions that are methods
+        name = func.func_name
+        class_ = getattr(func, 'class_', None)
+        if class_ is not None:
+            name = '%s.%s' % (class_.__name__, name)
+        for c in "<>&!":
+            name = name.replace(c, '_')
+        return name
+
diff --git a/pypy/objspace/flow/test/test_framestate.py b/pypy/objspace/flow/test/test_framestate.py
--- a/pypy/objspace/flow/test/test_framestate.py
+++ b/pypy/objspace/flow/test/test_framestate.py
@@ -2,6 +2,8 @@
 from pypy.rlib.unroll import SpecTag
 from pypy.objspace.flow.objspace import FlowObjSpace
 from pypy.objspace.flow.flowcontext import FlowSpaceFrame
+from pypy.objspace.flow.bytecode import HostCode
+from pypy.objspace.flow.pygraph import PyGraph
 
 class TestFrameState:
     def setup_class(cls):
@@ -12,8 +14,11 @@
             func = func.im_func
         except AttributeError:
             pass
-        frame = FlowSpaceFrame(self.space, func)
+        code = HostCode._from_code(func.func_code)
+        graph = PyGraph(func, code)
+        frame = FlowSpaceFrame(self.space, graph, code)
         # hack the frame
+        frame.setstate(graph.startblock.framestate)
         frame.locals_stack_w[frame.pycode.co_nlocals-1] = Constant(None)
         return frame
 
diff --git a/pypy/objspace/flow/test/test_generator.py b/pypy/objspace/flow/test/test_generator.py
--- a/pypy/objspace/flow/test/test_generator.py
+++ b/pypy/objspace/flow/test/test_generator.py
@@ -1,18 +1,127 @@
-from pypy.objspace.flow.test.test_objspace import Base
+from pypy.conftest import option
+from pypy.objspace.flow.objspace import FlowObjSpace
+from pypy.objspace.flow.model import Variable
+from pypy.objspace.flow.generator import (make_generatoriterator_class,
+        replace_graph_with_bootstrap, get_variable_names, attach_next_method)
+from pypy.translator.simplify import join_blocks
 
 
-class TestGenerator(Base):
+# ____________________________________________________________
 
-    def test_simple_generator(self):
-        def f(n):
+def f_gen(n):
+    i = 0
+    while i < n:
+        yield i
+        i += 1
+
+class GeneratorIterator(object):
+    def __init__(self, entry):
+        self.current = entry
+    def next(self):
+        e = self.current
+        self.current = None
+        if isinstance(e, Yield1):
+            n = e.n_0
+            i = e.i_0
+            i += 1
+        else:
+            n = e.n_0
             i = 0
-            while i < n:
-                yield i
-                yield i
-                i += 1
-        graph = self.codetest(f, tweak_for_generator=False)
-        ops = self.all_operations(graph)
-        assert ops == {'generator_mark': 1,
-                       'lt': 1, 'is_true': 1,
-                       'yield': 2,
-                       'inplace_add': 1}
+        if i < n:
+            e = Yield1()
+            e.n_0 = n
+            e.i_0 = i
+            self.current = e
+            return i
+        raise StopIteration
+
+    def __iter__(self):
+        return self
+
+class AbstractPosition(object):
+    _immutable_ = True
+class Entry1(AbstractPosition):
+    _immutable_ = True
+class Yield1(AbstractPosition):
+    _immutable_ = True
+
+def f_explicit(n):
+    e = Entry1()
+    e.n_0 = n
+    return GeneratorIterator(e)
+
+def test_explicit():
+    assert list(f_gen(10)) == list(f_explicit(10))
+
+def test_get_variable_names():
+    lst = get_variable_names([Variable('a'), Variable('b_'), Variable('a')])
+    assert lst == ['g_a', 'g_b', 'g_a_']
+
+# ____________________________________________________________
+
+
+class TestGenerator:
+
+    def test_replace_graph_with_bootstrap(self):
+        def func(n, x, y, z):
+            yield n
+            yield n
+        #
+        graph = FlowObjSpace().build_flow(func)
+        if option.view:
+            graph.show()
+        block = graph.startblock
+        ops = block.operations
+        assert ops[0].opname == 'simple_call' # e = Entry1()
+        assert ops[1].opname == 'setattr'     # e.g_n = n
+        assert ops[1].args[1].value == 'g_n'
+        assert ops[2].opname == 'setattr'     # e.g_x = x
+        assert ops[2].args[1].value == 'g_x'
+        assert ops[3].opname == 'setattr'     # e.g_y = y
+        assert ops[3].args[1].value == 'g_y'
+        assert ops[4].opname == 'setattr'     # e.g_z = z
+        assert ops[4].args[1].value == 'g_z'
+        assert ops[5].opname == 'simple_call' # g = GeneratorIterator(e)
+        assert ops[5].args[1] == ops[0].result
+        assert len(ops) == 6
+        assert len(block.exits) == 1
+        assert block.exits[0].target is graph.returnblock
+
+    def test_tweak_generator_graph(self):
+        def f(n, x, y, z):
+            z *= 10
+            yield n + 1
+            z -= 10
+        #
+        space = FlowObjSpace()
+        graph = space.build_flow(f)
+        GeneratorIterator = make_generatoriterator_class(graph)
+        replace_graph_with_bootstrap(GeneratorIterator, graph)
+        func1 = attach_next_method(GeneratorIterator, graph)
+        if option.view:
+            graph.show()
+        #
+        assert func1._generator_next_method_of_ is GeneratorIterator
+        assert hasattr(GeneratorIterator, 'next')
+        #
+        graph_next = space.build_flow(GeneratorIterator.next.im_func)
+        join_blocks(graph_next)
+        if option.view:
+            graph_next.show()
+        #
+        graph1 = space.build_flow(func1)
+        if option.view:
+            graph1.show()
+
+    def test_automatic(self):
+        def f(n, x, y, z):
+            z *= 10
+            yield n + 1
+            z -= 10
+        #
+        graph = FlowObjSpace().build_flow(f)
+        if option.view:
+            graph.show()
+        block = graph.startblock
+        assert len(block.exits) == 1
+        assert block.exits[0].target is graph.returnblock
diff --git a/pypy/objspace/flow/test/test_objspace.py b/pypy/objspace/flow/test/test_objspace.py
--- a/pypy/objspace/flow/test/test_objspace.py
+++ b/pypy/objspace/flow/test/test_objspace.py
@@ -1054,6 +1054,80 @@
         with py.test.raises(FlowingError):
             self.codetest(f)
 
+    @py.test.mark.xfail(reason="closures aren't supported")
+    def test_cellvar_store(self):
+        def f():
+            x = 5
+            return x
+            lambda: x # turn x into a cell variable
+        graph = self.codetest(f)
+        assert len(graph.startblock.exits) == 1
+        assert graph.startblock.exits[0].target == graph.returnblock
+
+    @py.test.mark.xfail(reason="closures aren't supported")
+    def test_arg_as_cellvar(self):
+        def f(x, y, z):
+            a, b, c = 1, 2, 3
+            z = b
+            return z
+            lambda: (a, b, x, z) # make cell variables
+        graph = self.codetest(f)
+        assert len(graph.startblock.exits) == 1
+        assert graph.startblock.exits[0].target == graph.returnblock
+        assert not graph.startblock.operations
+        assert graph.startblock.exits[0].args[0].value == 2
+
+    def test_lambda(self):
+        def f():
+            g = lambda m, n: n*m
+            return g
+        graph = self.codetest(f)
+        assert len(graph.startblock.exits) == 1
+        assert graph.startblock.exits[0].target == graph.returnblock
+        g = graph.startblock.exits[0].args[0].value
+        assert g(4, 4) == 16
+
+    def test_lambda_with_defaults(self):
+        def f():
+            g = lambda m, n=5: n*m
+            return g
+        graph = self.codetest(f)
+        assert len(graph.startblock.exits) == 1
+        assert graph.startblock.exits[0].target == graph.returnblock
+        g = graph.startblock.exits[0].args[0].value
+        assert g(4) == 20
+
+        def f2(x):
+            g = lambda m, n=x: n*m
+            return g
+        with py.test.raises(FlowingError):
+            self.codetest(f2)
+
+    @py.test.mark.xfail(reason="closures aren't supported")
+    def test_closure(self):
+        def f():
+            m = 5
+            return lambda n: m * n
+        graph = self.codetest(f)
+        assert len(graph.startblock.exits) == 1
+        assert graph.startblock.exits[0].target == graph.returnblock
+        g = graph.startblock.exits[0].args[0].value
+        assert g(4) == 20
+
+    def test_closure_error(self):
+        def f():
+            m = 5
+            return lambda n: m * n
+        with py.test.raises(ValueError) as excinfo:
+            self.codetest(f)
+        assert "closure" in str(excinfo.value)
+
+    def test_unbound_local(self):
+        def f():
+            x += 1
+        with py.test.raises(FlowingError):
+            self.codetest(f)
+
 DATA = {'x': 5,
         'y': 6}
 
diff --git a/pypy/objspace/std/bytearraytype.py b/pypy/objspace/std/bytearraytype.py
--- a/pypy/objspace/std/bytearraytype.py
+++ b/pypy/objspace/std/bytearraytype.py
@@ -1,7 +1,6 @@
-import sys
-from pypy.interpreter import gateway
 from pypy.interpreter.baseobjspace import ObjSpace, W_Root
 from pypy.interpreter.error import OperationError
+from pypy.interpreter.gateway import interp2app
 from pypy.objspace.std.register_all import register_all
 from pypy.objspace.std.stdtypedef import StdTypeDef, SMM
 
@@ -163,9 +162,9 @@
 bytearray(sequence) -> bytearray initialized from sequence\'s items
 
 If the argument is a bytearray, the return value is the same object.''',
-    __new__ = gateway.interp2app(descr__new__),
+    __new__ = interp2app(descr__new__),
     __hash__ = None,
-    __reduce__ = gateway.interp2app(descr_bytearray__reduce__),
-    fromhex = gateway.interp2app(descr_fromhex, as_classmethod=True)
+    __reduce__ = interp2app(descr_bytearray__reduce__),
+    fromhex = interp2app(descr_fromhex, as_classmethod=True)
     )
 bytearray_typedef.registermethods(globals())
diff --git a/pypy/rlib/rcomplex.py b/pypy/rlib/rcomplex.py
--- a/pypy/rlib/rcomplex.py
+++ b/pypy/rlib/rcomplex.py
@@ -57,6 +57,9 @@
             denom = r2 + i2 * ratio
             rr = (r1 + i1 * ratio) / denom
             ir = (i1 - r1 * ratio) / denom
+    elif isnan(r2):
+        rr = NAN
+        ir = NAN
     else:
         ratio = r2 / i2
         denom = r2 * ratio + i2
diff --git a/pypy/rlib/test/test_rcomplex.py b/pypy/rlib/test/test_rcomplex.py
--- a/pypy/rlib/test/test_rcomplex.py
+++ b/pypy/rlib/test/test_rcomplex.py
@@ -33,6 +33,9 @@
         ]:
             assert c.c_mul(c1, c2) == result
 
+def test_div():
+    c.c_div((2., 3.), (float('nan'), 0.)) == (float('nan'), float('nan'))
+
 def parse_testfile2(fname):
     """Parse a file with test values
 
diff --git a/pypy/rpython/microbench/__init__.py b/pypy/rpython/microbench/__init__.py
deleted file mode 100644
diff --git a/pypy/rpython/microbench/autopath.py b/pypy/rpython/microbench/autopath.py
deleted file mode 100644
--- a/pypy/rpython/microbench/autopath.py
+++ /dev/null
@@ -1,131 +0,0 @@
-"""
-self cloning, automatic path configuration 
-
-copy this into any subdirectory of pypy from which scripts need 
-to be run, typically all of the test subdirs. 
-The idea is that any such script simply issues
-
-    import autopath
-
-and this will make sure that the parent directory containing "pypy"
-is in sys.path. 
-
-If you modify the master "autopath.py" version (in pypy/tool/autopath.py) 
-you can directly run it which will copy itself on all autopath.py files
-it finds under the pypy root directory. 
-
-This module always provides these attributes:
-
-    pypydir    pypy root directory path 
-    this_dir   directory where this autopath.py resides 
-
-"""
-
-def __dirinfo(part):
-    """ return (partdir, this_dir) and insert parent of partdir
-    into sys.path.  If the parent directories don't have the part
-    an EnvironmentError is raised."""
-
-    import sys, os
-    try:
-        head = this_dir = os.path.realpath(os.path.dirname(__file__))
-    except NameError:
-        head = this_dir = os.path.realpath(os.path.dirname(sys.argv[0]))
-
-    error = None
-    while head:
-        partdir = head
-        head, tail = os.path.split(head)
-        if tail == part:
-            checkfile = os.path.join(partdir, os.pardir, 'pypy', '__init__.py')
-            if not os.path.exists(checkfile):
-                error = "Cannot find %r" % (os.path.normpath(checkfile),)
-            break
-    else:
-        error = "Cannot find the parent directory %r of the path %r" % (
-            partdir, this_dir)
-    if not error:
-        # check for bogus end-of-line style (e.g. files checked out on
-        # Windows and moved to Unix)
-        f = open(__file__.replace('.pyc', '.py'), 'r')
-        data = f.read()
-        f.close()
-        if data.endswith('\r\n') or data.endswith('\r'):
-            error = ("Bad end-of-line style in the .py files. Typically "
-                     "caused by a zip file or a checkout done on Windows and "
-                     "moved to Unix or vice-versa.")
-    if error:
-        raise EnvironmentError("Invalid source tree - bogus checkout! " +
-                               error)
-    
-    pypy_root = os.path.join(head, '')
-    try:
-        sys.path.remove(head)
-    except ValueError:
-        pass
-    sys.path.insert(0, head)
-
-    munged = {}
-    for name, mod in sys.modules.items():
-        if '.' in name:
-            continue
-        fn = getattr(mod, '__file__', None)
-        if not isinstance(fn, str):
-            continue
-        newname = os.path.splitext(os.path.basename(fn))[0]
-        if not newname.startswith(part + '.'):
-            continue
-        path = os.path.join(os.path.dirname(os.path.realpath(fn)), '')
-        if path.startswith(pypy_root) and newname != part:
-            modpaths = os.path.normpath(path[len(pypy_root):]).split(os.sep)
-            if newname != '__init__':
-                modpaths.append(newname)
-            modpath = '.'.join(modpaths)
-            if modpath not in sys.modules:
-                munged[modpath] = mod
-
-    for name, mod in munged.iteritems():
-        if name not in sys.modules:
-            sys.modules[name] = mod
-        if '.' in name:
-            prename = name[:name.rfind('.')]
-            postname = name[len(prename)+1:]
-            if prename not in sys.modules:
-                __import__(prename)
-                if not hasattr(sys.modules[prename], postname):
-                    setattr(sys.modules[prename], postname, mod)
-
-    return partdir, this_dir
-
-def __clone():
-    """ clone master version of autopath.py into all subdirs """
-    from os.path import join, walk
-    if not this_dir.endswith(join('pypy','tool')):
-        raise EnvironmentError("can only clone master version "
-                               "'%s'" % join(pypydir, 'tool',_myname))
-
-
-    def sync_walker(arg, dirname, fnames):
-        if _myname in fnames:
-            fn = join(dirname, _myname)
-            f = open(fn, 'rwb+')
-            try:
-                if f.read() == arg:
-                    print "checkok", fn
-                else:
-                    print "syncing", fn
-                    f = open(fn, 'w')
-                    f.write(arg)
-            finally:
-                f.close()
-    s = open(join(pypydir, 'tool', _myname), 'rb').read()
-    walk(pypydir, sync_walker, s)
-
-_myname = 'autopath.py'
-
-# set guaranteed attributes
-
-pypydir, this_dir = __dirinfo('pypy')
-
-if __name__ == '__main__':
-    __clone()
diff --git a/pypy/rpython/microbench/dict.py b/pypy/rpython/microbench/dict.py
deleted file mode 100644
--- a/pypy/rpython/microbench/dict.py
+++ /dev/null
@@ -1,65 +0,0 @@
-from pypy.rpython.microbench.microbench import MetaBench
-
-class str_dict__set_item:
-    __metaclass__ = MetaBench
-
-    def init():
-        return {}
-    args = ['obj', 'i']
-    def loop(obj, i):
-        obj['foo'] = i
-        obj['bar'] = i
-
-class str_dict__get_item:
-    __metaclass__ = MetaBench
-
-    def init():
-        return {'foo': 0, 'bar': 1}
-    args = ['obj', 'i']
-    def loop(obj, i):
-        return obj['foo'] + obj['bar']
-
-class int_dict__set_item:
-    __metaclass__ = MetaBench
-
-    def init():
-        return {}
-    args = ['obj', 'i']
-    def loop(obj, i):
-        obj[42] = i
-        obj[43] = i
-
-class int_dict__get_item:
-    __metaclass__ = MetaBench
-
-    def init():
-        return {42: 0, 43: 1}
-    args = ['obj', 'i']
-    def loop(obj, i):
-        return obj[42] + obj[43]
-
-
-class Foo:
-    pass
-
-obj1 = Foo()
-obj2 = Foo()
-
-class obj_dict__set_item:
-    __metaclass__ = MetaBench
-
-    def init():
-        return {}
-    args = ['obj', 'i']
-    def loop(obj, i):
-        obj[obj1] = i
-        obj[obj2] = i
-
-class obj_dict__get_item:
-    __metaclass__ = MetaBench
-
-    def init():
-        return {obj1: 0, obj2: 1}
-    args = ['obj', 'i']
-    def loop(obj, i):
-        return obj[obj1] + obj[obj2]
diff --git a/pypy/rpython/microbench/indirect.py b/pypy/rpython/microbench/indirect.py
deleted file mode 100644
--- a/pypy/rpython/microbench/indirect.py
+++ /dev/null
@@ -1,24 +0,0 @@
-from pypy.rpython.microbench.microbench import MetaBench
-
-def f1(x):
-    return x
-
-def f2(x):
-    return x+1
-
-def f3(x):
-    return x+2
-
-def f4(x):
-    return x+3
-
-FUNCS = [f1, f2, f3, f4]
-
-class indirect__call:
-    __metaclass__ = MetaBench
-
-    def init():
-        return FUNCS
-    args = ['obj', 'i']
-    def loop(obj, i):
-        return obj[i%4](i)
diff --git a/pypy/rpython/microbench/list.py b/pypy/rpython/microbench/list.py
deleted file mode 100644
--- a/pypy/rpython/microbench/list.py
+++ /dev/null
@@ -1,79 +0,0 @@
-from pypy.rpython.microbench.microbench import MetaBench
-
-class list__append:
-    __metaclass__ = MetaBench
-    def init():
-        return []
-    args = ['obj', 'i']
-    def loop(obj, i):
-        obj.append(i)
-    
-class list__get_item:
-    __metaclass__ = MetaBench
-    LOOPS = 100000000
-    def init():
-        obj = []
-        for i in xrange(1000):
-            obj.append(i)
-        return obj
-    args = ['obj', 'i']
-    def loop(obj, i):
-        return obj[i%1000]
-
-class list__set_item:
-    __metaclass__ = MetaBench
-    LOOPS = 100000000
-    def init():
-        obj = []
-        for i in xrange(1000):
-            obj.append(i)
-        return obj
-    args = ['obj', 'i']
-    def loop(obj, i):
-        obj[i%1000] = i
-
-class fixed_list__get_item:
-    __metaclass__ = MetaBench
-    LOOPS = 100000000
-    def init():
-        return [0] * 1000
-    args = ['obj', 'i']
-    def loop(obj, i):
-        return obj[i%1000]
-
-class fixed_list__set_item:
-    __metaclass__ = MetaBench
-    LOOPS = 100000000
-    def init():
-        return [0] * 1000
-    args = ['obj', 'i']
-    def loop(obj, i):
-        obj[i%1000] = i
-
-class list__iteration__int:
-    __metaclass__ = MetaBench
-    LOOPS = 100000
-    def init():
-        obj = [0]*1000
-        obj[0] = 42
-        return obj
-    args = ['obj']
-    def loop(obj):
-        tot = 0
-        for item in obj:
-            tot += item
-        return tot
-
-class list__iteration__string:
-    __metaclass__ = MetaBench
-    LOOPS = 100000
-    def init():
-        obj = ['foo']*1000
-        obj[0] = 'bar'
-        return obj
-    args = ['obj']
-    def loop(obj):
-        tot = 0
-        for item in obj:
-            tot += len(item)
-        return tot
diff --git a/pypy/rpython/microbench/microbench.py b/pypy/rpython/microbench/microbench.py
deleted file mode 100644
--- a/pypy/rpython/microbench/microbench.py
+++ /dev/null
@@ -1,117 +0,0 @@
-#!/usr/bin/env python
-
-import sys
-import autopath
-from time import clock
-import subprocess
-from pypy.translator.interactive import Translation
-
-LOOPS = 10000000
-
-class MetaBench(type):
-    def __new__(self, cls_name, bases, cls_dict):
-        loop = cls_dict['loop']
-        loop._dont_inline_ = True
-        myglob = {
-            'init': cls_dict['init'],
-            'loop': loop,
-            'LOOPS': cls_dict.get('LOOPS', LOOPS),
-            'clock': clock,
-            }
-        args = ', '.join(cls_dict['args'])
-        source = """
-def %(cls_name)s():
-    obj = init()
-    start = clock()
-    for i in xrange(LOOPS):
-        loop(%(args)s)
-    return clock() - start
-""" % locals()
-        exec source in myglob
-        func = myglob[cls_name]
-        func.benchmark = True
-        return func
-
-
-def run_benchmark(exe):
-    from pypy.translator.cli.test.runtest import CliFunctionWrapper
-    from pypy.translator.jvm.test.runtest import JvmGeneratedSourceWrapper
-    
-    if exe.__class__ in [CliFunctionWrapper,JvmGeneratedSourceWrapper]:
-        stdout, stderr, retval = exe.run()
-    else:
-        assert isinstance(exe, str)
-        bench = subprocess.Popen(exe, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
-        stdout, stderr = bench.communicate()
-        retval = bench.wait()
-    
-    if retval != 0:
-        print 'Running benchmark failed'
-        print 'Standard Output:'
-        print stdout
-        print '-' * 40
-        print 'Standard Error:'
-        print stderr
-        raise SystemExit(-1)
-    
-    mydict = {}
-    for line in stdout.splitlines():
-        name, res = line.split(':')
-        mydict[name.strip()] = float(res)
-    return mydict
-
-def import_benchmarks():
-    modules = sys.argv[1:]
-    if len(modules) == 0:
-        # import all the microbenchs
-        from glob import glob
-        for module in glob('*.py'):
-            if module not in ('__init__.py', 'autopath.py', 'microbench.py'):
-                modules.append(module)
-    
-    for module in modules:
-        module = module.rstrip('.py')
-        exec 'from %s import *' % module in globals()
-
-def main():
-    import_benchmarks()
-    benchmarks = []
-    for name, thing in globals().iteritems():
-        if getattr(thing, 'benchmark', False):
-            benchmarks.append((name, thing))
-    benchmarks.sort()
-    
-    def entry_point(argv):
-        for name, func in benchmarks:
-            print name, ':', func()
-        return 0
-    
-    t = Translation(entry_point, standalone=True, backend='c')
-    c_exe = t.compile()
-    t = Translation(entry_point, standalone=True, backend='cli')
-    cli_exe = t.compile()
-    t = Translation(entry_point, standalone=True, backend='jvm')
-    jvm_exe = t.compile()
-  
-    c_res = run_benchmark(c_exe)
-    cli_res = run_benchmark(cli_exe)
-    jvm_res = run_benchmark(jvm_exe)
-    
-    print 'benchmark                              genc     gencli     cli_ratio   genjvm     jvm_ratio'
-    print
-    for name, _ in benchmarks:
-        c_time = c_res[name]
-        cli_time = cli_res[name]
-        jvm_time = jvm_res[name]
-        if c_time == 0:
-            cli_ratio = '%10s' % '---'
-        else:
-            cli_ratio = '%10.2f' % (cli_time/c_time)
-        if c_time == 0:
-            jvm_ratio = '%10s' % '---'
-        else:
-            jvm_ratio = '%10.2f' % (jvm_time/c_time)
-        print '%-32s %10.2f %10.2f %s %10.2f %s' % (name, c_time, cli_time, cli_ratio, jvm_time, jvm_ratio)
-
-if __name__ == '__main__':
-    main()
diff --git a/pypy/rpython/microbench/rdict.py b/pypy/rpython/microbench/rdict.py
deleted file mode 100644
--- a/pypy/rpython/microbench/rdict.py
+++ /dev/null
@@ -1,70 +0,0 @@
-from pypy.rlib.objectmodel import r_dict
-from pypy.rpython.microbench.microbench import MetaBench
-
-class Obj:
-    def __init__(self, x):
-        self.x = x
-
-def myhash(obj):
-    return obj.x
-
-def mycmp(obj1, obj2):
-    return obj1.x == obj2.x
-
-class Space:
-    def myhash(self, obj):
-        return obj.x
-
-    def mycmp(self, obj1, obj2):
-        return obj1.x == obj2.x
-
-    def _freeze_(self):
-        return True
-
-space = Space()
-obj1 = Obj(1)
-obj2 = Obj(2)
-
-class r_dict__set_item:
-    __metaclass__ = MetaBench
-
-    def init():
-        return r_dict(mycmp, myhash)
-    args = ['obj', 'i']
-    def loop(obj, i):
-        obj[obj1] = i
-        obj[obj2] = i
-
-class r_dict__get_item:
-    __metaclass__ = MetaBench
-
-    def init():
-        res = r_dict(mycmp, myhash)
-        res[obj1] = 42
-        res[obj2] = 43
-        return res
-    args = ['obj', 'i']
-    def loop(obj, i):
-        return obj[obj1] + obj[obj2]
-
-class r_dict__frozen_pbc__set_item:
-    __metaclass__ = MetaBench
-
-    def init():
-        return r_dict(space.mycmp, space.myhash)
-    args = ['obj', 'i']
-    def loop(obj, i):
-        obj[obj1] = i
-        obj[obj2] = i
-
-class r_dict__frozen_pbc__get_item:
-    __metaclass__ = MetaBench
-
-    def init():
-        res = r_dict(space.mycmp, space.myhash)
-        res[obj1] = 42
-        res[obj2] = 43
-        return res
-    args = ['obj', 'i']
-    def loop(obj, i):
-        return obj[obj1] + obj[obj2]
diff --git a/pypy/translator/generator.py b/pypy/translator/generator.py
deleted file mode 100644
--- a/pypy/translator/generator.py
+++ /dev/null
@@ -1,184 +0,0 @@
-from pypy.objspace.flow.model import Block, Link, SpaceOperation, checkgraph
-from pypy.objspace.flow.model import Variable, Constant, FunctionGraph
-from pypy.translator.unsimplify import insert_empty_startblock
-from pypy.translator.unsimplify import split_block
-from pypy.translator.simplify import eliminate_empty_blocks, simplify_graph
-from pypy.tool.sourcetools import func_with_new_name
-from pypy.interpreter.argument import Signature
-
-
-class AbstractPosition(object):
-    _immutable_ = True
-    _attrs_ = ()
-
-
-def tweak_generator_graph(graph):
-    if not hasattr(graph.func, '_generator_next_method_of_'):
-        # This is the first copy of the graph.  We replace it with
-        # a small bootstrap graph.
-        GeneratorIterator = make_generatoriterator_class(graph)
-        replace_graph_with_bootstrap(GeneratorIterator, graph)
-        # We attach a 'next' method to the GeneratorIterator class
-        # that will invoke the real function, based on a second
-        # copy of the graph.
-        attach_next_method(GeneratorIterator, graph)
-    else:
-        # This is the second copy of the graph.  Tweak it.
-        GeneratorIterator = graph.func._generator_next_method_of_
-        tweak_generator_body_graph(GeneratorIterator.Entry, graph)
-
-
-def make_generatoriterator_class(graph):
-    class GeneratorIterator(object):
-        class Entry(AbstractPosition):
-            _immutable_ = True
-            varnames = get_variable_names(graph.startblock.inputargs)
-
-        def __init__(self, entry):
-            self.current = entry
-
-        def __iter__(self):
-            return self
-
-    return GeneratorIterator
-
-def replace_graph_with_bootstrap(GeneratorIterator, graph):
-    Entry = GeneratorIterator.Entry
-    newblock = Block(graph.startblock.inputargs)
-    v_generator = Variable('generator')
-    v_entry = Variable('entry')
-    newblock.operations.append(
-        SpaceOperation('simple_call', [Constant(Entry)], v_entry))
-    assert len(graph.startblock.inputargs) == len(Entry.varnames)
-    for v, name in zip(graph.startblock.inputargs, Entry.varnames):
-        newblock.operations.append(
-            SpaceOperation('setattr', [v_entry, Constant(name), v],
-                           Variable()))
-    newblock.operations.append(
-        SpaceOperation('simple_call', [Constant(GeneratorIterator), v_entry],
-                       v_generator))
-    newblock.closeblock(Link([v_generator], graph.returnblock))
-    graph.startblock = newblock
-
-def attach_next_method(GeneratorIterator, graph):
-    func = graph.func
-    func = func_with_new_name(func, '%s__next' % (func.func_name,))
-    func._generator_next_method_of_ = GeneratorIterator
-    func._always_inline_ = True
-    #
-    def next(self):
-        entry = self.current
-        self.current = None
-        assert entry is not None      # else, recursive generator invocation
-        (next_entry, return_value) = func(entry)
-        self.current = next_entry
-        return return_value
-    GeneratorIterator.next = next
-    return func   # for debugging
-
-def get_variable_names(variables):
-    seen = set()
-    result = []
-    for v in variables:
-        name = v._name.strip('_')
-        while name in seen:
-            name += '_'
-        result.append('g_' + name)
-        seen.add(name)
-    return result
-
-def _insert_reads(block, varnames):
-    assert len(varnames) == len(block.inputargs)
-    v_entry1 = Variable('entry')
-    for i, name in enumerate(varnames):
-        block.operations.insert(i,
-            SpaceOperation('getattr', [v_entry1, Constant(name)],
-                           block.inputargs[i]))
-    block.inputargs = [v_entry1]
-
-def tweak_generator_body_graph(Entry, graph):
-    # First, always run simplify_graph in order to reduce the number of
-    # variables passed around
-    simplify_graph(graph)
-    #
-    assert graph.startblock.operations[0].opname == 'generator_mark'
-    graph.startblock.operations.pop(0)
-    #
-    insert_empty_startblock(None, graph)
-    _insert_reads(graph.startblock, Entry.varnames)
-    Entry.block = graph.startblock
-    #
-    mappings = [Entry]
-    #
-    stopblock = Block([])
-    v0 = Variable(); v1 = Variable()
-    stopblock.operations = [
-        SpaceOperation('simple_call', [Constant(StopIteration)], v0),
-        SpaceOperation('type', [v0], v1),
-        ]
-    stopblock.closeblock(Link([v1, v0], graph.exceptblock))
-    #
-    for block in list(graph.iterblocks()):
-        for exit in block.exits:
-            if exit.target is graph.returnblock:
-                exit.args = []
-                exit.target = stopblock
-        assert block is not stopblock
-        for index in range(len(block.operations)-1, -1, -1):
-            op = block.operations[index]
-            if op.opname == 'yield':
-                [v_yielded_value] = op.args
-                del block.operations[index]
-                newlink = split_block(None, block, index)
-                newblock = newlink.target
-                #
-                class Resume(AbstractPosition):
-                    _immutable_ = True
-                    block = newblock
-                Resume.__name__ = 'Resume%d' % len(mappings)
-                mappings.append(Resume)
-                varnames = get_variable_names(newlink.args)
-                #
-                _insert_reads(newblock, varnames)
-                #
-                v_resume = Variable('resume')
-                block.operations.append(
-                    SpaceOperation('simple_call', [Constant(Resume)],
-                                   v_resume))
-                for i, name in enumerate(varnames):


More information about the pypy-commit mailing list