[pypy-commit] pypy arm-backend-2: merge default

bivab noreply at buildbot.pypy.org
Fri Aug 10 14:13:11 CEST 2012


Author: David Schneider <david.schneider at picle.org>
Branch: arm-backend-2
Changeset: r56687:d8f3bbebe233
Date: 2012-08-10 08:42 +0000
http://bitbucket.org/pypy/pypy/changeset/d8f3bbebe233/

Log:	merge default

diff --git a/lib_pypy/_ctypes/basics.py b/lib_pypy/_ctypes/basics.py
--- a/lib_pypy/_ctypes/basics.py
+++ b/lib_pypy/_ctypes/basics.py
@@ -59,7 +59,8 @@
         'resbuffer' is a _rawffi array of length 1 containing the value,
         and this returns a general Python object that corresponds.
         """
-        res = self.__new__(self)
+        res = object.__new__(self)
+        res.__class__ = self
         res.__dict__['_buffer'] = resbuffer
         res.__dict__['_base'] = base
         res.__dict__['_index'] = index
diff --git a/lib_pypy/_marshal.py b/lib_pypy/_marshal.py
--- a/lib_pypy/_marshal.py
+++ b/lib_pypy/_marshal.py
@@ -430,6 +430,7 @@
 def _read(self, n):
     pos = self.bufpos
     newpos = pos + n
+    if newpos > len(self.bufstr): raise EOFError
     ret = self.bufstr[pos : newpos]
     self.bufpos = newpos
     return ret
diff --git a/lib_pypy/greenlet.py b/lib_pypy/greenlet.py
--- a/lib_pypy/greenlet.py
+++ b/lib_pypy/greenlet.py
@@ -77,8 +77,6 @@
         try:
             unbound_method = getattr(_continulet, methodname)
             args = unbound_method(current, *args, to=target)
-        except GreenletExit, e:
-            args = (e,)
         finally:
             _tls.current = current
         #
@@ -132,6 +130,8 @@
     _tls.current = greenlet
     try:
         res = greenlet.run(*args)
+    except GreenletExit, e:
+        res = e
     finally:
         _continuation.permute(greenlet, greenlet.parent)
     return (res,)
diff --git a/lib_pypy/pypy_test/test_marshal_extra.py b/lib_pypy/pypy_test/test_marshal_extra.py
--- a/lib_pypy/pypy_test/test_marshal_extra.py
+++ b/lib_pypy/pypy_test/test_marshal_extra.py
@@ -142,4 +142,6 @@
         f2.close()
     assert obj == case
 
-
+def test_load_truncated_string():
+    s = '(\x02\x00\x00\x00i\x03\x00\x00\x00sB\xf9\x00\x00\nabcd'
+    py.test.raises(EOFError, marshal.loads, s)
diff --git a/pypy/jit/backend/arm/test/test_ztranslation.py b/pypy/jit/backend/arm/test/test_ztranslation.py
--- a/pypy/jit/backend/arm/test/test_ztranslation.py
+++ b/pypy/jit/backend/arm/test/test_ztranslation.py
@@ -176,7 +176,6 @@
         assert bound & (bound-1) == 0       # a power of two
 
     def test_jit_get_stats(self):
-        py.test.xfail()
         driver = JitDriver(greens = [], reds = ['i'])
         
         def f():
@@ -192,7 +191,8 @@
             return len(ll_times)
 
         res = self.meta_interp(main, [])
-        assert res == 1
+        assert res == 3
+        # one for loop, one for entry point and one for the prologue
 
 class TestTranslationRemoveTypePtrARM(CCompiledMixin):
     CPUClass = getcpuclass()
diff --git a/pypy/jit/backend/x86/assembler.py b/pypy/jit/backend/x86/assembler.py
--- a/pypy/jit/backend/x86/assembler.py
+++ b/pypy/jit/backend/x86/assembler.py
@@ -127,9 +127,13 @@
         self._build_stack_check_slowpath()
         if gc_ll_descr.gcrootmap:
             self._build_release_gil(gc_ll_descr.gcrootmap)
-        debug_start('jit-backend-counts')
-        self.set_debug(have_debug_prints())
-        debug_stop('jit-backend-counts')
+        if not self._debug:
+            # if self._debug is already set it means that someone called
+            # set_debug by hand before initializing the assembler. Leave it
+            # as it is
+            debug_start('jit-backend-counts')
+            self.set_debug(have_debug_prints())
+            debug_stop('jit-backend-counts')
 
     def setup(self, looptoken):
         assert self.memcpy_addr != 0, "setup_once() not called?"
diff --git a/pypy/jit/backend/x86/test/test_ztranslation.py b/pypy/jit/backend/x86/test/test_ztranslation.py
--- a/pypy/jit/backend/x86/test/test_ztranslation.py
+++ b/pypy/jit/backend/x86/test/test_ztranslation.py
@@ -172,7 +172,6 @@
         assert bound & (bound-1) == 0       # a power of two
 
     def test_jit_get_stats(self):
-        py.test.xfail()
         driver = JitDriver(greens = [], reds = ['i'])
         
         def f():
@@ -188,7 +187,8 @@
             return len(ll_times)
 
         res = self.meta_interp(main, [])
-        assert res == 1
+        assert res == 3
+        # one for loop, one for entry point and one for the prologue
 
 class TestTranslationRemoveTypePtrX86(CCompiledMixin):
     CPUClass = getcpuclass()
diff --git a/pypy/jit/metainterp/executor.py b/pypy/jit/metainterp/executor.py
--- a/pypy/jit/metainterp/executor.py
+++ b/pypy/jit/metainterp/executor.py
@@ -277,19 +277,6 @@
 
 
 def _make_execute_list():
-    if 0:     # enable this to trace calls to do_xxx
-        def wrap(fn):
-            def myfn(*args):
-                print '<<<', fn.__name__
-                try:
-                    return fn(*args)
-                finally:
-                    print fn.__name__, '>>>'
-            return myfn
-    else:
-        def wrap(fn):
-            return fn
-    #
     execute_by_num_args = {}
     for key, value in rop.__dict__.items():
         if not key.startswith('_'):
diff --git a/pypy/jit/metainterp/test/test_warmspot.py b/pypy/jit/metainterp/test/test_warmspot.py
--- a/pypy/jit/metainterp/test/test_warmspot.py
+++ b/pypy/jit/metainterp/test/test_warmspot.py
@@ -260,6 +260,33 @@
                     pass   # other case
         self.meta_interp(f1, [18])
 
+    def test_bug_constant_int(self):
+        py.test.skip("crashes because a is a constant")
+        from pypy.rpython.lltypesystem import lltype, rffi
+        mydriver = JitDriver(greens=['a'], reds=['m'])
+        def f1(m, a):
+            while m > 0:
+                mydriver.jit_merge_point(a=a, m=m)
+                m = m - 1
+        def entry(m):
+            f1(m, 42)
+        self.meta_interp(entry, [18])
+
+    def test_bug_constant_instance(self):
+        py.test.skip("crashes because a is a constant")
+        from pypy.rpython.lltypesystem import lltype, rffi
+        mydriver = JitDriver(greens=['a'], reds=['m'])
+        class A(object):
+            pass
+        a1 = A()
+        def f1(m, a):
+            while m > 0:
+                mydriver.jit_merge_point(a=a, m=m)
+                m = m - 1
+        def entry(m):
+            f1(m, a1)
+        self.meta_interp(entry, [18])
+
     def test_bug_constant_rawptrs(self):
         py.test.skip("crashes because a is a constant")
         from pypy.rpython.lltypesystem import lltype, rffi
diff --git a/pypy/module/_minimal_curses/fficurses.py b/pypy/module/_minimal_curses/fficurses.py
--- a/pypy/module/_minimal_curses/fficurses.py
+++ b/pypy/module/_minimal_curses/fficurses.py
@@ -9,10 +9,12 @@
 from pypy.module._minimal_curses import interp_curses
 from pypy.translator.tool.cbuild import ExternalCompilationInfo
 from sys import platform
+import os.path
 
 _CYGWIN = platform == 'cygwin'
+_NCURSES_CURSES = os.path.isfile("/usr/include/ncurses/curses.h") 
 
-if _CYGWIN:
+if _CYGWIN or _NCURSES_CURSES:
     eci = ExternalCompilationInfo(
         includes = ['ncurses/curses.h', 'ncurses/term.h'],
         libraries = ['curses'],
diff --git a/pypy/module/imp/importing.py b/pypy/module/imp/importing.py
--- a/pypy/module/imp/importing.py
+++ b/pypy/module/imp/importing.py
@@ -602,8 +602,10 @@
 
         try:
             if find_info.modtype == PY_SOURCE:
-                load_source_module(space, w_modulename, w_mod, find_info.filename,
-                                   find_info.stream.readall())
+                load_source_module(
+                    space, w_modulename, w_mod, 
+                    find_info.filename, find_info.stream.readall(),
+                    find_info.stream.try_to_find_file_descriptor())
                 return w_mod
             elif find_info.modtype == PY_COMPILED:
                 magic = _r_long(find_info.stream)
@@ -878,7 +880,7 @@
 
 
 @jit.dont_look_inside
-def load_source_module(space, w_modulename, w_mod, pathname, source,
+def load_source_module(space, w_modulename, w_mod, pathname, source, fd,
                        write_pyc=True):
     """
     Load a source module from a given file and return its module
@@ -887,8 +889,8 @@
     w = space.wrap
 
     if space.config.objspace.usepycfiles:
+        src_stat = os.fstat(fd)
         cpathname = pathname + 'c'
-        src_stat = os.stat(pathname)
         mtime = int(src_stat[stat.ST_MTIME])
         mode = src_stat[stat.ST_MODE]
         stream = check_compiled_module(space, cpathname, mtime)
diff --git a/pypy/module/imp/interp_imp.py b/pypy/module/imp/interp_imp.py
--- a/pypy/module/imp/interp_imp.py
+++ b/pypy/module/imp/interp_imp.py
@@ -101,7 +101,8 @@
     importing._prepare_module(space, w_mod, filename, None)
 
     importing.load_source_module(
-        space, w_modulename, w_mod, filename, stream.readall())
+        space, w_modulename, w_mod,
+        filename, stream.readall(), stream.try_to_find_file_descriptor())
     if space.is_w(w_file, space.w_None):
         stream.close()
     return w_mod
diff --git a/pypy/module/imp/test/test_import.py b/pypy/module/imp/test/test_import.py
--- a/pypy/module/imp/test/test_import.py
+++ b/pypy/module/imp/test/test_import.py
@@ -104,11 +104,10 @@
         filename = str(p.join("x.py"))
         stream = streamio.open_file_as_stream(filename, "r")
         try:
-            importing.load_source_module(space,
-                                         w_modname,
-                                         w(importing.Module(space, w_modname)),
-                                         filename,
-                                         stream.readall())
+            importing.load_source_module(
+                space, w_modname, w(importing.Module(space, w_modname)),
+                filename, stream.readall(),
+                stream.try_to_find_file_descriptor())
         finally:
             stream.close()
         if space.config.objspace.usepycfiles:
@@ -618,6 +617,19 @@
             sys.path.insert(0, sys.path.pop())
         del sys.modules['itertools']
 
+    def test_invalid_pathname(self):
+        import imp
+        import pkg
+        import os
+
+        info = ('.py', 'r', imp.PY_SOURCE)
+        pathname = os.path.join(os.path.dirname(pkg.__file__), 'a.py')
+        
+        module = imp.load_module('a', open(pathname),
+                                 'invalid_path_name', ('.py', 'r', imp.PY_SOURCE))
+        assert module.__name__ == 'a'
+        assert module.__file__ == 'invalid_path_name'
+
 
 class TestAbi:
     def test_abi_tag(self):
@@ -783,11 +795,10 @@
         pathname = _testfilesource()
         stream = streamio.open_file_as_stream(pathname, "r")
         try:
-            w_ret = importing.load_source_module(space,
-                                                 w_modulename,
-                                                 w_mod,
-                                                 pathname,
-                                                 stream.readall())
+            w_ret = importing.load_source_module(
+                space, w_modulename, w_mod,
+                pathname, stream.readall(),
+                stream.try_to_find_file_descriptor())
         finally:
             stream.close()
         assert w_mod is w_ret
@@ -806,12 +817,11 @@
         pathname = _testfilesource()
         stream = streamio.open_file_as_stream(pathname, "r")
         try:
-            w_ret = importing.load_source_module(space,
-                                                 w_modulename,
-                                                 w_mod,
-                                                 pathname,
-                                                 stream.readall(),
-                                                 write_pyc=False)
+            w_ret = importing.load_source_module(
+                space, w_modulename, w_mod,
+                pathname, stream.readall(),
+                stream.try_to_find_file_descriptor(),
+                write_pyc=False)
         finally:
             stream.close()
         cpathname = udir.join('test.pyc')
@@ -826,11 +836,10 @@
         try:
             space.setattr(space.sys, space.wrap('dont_write_bytecode'),
                           space.w_True)
-            w_ret = importing.load_source_module(space,
-                                                 w_modulename,
-                                                 w_mod,
-                                                 pathname,
-                                                 stream.readall())
+            w_ret = importing.load_source_module(
+                space, w_modulename, w_mod,
+                pathname, stream.readall(),
+                stream.try_to_find_file_descriptor())
         finally:
             space.setattr(space.sys, space.wrap('dont_write_bytecode'),
                           space.w_False)
@@ -846,11 +855,10 @@
         pathname = _testfilesource(source="<Syntax Error>")
         stream = streamio.open_file_as_stream(pathname, "r")
         try:
-            w_ret = importing.load_source_module(space,
-                                                 w_modulename,
-                                                 w_mod,
-                                                 pathname,
-                                                 stream.readall())
+            w_ret = importing.load_source_module(
+                space, w_modulename, w_mod,
+                pathname, stream.readall(),
+                stream.try_to_find_file_descriptor())
         except OperationError:
             # OperationError("Syntax Error")
             pass
@@ -867,11 +875,10 @@
         pathname = _testfilesource(source="a = unknown_name")
         stream = streamio.open_file_as_stream(pathname, "r")
         try:
-            w_ret = importing.load_source_module(space,
-                                                 w_modulename,
-                                                 w_mod,
-                                                 pathname,
-                                                 stream.readall())
+            w_ret = importing.load_source_module(
+                space, w_modulename, w_mod,
+                pathname, stream.readall(),
+                stream.try_to_find_file_descriptor())
         except OperationError:
             # OperationError("NameError", "global name 'unknown_name' is not defined")
             pass
diff --git a/pypy/module/test_lib_pypy/ctypes_tests/test_numbers.py b/pypy/module/test_lib_pypy/ctypes_tests/test_numbers.py
--- a/pypy/module/test_lib_pypy/ctypes_tests/test_numbers.py
+++ b/pypy/module/test_lib_pypy/ctypes_tests/test_numbers.py
@@ -187,6 +187,14 @@
         # probably be changed:
         raises(TypeError, c_int, c_long(42))
 
+    def test_subclass(self):
+        class enum(c_int):
+            def __new__(cls, value):
+                dont_call_me
+        class S(Structure):
+            _fields_ = [('t', enum)]
+        assert isinstance(S().t, enum)
+
 ##    def test_perf(self):
 ##        check_perf()
 
diff --git a/pypy/module/test_lib_pypy/test_greenlet.py b/pypy/module/test_lib_pypy/test_greenlet.py
--- a/pypy/module/test_lib_pypy/test_greenlet.py
+++ b/pypy/module/test_lib_pypy/test_greenlet.py
@@ -134,6 +134,40 @@
         res = g1.switch()
         assert res == "ok"
 
+    def test_throw_GreenletExit(self):
+        from greenlet import greenlet
+        gmain = greenlet.getcurrent()
+        l = [0]
+        #
+        def func():
+            l[0] += 1
+            gmain.switch()
+            l[0] += 1
+        #
+        g = greenlet(func)
+        g.switch()
+        assert l[0] == 1
+        g.throw()
+        assert l[0] == 1
+
+    def test_throw_GreenletExit_result(self):
+        from greenlet import greenlet
+        gmain = greenlet.getcurrent()
+        l = [0]
+        #
+        def func():
+            l[0] += 1
+            gmain.switch()
+            l[0] += 1
+        #
+        g = greenlet(func)
+        g.switch()
+        assert l[0] == 1
+        ge1 = greenlet.GreenletExit(1, 2, 3)
+        ge2 = g.throw(ge1)
+        assert l[0] == 1
+        assert ge1 is ge2
+
     def test_nondefault_parent(self):
         from greenlet import greenlet
         #
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
@@ -4,10 +4,12 @@
 from pypy.interpreter.error import OperationError
 from pypy.interpreter import pyframe, nestedscope
 from pypy.interpreter.argument import ArgumentsForTranslation
+from pypy.interpreter.astcompiler.consts import CO_GENERATOR
+from pypy.interpreter.pycode import PyCode, cpython_code_signature
 from pypy.objspace.flow import operation
 from pypy.objspace.flow.model import *
-from pypy.objspace.flow.framestate import FrameState
-from pypy.rlib import jit
+from pypy.objspace.flow.framestate import (FrameState, recursively_unflatten,
+        recursively_flatten)
 from pypy.tool.stdlib_opcode import host_bytecode_spec
 
 class StopFlowing(Exception):
@@ -28,13 +30,6 @@
         self.framestate = framestate
         self.dead = False
 
-    def patchframe(self, frame):
-        if self.dead:
-            raise StopFlowing
-        self.framestate.restoreframe(frame)
-        return BlockRecorder(self)
-
-
 class EggBlock(Block):
     # make slots optional, for debugging
     if hasattr(Block, '__slots__'):
@@ -45,21 +40,6 @@
         self.prevblock = prevblock
         self.booloutcome = booloutcome
 
-    def patchframe(self, frame):
-        parentblocks = []
-        block = self
-        while isinstance(block, EggBlock):
-            block = block.prevblock
-            parentblocks.append(block)
-        # parentblocks = [Egg, Egg, ..., Egg, Spam] not including self
-        block.patchframe(frame)
-        recorder = BlockRecorder(self)
-        prevblock = self
-        for block in parentblocks:
-            recorder = Replayer(block, prevblock.booloutcome, recorder)
-            prevblock = block
-        return recorder
-
     def extravars(self, last_exception=None, last_exc_value=None):
         self.last_exception = last_exception
 
@@ -93,7 +73,6 @@
         self.crnt_block.operations.append(operation)
 
     def bytecode_trace(self, ec, frame):
-        assert frame is ec.crnt_frame, "seeing an unexpected frame!"
         ec.crnt_offset = frame.last_instr      # save offset for opcode
         if self.enterspamblock:
             # If we have a SpamBlock, the first call to bytecode_trace()
@@ -110,7 +89,7 @@
             # 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 = FrameState(frame)
+            self.last_join_point = frame.getstate()
 
     def guessbool(self, ec, w_condition, cases=[False,True],
                   replace_last_variable_except_in_first_case = None):
@@ -184,43 +163,24 @@
 
 class FlowExecutionContext(ExecutionContext):
 
-    def __init__(self, space, code, globals, constargs={}, outer_func=None,
-                 name=None, is_generator=False):
-        ExecutionContext.__init__(self, space)
-        self.code = code
-
-        self.w_globals = w_globals = space.wrap(globals)
-
-        self.crnt_offset = -1
-        self.crnt_frame = None
-        if outer_func and outer_func.closure:
-            self.closure = [nestedscope.Cell(Constant(value))
-                            for value in outer_func.closure]
-        else:
-            self.closure = None
-        frame = self.create_frame()
-        formalargcount = code.getformalargcount()
-        arg_list = [Variable() for i in range(formalargcount)]
-        for position, value in constargs.items():
-            arg_list[position] = Constant(value)
-        frame.setfastscope(arg_list)
-        self.joinpoints = {}
-        initialblock = SpamBlock(FrameState(frame).copy())
-        self.pendingblocks = collections.deque([initialblock])
-        self.graph = FunctionGraph(name or code.co_name, initialblock)
-        self.is_generator = is_generator
+    def _init_graph(self, func, initialblock):
+        # 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, '_')
+        self.graph = 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.code.signature()
+        graph.defaults = func.func_defaults or ()
 
     make_link = Link # overridable for transition tracking
 
-    def create_frame(self):
-        # create an empty frame suitable for the code object
-        # while ignoring any operation like the creation of the locals dict
-        self.recorder = []
-        frame = FlowSpaceFrame(self.space, self.code,
-                               self.w_globals, self)
-        frame.last_instr = 0
-        return frame
-
     def bytecode_trace(self, frame):
         self.recorder.bytecode_trace(self, frame)
 
@@ -247,33 +207,40 @@
                 w_exc_cls = egg.last_exception
         return outcome, w_exc_cls, w_exc_value
 
-    def build_flow(self):
+    def build_flow(self, func, constargs={}):
+        space = self.space
+        code = PyCode._from_code(space, func.func_code)
+        self.is_generator = bool(code.co_flags & CO_GENERATOR)
+        self.code = code
+
+        self.crnt_offset = -1
+        self.frame = frame = FlowSpaceFrame(self.space, code,
+                               func, constargs)
+        self.joinpoints = {}
+        initialblock = SpamBlock(frame.getstate())
+        self.pendingblocks = collections.deque([initialblock])
+        self._init_graph(func, initialblock)
+
         if self.is_generator:
-            self.produce_generator_mark()
+            initialblock.operations.append(
+                SpaceOperation('generator_mark', [], Variable()))
+
         while self.pendingblocks:
             block = self.pendingblocks.popleft()
-            frame = self.create_frame()
             try:
-                self.recorder = block.patchframe(frame)
+                self.recorder = frame.recording(block)
             except StopFlowing:
                 continue   # restarting a dead SpamBlock
             try:
-                old_frameref = self.topframeref
-                self.topframeref = jit.non_virtual_ref(frame)
-                self.crnt_frame = frame
-                try:
-                    frame.frame_finished_execution = False
-                    while True:
-                        w_result = frame.dispatch(frame.pycode,
-                                                  frame.last_instr,
-                                                  self)
-                        if frame.frame_finished_execution:
-                            break
-                        else:
-                            self.generate_yield(frame, w_result)
-                finally:
-                    self.crnt_frame = None
-                    self.topframeref = old_frameref
+                frame.frame_finished_execution = False
+                while True:
+                    w_result = frame.dispatch(frame.pycode,
+                                                frame.last_instr,
+                                                self)
+                    if frame.frame_finished_execution:
+                        break
+                    else:
+                        self.generate_yield(frame, w_result)
 
             except operation.OperationThatShouldNotBePropagatedError, e:
                 raise Exception(
@@ -316,11 +283,6 @@
             del self.recorder
         self.fixeggblocks()
 
-    def produce_generator_mark(self):
-        [initialblock] = self.pendingblocks
-        initialblock.operations.append(
-            SpaceOperation('generator_mark', [], Variable()))
-
     def generate_yield(self, frame, w_result):
         assert self.is_generator
         self.recorder.crnt_block.operations.append(
@@ -408,7 +370,7 @@
     # hack for unrolling iterables, don't use this
     def replace_in_stack(self, oldvalue, newvalue):
         w_new = Constant(newvalue)
-        f = self.crnt_frame
+        f = self.frame
         stack_items_w = f.locals_stack_w
         for i in range(f.valuestackdepth-1, f.pycode.co_nlocals-1, -1):
             w_v = stack_items_w[i]
@@ -421,6 +383,71 @@
 
 class FlowSpaceFrame(pyframe.CPythonFrame):
 
+    def __init__(self, space, code, func, constargs=None):
+        w_globals = Constant(func.func_globals)
+        class outerfunc: pass # hack
+        if func.func_closure is not None:
+            cl = [c.cell_contents for c in func.func_closure]
+            outerfunc.closure = [nestedscope.Cell(Constant(value)) for value in cl]
+        else:
+            outerfunc.closure = None
+        super(FlowSpaceFrame, self).__init__(space, code, w_globals, outerfunc)
+        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)
+
+    def getstate(self):
+        # getfastscope() can return real None, for undefined locals
+        data = self.save_locals_stack()
+        if self.last_exception is None:
+            data.append(Constant(None))
+            data.append(Constant(None))
+        else:
+            data.append(self.last_exception.w_type)
+            data.append(self.last_exception.get_w_value(self.space))
+        recursively_flatten(self.space, data)
+        nonmergeable = (self.get_blocklist(),
+            self.last_instr,   # == next_instr when between bytecodes
+            self.w_locals,)
+        return FrameState(data, nonmergeable)
+
+    def setstate(self, state):
+        """ Reset the frame to the given state. """
+        data = state.mergeable[:]
+        recursively_unflatten(self.space, data)
+        self.restore_locals_stack(data[:-2])  # Nones == undefined locals
+        if data[-2] == Constant(None):
+            assert data[-1] == Constant(None)
+            self.last_exception = None
+        else:
+            self.last_exception = OperationError(data[-2], data[-1])
+        blocklist, self.last_instr, self.w_locals = state.nonmergeable
+        self.set_blocklist(blocklist)
+
+    def recording(self, block):
+        """ Setup recording of the block and return the recorder. """
+        parentblocks = []
+        parent = block
+        while isinstance(parent, EggBlock):
+            parent = parent.prevblock
+            parentblocks.append(parent)
+        # parentblocks = [Egg, Egg, ..., Egg, Spam] not including block
+        if parent.dead:
+            raise StopFlowing
+        self.setstate(parent.framestate)
+        recorder = BlockRecorder(block)
+        prevblock = block
+        for parent in parentblocks:
+            recorder = Replayer(parent, prevblock.booloutcome, recorder)
+            prevblock = parent
+        return recorder
+
     def SETUP_WITH(self, offsettoend, next_instr):
         # A simpler version than the 'real' 2.7 one:
         # directly call manager.__enter__(), don't use special lookup functions
diff --git a/pypy/objspace/flow/framestate.py b/pypy/objspace/flow/framestate.py
--- a/pypy/objspace/flow/framestate.py
+++ b/pypy/objspace/flow/framestate.py
@@ -1,59 +1,16 @@
-from pypy.interpreter.pyframe import PyFrame
 from pypy.interpreter.pyopcode import SuspendedUnroller
-from pypy.interpreter.error import OperationError
 from pypy.rlib.unroll import SpecTag
 from pypy.objspace.flow.model import *
 
 class FrameState:
-    # XXX this class depends on the internal state of PyFrame objects
-
-    def __init__(self, state):
-        if isinstance(state, PyFrame):
-            # getfastscope() can return real None, for undefined locals
-            data = state.save_locals_stack()
-            if state.last_exception is None:
-                data.append(Constant(None))
-                data.append(Constant(None))
-            else:
-                data.append(state.last_exception.w_type)
-                data.append(state.last_exception.get_w_value(state.space))
-            recursively_flatten(state.space, data)
-            self.mergeable = data
-            self.nonmergeable = (
-                state.get_blocklist(),
-                state.last_instr,   # == next_instr when between bytecodes
-                state.w_locals,
-            )
-        elif isinstance(state, tuple):
-            self.mergeable, self.nonmergeable = state
-        else:
-            raise TypeError("can't get framestate for %r" % 
-                            state.__class__.__name__)
+    def __init__(self, mergeable, nonmergeable):
+        self.mergeable = mergeable
+        self.nonmergeable = nonmergeable
         self.next_instr = self.nonmergeable[1]
         for w1 in self.mergeable:
             assert isinstance(w1, (Variable, Constant)) or w1 is None, (
                 '%r found in frame state' % w1)
 
-    def restoreframe(self, frame):
-        if isinstance(frame, PyFrame):
-            data = self.mergeable[:]
-            recursively_unflatten(frame.space, data)
-            frame.restore_locals_stack(data[:-2])  # Nones == undefined locals
-            if data[-2] == Constant(None):
-                assert data[-1] == Constant(None)
-                frame.last_exception = None
-            else:
-                frame.last_exception = OperationError(data[-2], data[-1])
-            (
-                blocklist,
-                frame.last_instr,
-                frame.w_locals,
-            ) = self.nonmergeable
-            frame.set_blocklist(blocklist)
-        else:
-            raise TypeError("can't set framestate for %r" % 
-                            frame.__class__.__name__)
-
     def copy(self):
         "Make a copy of this state in which all Variables are fresh."
         newstate = []
@@ -61,7 +18,7 @@
             if isinstance(w, Variable):
                 w = Variable()
             newstate.append(w)
-        return FrameState((newstate, self.nonmergeable))
+        return FrameState(newstate, self.nonmergeable)
 
     def getvariables(self):
         return [w for w in self.mergeable if isinstance(w, Variable)]
@@ -94,7 +51,7 @@
                 newstate.append(union(w1, w2))
         except UnionError:
             return None
-        return FrameState((newstate, self.nonmergeable))
+        return FrameState(newstate, self.nonmergeable)
 
     def getoutputargs(self, targetstate):
         "Return the output arguments needed to link self to targetstate."
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
@@ -5,13 +5,12 @@
 import types
 from pypy.tool import error
 from pypy.interpreter.baseobjspace import ObjSpace, Wrappable
-from pypy.interpreter.pycode import PyCode, cpython_code_signature
 from pypy.interpreter.module import Module
 from pypy.interpreter.error import OperationError
-from pypy.interpreter.astcompiler.consts import CO_GENERATOR
 from pypy.interpreter import pyframe, argument
 from pypy.objspace.flow.model import *
-from pypy.objspace.flow import flowcontext, operation, specialcase
+from pypy.objspace.flow import flowcontext, operation
+from pypy.objspace.flow.specialcase import SPECIAL_CASES
 from pypy.rlib.unroll import unrolling_iterable, _unroller
 from pypy.rlib import rstackovf, rarithmetic
 from pypy.rlib.rarithmetic import is_valid_int
@@ -76,7 +75,7 @@
         for exc in [NameError, UnboundLocalError]:
             clsname = exc.__name__
             setattr(self, 'w_'+clsname, None)
-        self.specialcases = {}
+        self.specialcases = SPECIAL_CASES.copy()
         #self.make_builtins()
         #self.make_sys()
         # w_str is needed because cmp_exc_match of frames checks against it,
@@ -162,7 +161,7 @@
             if type(val) is not str:
                 raise TypeError("expected string: " + repr(w_obj))
             return val
-        return self.unwrap(w_obj)                                
+        return self.unwrap(w_obj)
 
     def float_w(self, w_obj):
         if isinstance(w_obj, Constant):
@@ -220,10 +219,6 @@
         # because it is done each time a FlowExecutionContext is built
         return None
 
-    def setup_executioncontext(self, ec):
-        self.executioncontext = ec
-        specialcase.setup(self)
-
     def exception_match(self, w_exc_type, w_check_class):
         try:
             check_class = self.unwrap(w_check_class)
@@ -260,36 +255,11 @@
         """
         if func.func_doc and func.func_doc.lstrip().startswith('NOT_RPYTHON'):
             raise Exception, "%r is tagged as NOT_RPYTHON" % (func,)
-        code = func.func_code
-        is_generator = bool(code.co_flags & CO_GENERATOR)
-        code = PyCode._from_code(self, code)
-        if func.func_closure is None:
-            cl = None
-        else:
-            cl = [extract_cell_content(c) for c in func.func_closure]
-        # 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, '_')
-        class outerfunc: # hack
-            closure = cl
-        ec = flowcontext.FlowExecutionContext(self, code, func.func_globals,
-                                              constargs, outerfunc, name,
-                                              is_generator)
-        graph = ec.graph
-        graph.func = func
-        # attach a signature and defaults to the graph
-        # so that it becomes even more interchangeable with the function
-        # itself
-        graph.signature = cpython_code_signature(code)
-        graph.defaults = func.func_defaults or ()
-        self.setup_executioncontext(ec)
+        ec = flowcontext.FlowExecutionContext(self)
+        self.executioncontext = ec
 
         try:
-            ec.build_flow()
+            ec.build_flow(func, constargs)
         except error.FlowingError, a:
             # attach additional source info to AnnotatorError
             _, _, tb = sys.exc_info()
@@ -297,12 +267,12 @@
                                                  str(a))
             e = error.FlowingError(formated)
             raise error.FlowingError, e, tb
+
+        graph = ec.graph
         checkgraph(graph)
-        #
-        if is_generator and tweak_for_generator:
+        if ec.is_generator and tweak_for_generator:
             from pypy.translator.generator import tweak_generator_graph
             tweak_generator_graph(graph)
-        #
         return graph
 
     def fixedview(self, w_tuple, expected_length=None):
@@ -325,7 +295,7 @@
                 e = OperationError(self.w_ValueError, self.w_None)
                 e.normalize_exception(self)
                 raise e
-            return [self.do_operation('getitem', w_iterable, self.wrap(i)) 
+            return [self.do_operation('getitem', w_iterable, self.wrap(i))
                         for i in range(expected_length)]
         return ObjSpace.unpackiterable(self, w_iterable, expected_length)
 
@@ -391,6 +361,11 @@
             return w_item
 
     def setitem(self, w_obj, w_key, w_val):
+        # protect us from globals write access
+        ec = self.getexecutioncontext()
+        if ec and w_obj is ec.frame.w_globals:
+            raise SyntaxError("attempt to modify global attribute %r in %r"
+                            % (w_key, ec.graph.func))
         if self.concrete_mode:
             try:
                 obj = self.unwrap_for_computation(w_obj)
@@ -400,9 +375,38 @@
                 return self.w_None
             except UnwrapException:
                 pass
-        return self.do_operation_with_implicit_exceptions('setitem', w_obj, 
+        return self.do_operation_with_implicit_exceptions('setitem', w_obj,
                                                           w_key, w_val)
 
+    def getattr(self, w_obj, w_name):
+        # handling special things like sys
+        # unfortunately this will never vanish with a unique import logic :-(
+        if w_obj in self.not_really_const:
+            const_w = self.not_really_const[w_obj]
+            if w_name not in const_w:
+                return self.do_operation_with_implicit_exceptions('getattr',
+                                                                w_obj, w_name)
+        try:
+            obj = self.unwrap_for_computation(w_obj)
+            name = self.unwrap_for_computation(w_name)
+        except UnwrapException:
+            pass
+        else:
+            try:
+                result = getattr(obj, name)
+            except Exception, e:
+                etype = e.__class__
+                msg = "generated by a constant operation:\n\t%s%r" % (
+                    'getattr', (obj, name))
+                raise operation.OperationThatShouldNotBePropagatedError(
+                    self.wrap(etype), self.wrap(msg))
+            try:
+                return self.wrap(result)
+            except WrapException:
+                pass
+        return self.do_operation_with_implicit_exceptions('getattr',
+                w_obj, w_name)
+
     def call_function(self, w_func, *args_w):
         nargs = len(args_w)
         args = argument.ArgumentsForTranslation(self, list(args_w))
@@ -487,28 +491,3 @@
                            "flow graph construction")
     w_RuntimeError = prebuilt_recursion_error = property(w_RuntimeError)
 operation.add_operations(FlowObjSpace)
-
-
-def extract_cell_content(c):
-    """Get the value contained in a CPython 'cell', as read through
-    the func_closure of a function object."""
-    try:
-        # This is simple on 2.5
-        return getattr(c, "cell_contents")
-    except AttributeError:
-        class X(object):
-            def __cmp__(self, other):
-                self.other = other
-                return 0
-            def __eq__(self, other):
-                self.other = other
-                return True
-        x = X()
-        x_cell, = (lambda: x).func_closure
-        x_cell == c
-        try:
-            return x.other    # crashes if the cell is actually empty
-        except AttributeError:
-            raise ValueError("empty cell")
-# ______________________________________________________________________
-# End of objspace.py
diff --git a/pypy/objspace/flow/operation.py b/pypy/objspace/flow/operation.py
--- a/pypy/objspace/flow/operation.py
+++ b/pypy/objspace/flow/operation.py
@@ -378,45 +378,7 @@
     setattr(fs, name, generic_operator)
 
 
-"""
-This is just a placeholder for some code I'm checking in elsewhere.
-It is provenly possible to determine constantness of certain expressions
-a little later. I introduced this a bit too early, together with tieing
-this to something being global, which was a bad idea.
-The concept is still valid, and it can  be used to force something to
-be evaluated immediately because it is supposed to be a constant.
-One good possible use of this is loop unrolling.
-This will be found in an 'experimental' folder with some use cases.
-"""
-
-def special_overrides(fs):
-    def getattr(self, w_obj, w_name):
-        # handling special things like sys
-        # unfortunately this will never vanish with a unique import logic :-(
-        if w_obj in self.not_really_const:
-            const_w = self.not_really_const[w_obj]
-            if w_name not in const_w:
-                return self.do_operation_with_implicit_exceptions('getattr',
-                                                                  w_obj, w_name)
-        return self.regular_getattr(w_obj, w_name)
-
-    fs.regular_getattr = fs.getattr
-    fs.getattr = getattr
-
-    # protect us from globals write access
-    def setitem(self, w_obj, w_key, w_val):
-        ec = self.getexecutioncontext()
-        if not (ec and w_obj is ec.w_globals):
-            return self.regular_setitem(w_obj, w_key, w_val)
-        raise SyntaxError("attempt to modify global attribute %r in %r"
-                          % (w_key, ec.graph.func))
-
-    fs.regular_setitem = fs.setitem
-    fs.setitem = setitem
-
-
 def add_operations(fs):
     """Add function operations to the flow space."""
     for line in ObjSpace.MethodTable:
         make_op(fs, *line)
-    special_overrides(fs)
diff --git a/pypy/objspace/flow/specialcase.py b/pypy/objspace/flow/specialcase.py
--- a/pypy/objspace/flow/specialcase.py
+++ b/pypy/objspace/flow/specialcase.py
@@ -19,7 +19,7 @@
     if len(args_w) > 2:
         w_loc = args_w[2]
     if len(args_w) > 3:
-        w_frm = args_w[3]   
+        w_frm = args_w[3]
     if not isinstance(w_loc, Constant):
         # import * in a function gives us the locals as Variable
         # we always forbid it as a SyntaxError
@@ -89,6 +89,9 @@
 # _________________________________________________________________________
 
 def sc_r_uint(space, r_uint, args):
+    # special case to constant-fold r_uint(32-bit-constant)
+    # (normally, the 32-bit constant is a long, and is not allowed to
+    # show up in the flow graphs at all)
     args_w, kwds_w = args.unpack()
     assert not kwds_w
     [w_value] = args_w
@@ -99,20 +102,8 @@
 def sc_we_are_translated(space, we_are_translated, args):
     return Constant(True)
 
-def setup(space):
-    # fn = pyframe.normalize_exception.get_function(space)
-    # this is now routed through the objspace, directly.
-    # space.specialcases[fn] = sc_normalize_exception
-    space.specialcases[__import__] = sc_import
-    # redirect ApplevelClass for print et al.
-    space.specialcases[ApplevelClass] = sc_applevel
-    # turn calls to built-in functions to the corresponding operation,
-    # if possible
-    for fn in OperationName:
-        space.specialcases[fn] = sc_operator
-    # special case to constant-fold r_uint(32-bit-constant)
-    # (normally, the 32-bit constant is a long, and is not allowed to
-    # show up in the flow graphs at all)
-    space.specialcases[r_uint] = sc_r_uint
-    # special case we_are_translated() to return True
-    space.specialcases[we_are_translated] = sc_we_are_translated
+SPECIAL_CASES = {__import__: sc_import, ApplevelClass: sc_applevel,
+        r_uint: sc_r_uint, we_are_translated: sc_we_are_translated}
+for fn in OperationName:
+    SPECIAL_CASES[fn] = sc_operator
+
diff --git a/pypy/objspace/flow/test/test_framestate.py b/pypy/objspace/flow/test/test_framestate.py
--- a/pypy/objspace/flow/test/test_framestate.py
+++ b/pypy/objspace/flow/test/test_framestate.py
@@ -1,14 +1,13 @@
-
-
 from py.test import raises
 from pypy.objspace.flow.model import *
-from pypy.objspace.flow.framestate import *
 from pypy.interpreter.pycode import PyCode
+from pypy.rlib.unroll import SpecTag
 from pypy.objspace.flow.objspace import FlowObjSpace
+from pypy.objspace.flow.flowcontext import FlowSpaceFrame
 
 class TestFrameState:
     def setup_class(cls):
-        cls.space = FlowObjSpace() 
+        cls.space = FlowObjSpace()
 
     def getframe(self, func):
         space = self.space
@@ -18,15 +17,9 @@
             pass
         code = func.func_code
         code = PyCode._from_code(self.space, code)
-        w_globals = Constant({}) # space.newdict()
-        frame = self.space.createframe(code, w_globals)
-
-        formalargcount = code.getformalargcount()
-        dummy = Constant(None)
-        #dummy.dummy = True
-        arg_list = ([Variable() for i in range(formalargcount)] +
-                    [dummy] * (frame.pycode.co_nlocals - formalargcount))
-        frame.setfastscope(arg_list)
+        frame = FlowSpaceFrame(space, code, func)
+        # hack the frame
+        frame.locals_stack_w[frame.pycode.co_nlocals-1] = Constant(None)
         return frame
 
     def func_simple(x):
@@ -35,55 +28,55 @@
 
     def test_eq_framestate(self):
         frame = self.getframe(self.func_simple)
-        fs1 = FrameState(frame)
-        fs2 = FrameState(frame)
+        fs1 = frame.getstate()
+        fs2 = frame.getstate()
         assert fs1 == fs2
 
     def test_neq_hacked_framestate(self):
         frame = self.getframe(self.func_simple)
-        fs1 = FrameState(frame)
+        fs1 = frame.getstate()
         frame.locals_stack_w[frame.pycode.co_nlocals-1] = Variable()
-        fs2 = FrameState(frame)
+        fs2 = frame.getstate()
         assert fs1 != fs2
 
     def test_union_on_equal_framestates(self):
         frame = self.getframe(self.func_simple)
-        fs1 = FrameState(frame)
-        fs2 = FrameState(frame)
+        fs1 = frame.getstate()
+        fs2 = frame.getstate()
         assert fs1.union(fs2) == fs1
 
     def test_union_on_hacked_framestates(self):
         frame = self.getframe(self.func_simple)
-        fs1 = FrameState(frame)
+        fs1 = frame.getstate()
         frame.locals_stack_w[frame.pycode.co_nlocals-1] = Variable()
-        fs2 = FrameState(frame)
+        fs2 = frame.getstate()
         assert fs1.union(fs2) == fs2  # fs2 is more general
         assert fs2.union(fs1) == fs2  # fs2 is more general
 
     def test_restore_frame(self):
         frame = self.getframe(self.func_simple)
-        fs1 = FrameState(frame)
+        fs1 = frame.getstate()
         frame.locals_stack_w[frame.pycode.co_nlocals-1] = Variable()
-        fs1.restoreframe(frame)
-        assert fs1 == FrameState(frame)
+        frame.setstate(fs1)
+        assert fs1 == frame.getstate()
 
     def test_copy(self):
         frame = self.getframe(self.func_simple)
-        fs1 = FrameState(frame)
+        fs1 = frame.getstate()
         fs2 = fs1.copy()
         assert fs1 == fs2
 
     def test_getvariables(self):
         frame = self.getframe(self.func_simple)
-        fs1 = FrameState(frame)
+        fs1 = frame.getstate()
         vars = fs1.getvariables()
-        assert len(vars) == 1 
+        assert len(vars) == 1
 
     def test_getoutputargs(self):
         frame = self.getframe(self.func_simple)
-        fs1 = FrameState(frame)
+        fs1 = frame.getstate()
         frame.locals_stack_w[frame.pycode.co_nlocals-1] = Variable()
-        fs2 = FrameState(frame)
+        fs2 = frame.getstate()
         outputargs = fs1.getoutputargs(fs2)
         # 'x' -> 'x' is a Variable
         # locals_w[n-1] -> locals_w[n-1] is Constant(None)
@@ -91,17 +84,17 @@
 
     def test_union_different_constants(self):
         frame = self.getframe(self.func_simple)
-        fs1 = FrameState(frame)
+        fs1 = frame.getstate()
         frame.locals_stack_w[frame.pycode.co_nlocals-1] = Constant(42)
-        fs2 = FrameState(frame)
+        fs2 = frame.getstate()
         fs3 = fs1.union(fs2)
-        fs3.restoreframe(frame)
+        frame.setstate(fs3)
         assert isinstance(frame.locals_stack_w[frame.pycode.co_nlocals-1],
                           Variable)   # generalized
 
     def test_union_spectag(self):
         frame = self.getframe(self.func_simple)
-        fs1 = FrameState(frame)
+        fs1 = frame.getstate()
         frame.locals_stack_w[frame.pycode.co_nlocals-1] = Constant(SpecTag())
-        fs2 = FrameState(frame)
+        fs2 = frame.getstate()
         assert fs1.union(fs2) is None   # UnionError
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
@@ -32,8 +32,8 @@
         if conftest.option.view:
             graph.show()
 
-    def setup_class(cls): 
-        cls.space = FlowObjSpace() 
+    def setup_class(cls):
+        cls.space = FlowObjSpace()
 
     def all_operations(self, graph):
         result = {}
@@ -77,7 +77,7 @@
         if i < 0:
             i = j
         return user_defined_function(i) + 1
-    
+
     def test_ifthenelse(self):
         x = self.codetest(self.ifthenelse)
 
@@ -96,7 +96,7 @@
     #__________________________________________________________
     def print_(i):
         print i
-    
+
     def test_print(self):
         x = self.codetest(self.print_)
 
@@ -124,7 +124,7 @@
         if i:
             i = 5
         return i
-    
+
     def test_union_hard(self):
         x = self.codetest(self.union_hard)
 
@@ -135,7 +135,7 @@
             total += i
             i = i - 1
         return total
-    
+
     def test_while_union(self):
         x = self.codetest(self.while_union)
 
@@ -145,7 +145,7 @@
         for i in lst:
             total += i
         return total
-    
+
     def test_simple_for(self):
         x = self.codetest(self.simple_for)
 
@@ -311,7 +311,7 @@
                     else:
                         found[link.exitcase] = None
         assert found == {IndexError: True, KeyError: True, Exception: None}
-    
+
     def reraiseAnything(x):
         try:
             pow(x, 5)
@@ -354,7 +354,7 @@
     #__________________________________________________________
     def raise1(msg):
         raise IndexError
-    
+
     def test_raise1(self):
         x = self.codetest(self.raise1)
         simplify_graph(x)
@@ -371,7 +371,7 @@
     #__________________________________________________________
     def raise2(msg):
         raise IndexError, msg
-    
+
     def test_raise2(self):
         x = self.codetest(self.raise2)
         # XXX can't check the shape of the graph, too complicated...
@@ -379,7 +379,7 @@
     #__________________________________________________________
     def raise3(msg):
         raise IndexError(msg)
-    
+
     def test_raise3(self):
         x = self.codetest(self.raise3)
         # XXX can't check the shape of the graph, too complicated...
@@ -387,7 +387,7 @@
     #__________________________________________________________
     def raise4(stuff):
         raise stuff
-    
+
     def test_raise4(self):
         x = self.codetest(self.raise4)
 
@@ -405,7 +405,7 @@
         except IndexError:
             return -1
         return 0
-    
+
     def test_raise_and_catch_1(self):
         x = self.codetest(self.raise_and_catch_1)
 
@@ -416,7 +416,7 @@
         except IndexError:
             return -1
         return 0
-    
+
     def test_catch_simple_call(self):
         x = self.codetest(self.catch_simple_call)
 
@@ -427,7 +427,7 @@
         except (IndexError, OSError):
             return -1
         return 0
-    
+
     def test_multiple_catch_simple_call(self):
         graph = self.codetest(self.multiple_catch_simple_call)
         simplify_graph(graph)
@@ -447,7 +447,7 @@
         del x
         for i in range(10):
             pass
-    
+
     def test_dellocal(self):
         x = self.codetest(self.dellocal)
 
@@ -456,7 +456,7 @@
         x = DATA['x']
         z = DATA[name]
         return x, z
-    
+
     def test_globalconstdict(self):
         x = self.codetest(self.globalconstdict)
 
@@ -464,12 +464,12 @@
     def dictliteral(name):
         x = {'x': 1}
         return x
-    
+
     def test_dictliteral(self):
         x = self.codetest(self.dictliteral)
 
     #__________________________________________________________
-    
+
     def specialcases(x):
         operator.lt(x,3)
         operator.le(x,3)
@@ -488,7 +488,7 @@
         # the following ones are constant-folded
         operator.eq(2,3)
         operator.__gt__(2,3)
-    
+
     def test_specialcases(self):
         x = self.codetest(self.specialcases)
         from pypy.translator.simplify import join_blocks
@@ -765,7 +765,7 @@
                 raise
         graph = self.codetest(f)
         simplify_graph(graph)
-        assert self.all_operations(graph) == {'getitem_idx': 1}        
+        assert self.all_operations(graph) == {'getitem_idx': 1}
 
         def f(c, x):
             try:
@@ -775,7 +775,7 @@
         graph = self.codetest(f)
         simplify_graph(graph)
         assert self.all_operations(graph) == {'getitem_key': 1}
-        
+
         def f(c, x):
             try:
                 return c[x]
@@ -794,7 +794,7 @@
         simplify_graph(graph)
         self.show(graph)
         assert self.all_operations(graph) == {'getitem_idx_key': 1}
-        
+
         def f(c, x):
             try:
                 return c[x]
@@ -812,7 +812,7 @@
         graph = self.codetest(f)
         simplify_graph(graph)
         assert self.all_operations(graph) == {'getitem_key': 1}
-  
+
         def f(c, x):
             try:
                 return c[x]
@@ -1004,14 +1004,3 @@
 
 def user_defined_function():
     pass
-
-
-def test_extract_cell_content():
-    class Strange(object):
-        def __cmp__(self, other):
-            assert False, "should not be called"
-    strange = Strange()
-    def f():
-        return strange
-    res = objspace.extract_cell_content(f.func_closure[0])
-    assert res is strange
diff --git a/pypy/rlib/rmarshal.py b/pypy/rlib/rmarshal.py
--- a/pypy/rlib/rmarshal.py
+++ b/pypy/rlib/rmarshal.py
@@ -9,6 +9,7 @@
 from pypy.rlib.rarithmetic import r_longlong, intmask, LONG_BIT
 from pypy.rlib.rfloat import formatd, rstring_to_float
 from pypy.rlib.unroll import unrolling_iterable
+from pypy.rlib.rstring import assert_str0
 
 class CannotMarshal(Exception):
     pass
@@ -223,12 +224,33 @@
     return readchr(loader)
 add_loader(annmodel.SomeChar(), load_single_char)
 
+def load_string_nonul(loader):
+    if readchr(loader) != TYPE_STRING:
+        raise ValueError("expected a string")
+    length = readlong(loader)
+    return assert_str0(readstr(loader, length))
+add_loader(annmodel.SomeString(can_be_None=False, no_nul=True),
+           load_string_nonul)
+
 def load_string(loader):
     if readchr(loader) != TYPE_STRING:
         raise ValueError("expected a string")
     length = readlong(loader)
     return readstr(loader, length)
-add_loader(annmodel.SomeString(can_be_None=False), load_string)
+add_loader(annmodel.SomeString(can_be_None=False, no_nul=False),
+           load_string)
+
+def load_string_or_none_nonul(loader):
+    t = readchr(loader)
+    if t == TYPE_STRING:
+        length = readlong(loader)
+        return assert_str0(readstr(loader, length))
+    elif t == TYPE_NONE:
+        return None
+    else:
+        raise ValueError("expected a string or None")
+add_loader(annmodel.SomeString(can_be_None=True, no_nul=True),
+           load_string_or_none_nonul)
 
 def load_string_or_none(loader):
     t = readchr(loader)
@@ -239,7 +261,8 @@
         return None
     else:
         raise ValueError("expected a string or None")
-add_loader(annmodel.SomeString(can_be_None=True), load_string_or_none)
+add_loader(annmodel.SomeString(can_be_None=True, no_nul=False),
+           load_string_or_none)
 
 # ____________________________________________________________
 #
diff --git a/pypy/translator/backendopt/removeassert.py b/pypy/translator/backendopt/removeassert.py
--- a/pypy/translator/backendopt/removeassert.py
+++ b/pypy/translator/backendopt/removeassert.py
@@ -41,7 +41,19 @@
                 log.removeassert("removed %d asserts in %s" % (count, graph.name))
             checkgraph(graph)
             #transform_dead_op_vars(graph, translator)
-    log.removeassert("Could not remove %d asserts, but removed %d asserts." % tuple(total_count))
+    total_count = tuple(total_count)
+    if total_count[0] == 0:
+        if total_count[1] == 0:
+            msg = None
+        else:
+            msg = "Removed %d asserts" % (total_count[1],)
+    else:
+        if total_count[1] == 0:
+            msg = "Could not remove %d asserts" % (total_count[0],)
+        else:
+            msg = "Could not remove %d asserts, but removed %d asserts." % total_count
+    if msg is not None:
+        log.removeassert(msg)
 
 
 def kill_assertion_link(graph, link):
diff --git a/pypy/translator/sandbox/test/test_sandbox.py b/pypy/translator/sandbox/test/test_sandbox.py
--- a/pypy/translator/sandbox/test/test_sandbox.py
+++ b/pypy/translator/sandbox/test/test_sandbox.py
@@ -21,7 +21,8 @@
         g.flush()
 
 def compile(f, gc='ref'):
-    t = Translation(f, backend='c', standalone=True, sandbox=True, gc=gc)
+    t = Translation(f, backend='c', standalone=True, sandbox=True, gc=gc,
+                    check_str_without_nul=True)
     return str(t.compile())
 
 
@@ -115,6 +116,21 @@
     f.close()
     assert tail == ""
 
+def test_getcwd():
+    def entry_point(argv):
+        t = os.getcwd()
+        os.dup(len(t))
+        return 0
+
+    exe = compile(entry_point)
+    g, f = os.popen2(exe, "t", 0)
+    expect(f, g, "ll_os.ll_os_getcwd", (), "/tmp/foo/bar")
+    expect(f, g, "ll_os.ll_os_dup", (len("/tmp/foo/bar"),), 3)
+    g.close()
+    tail = f.read()
+    f.close()
+    assert tail == ""
+
 def test_oserror():
     def entry_point(argv):
         try:
diff --git a/pypy/translator/unsimplify.py b/pypy/translator/unsimplify.py
--- a/pypy/translator/unsimplify.py
+++ b/pypy/translator/unsimplify.py
@@ -102,7 +102,14 @@
                 # then it's ok to recreate its value in the target block.
                 # If not, then we have a problem :-)
                 from pypy.rpython.lltypesystem import lltype
-                assert v.concretetype is lltype.Void
+                if v.concretetype is not lltype.Void:
+                    raise Exception(
+                        "The variable %r of type %r was not explicitly listed"
+                        " in _forcelink.  This issue can be caused by a"
+                        " jitdriver.jit_merge_point() where some variable"
+                        " containing an int or str or instance is actually"
+                        " known to be constant, e.g. always 42." % (
+                        v, v.concretetype))
                 c = Constant(None, lltype.Void)
                 w = varmap[v]
                 newop = SpaceOperation('same_as', [c], w)


More information about the pypy-commit mailing list