Commits

Armin Rigo  committed 1ed8b5b Draft Merge

Merged in rlamy/pypy/translation-cleanup (pull request #82)

  • Participants
  • Parent commits 0cf0134, 0a90d88

Comments (0)

Files changed (7)

File pypy/objspace/flow/flowcontext.py

 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):
         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__'):
         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
 
         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()
             # 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):
 
 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)
 
                 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(
             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(
     # 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]
 
 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

File pypy/objspace/flow/framestate.py

-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 = []
             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)]
                 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."

File pypy/objspace/flow/objspace.py

 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
         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,
             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):
         # 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)
         """
         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()
                                                  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):
                 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)
 
             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)
                 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))
                            "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

File pypy/objspace/flow/operation.py

     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)

File pypy/objspace/flow/specialcase.py

     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
 # _________________________________________________________________________
 
 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
 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
+

File pypy/objspace/flow/test/test_framestate.py

-
-
 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
             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):
 
     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)
 
     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

File pypy/objspace/flow/test/test_objspace.py

         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 = {}
         if i < 0:
             i = j
         return user_defined_function(i) + 1
-    
+
     def test_ifthenelse(self):
         x = self.codetest(self.ifthenelse)
 
     #__________________________________________________________
     def print_(i):
         print i
-    
+
     def test_print(self):
         x = self.codetest(self.print_)
 
         if i:
             i = 5
         return i
-    
+
     def test_union_hard(self):
         x = self.codetest(self.union_hard)
 
             total += i
             i = i - 1
         return total
-    
+
     def test_while_union(self):
         x = self.codetest(self.while_union)
 
         for i in lst:
             total += i
         return total
-    
+
     def test_simple_for(self):
         x = self.codetest(self.simple_for)
 
                     else:
                         found[link.exitcase] = None
         assert found == {IndexError: True, KeyError: True, Exception: None}
-    
+
     def reraiseAnything(x):
         try:
             pow(x, 5)
     #__________________________________________________________
     def raise1(msg):
         raise IndexError
-    
+
     def test_raise1(self):
         x = self.codetest(self.raise1)
         simplify_graph(x)
     #__________________________________________________________
     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...
     #__________________________________________________________
     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...
     #__________________________________________________________
     def raise4(stuff):
         raise stuff
-    
+
     def test_raise4(self):
         x = self.codetest(self.raise4)
 
         except IndexError:
             return -1
         return 0
-    
+
     def test_raise_and_catch_1(self):
         x = self.codetest(self.raise_and_catch_1)
 
         except IndexError:
             return -1
         return 0
-    
+
     def test_catch_simple_call(self):
         x = self.codetest(self.catch_simple_call)
 
         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)
         del x
         for i in range(10):
             pass
-    
+
     def test_dellocal(self):
         x = self.codetest(self.dellocal)
 
         x = DATA['x']
         z = DATA[name]
         return x, z
-    
+
     def test_globalconstdict(self):
         x = self.codetest(self.globalconstdict)
 
     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)
         # 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
                 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:
         graph = self.codetest(f)
         simplify_graph(graph)
         assert self.all_operations(graph) == {'getitem_key': 1}
-        
+
         def f(c, x):
             try:
                 return c[x]
         simplify_graph(graph)
         self.show(graph)
         assert self.all_operations(graph) == {'getitem_idx_key': 1}
-        
+
         def f(c, x):
             try:
                 return c[x]
         graph = self.codetest(f)
         simplify_graph(graph)
         assert self.all_operations(graph) == {'getitem_key': 1}
-  
+
         def f(c, x):
             try:
                 return c[x]
 
 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