Author: arigo <[email protected]>
Branch: 
Changeset: r57021:97e1d2c15876
Date: 2012-08-30 18:37 +0200
http://bitbucket.org/pypy/pypy/changeset/97e1d2c15876/

Log:    Merged in rlamy/pypy/translation-cleanup (pull request #83)

diff --git a/pypy/annotation/policy.py b/pypy/annotation/policy.py
--- a/pypy/annotation/policy.py
+++ b/pypy/annotation/policy.py
@@ -27,11 +27,6 @@
             callback()
         del annotator.bookkeeper.pending_specializations[:]
 
-    def _adjust_space_config(self, space):
-        # allow to override space options.
-        if getattr(self, 'do_imports_immediately', None) is not None:
-            space.do_imports_immediately = self.do_imports_immediately
-
 class AnnotatorPolicy(BasicAnnotatorPolicy):
     """
     Possibly subclass and pass an instance to the annotator to control special 
casing during annotation
@@ -67,7 +62,7 @@
                 def specialize_with_parms(funcdesc, args_s):
                     return specializer(funcdesc, args_s, *parms)
                 return specialize_with_parms
-        
+
     # common specializations
 
     default_specialize = staticmethod(default)
diff --git a/pypy/interpreter/pycode.py b/pypy/interpreter/pycode.py
--- a/pypy/interpreter/pycode.py
+++ b/pypy/interpreter/pycode.py
@@ -19,6 +19,10 @@
 from pypy.rlib.objectmodel import compute_hash
 from pypy.tool.stdlib_opcode import opcodedesc, HAVE_ARGUMENT
 
+
+class BytecodeCorruption(Exception):
+    """Detected bytecode corruption.  Never caught; it's an error."""
+
 # helper
 
 def unpack_str_tuple(space,w_str_tuple):
diff --git a/pypy/interpreter/pyopcode.py b/pypy/interpreter/pyopcode.py
--- a/pypy/interpreter/pyopcode.py
+++ b/pypy/interpreter/pyopcode.py
@@ -8,7 +8,7 @@
 from pypy.interpreter.error import OperationError, operationerrfmt
 from pypy.interpreter.baseobjspace import Wrappable
 from pypy.interpreter import gateway, function, eval, pyframe, pytraceback
-from pypy.interpreter.pycode import PyCode
+from pypy.interpreter.pycode import PyCode, BytecodeCorruption
 from pypy.tool.sourcetools import func_with_new_name
 from pypy.rlib.objectmodel import we_are_translated
 from pypy.rlib import jit, rstackovf
@@ -1172,9 +1172,6 @@
     def __init__(self, operr):
         self.operr = operr
 
-class BytecodeCorruption(Exception):
-    """Detected bytecode corruption.  Never caught; it's an error."""
-
 
 ### Frame Blocks ###
 
diff --git a/pypy/objspace/flow/bytecode.py b/pypy/objspace/flow/bytecode.py
new file mode 100644
--- /dev/null
+++ b/pypy/objspace/flow/bytecode.py
@@ -0,0 +1,47 @@
+"""
+Bytecode handling classes and functions for use by the flow space.
+"""
+from pypy.interpreter.pycode import PyCode, BytecodeCorruption
+from pypy.tool.stdlib_opcode import (host_bytecode_spec, EXTENDED_ARG,
+        HAVE_ARGUMENT)
+from pypy.interpreter.astcompiler.consts import CO_GENERATOR
+
+class HostCode(PyCode):
+    """
+    A wrapper around a native code object of the host interpreter
+    """
+    opnames = host_bytecode_spec.method_names
+
+    def read(self, pos):
+        """
+        Decode the instruction starting at position ``next_instr``.
+
+        Returns (next_instr, opname, oparg).
+        """
+        co_code = self.co_code
+        opcode = ord(co_code[pos])
+        next_instr = pos + 1
+
+        if opcode >= HAVE_ARGUMENT:
+            lo = ord(co_code[next_instr])
+            hi = ord(co_code[next_instr+1])
+            next_instr += 2
+            oparg = (hi * 256) | lo
+        else:
+            oparg = 0
+
+        while opcode == EXTENDED_ARG:
+            opcode = ord(co_code[next_instr])
+            if opcode < HAVE_ARGUMENT:
+                raise BytecodeCorruption
+            lo = ord(co_code[next_instr+1])
+            hi = ord(co_code[next_instr+2])
+            next_instr += 3
+            oparg = (oparg * 65536) | (hi * 256) | lo
+
+        opname = self.opnames[opcode]
+        return next_instr, opname, oparg
+
+    @property
+    def is_generator(self):
+        return bool(self.co_flags & CO_GENERATOR)
diff --git a/pypy/objspace/flow/flowcontext.py 
b/pypy/objspace/flow/flowcontext.py
--- a/pypy/objspace/flow/flowcontext.py
+++ b/pypy/objspace/flow/flowcontext.py
@@ -1,16 +1,22 @@
 import collections
 import sys
+from pypy.tool.error import FlowingError
 from pypy.interpreter.executioncontext import ExecutionContext
 from pypy.interpreter.error import OperationError
-from pypy.interpreter import pyframe, nestedscope
+from pypy.interpreter.pytraceback import PyTraceback
+from pypy.interpreter import pyframe
+from pypy.interpreter.nestedscope import Cell
+from pypy.interpreter.pycode import CO_OPTIMIZED, CO_NEWLOCALS
 from pypy.interpreter.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.interpreter.pyopcode import (Return, Yield, SuspendedUnroller,
+        SReturnValue, SApplicationException, BytecodeCorruption, Reraise,
+        RaiseWithExplicitTraceback)
+from pypy.objspace.flow.operation import (ImplicitOperationError,
+        OperationThatShouldNotBePropagatedError)
 from pypy.objspace.flow.model import *
 from pypy.objspace.flow.framestate import (FrameState, recursively_unflatten,
         recursively_flatten)
-from pypy.tool.stdlib_opcode import host_bytecode_spec
+from pypy.objspace.flow.bytecode import HostCode
 
 class StopFlowing(Exception):
     pass
@@ -50,7 +56,7 @@
     def append(self, operation):
         raise NotImplementedError
 
-    def bytecode_trace(self, ec, frame):
+    def bytecode_trace(self, frame):
         pass
 
     def guessbool(self, ec, w_condition, **kwds):
@@ -72,8 +78,7 @@
             raise MergeBlock(self.crnt_block, self.last_join_point)
         self.crnt_block.operations.append(operation)
 
-    def bytecode_trace(self, ec, frame):
-        ec.crnt_offset = frame.last_instr      # save offset for opcode
+    def bytecode_trace(self, frame):
         if self.enterspamblock:
             # If we have a SpamBlock, the first call to bytecode_trace()
             # occurs as soon as frame.resume() starts, before interpretation
@@ -150,39 +155,15 @@
         ec.recorder = self.nextreplayer
         return self.booloutcome
 
-
-class ConcreteNoOp(Recorder):
-    # In "concrete mode", no SpaceOperations between Variables are allowed.
-    # Concrete mode is used to precompute lazily-initialized caches,
-    # when we don't want this precomputation to show up on the flow graph.
-    def append(self, operation):
-        raise AssertionError, "concrete mode: cannot perform %s" % operation
-
 # ____________________________________________________________
 
 
 class FlowExecutionContext(ExecutionContext):
 
-    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 bytecode_trace(self, frame):
-        self.recorder.bytecode_trace(self, frame)
+    # disable superclass method
+    bytecode_trace = None
 
     def guessbool(self, w_condition, **kwds):
         return self.recorder.guessbool(self, w_condition, **kwds)
@@ -209,46 +190,21 @@
 
     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.frame = frame = FlowSpaceFrame(self.space, func, constargs)
         self.joinpoints = {}
-        initialblock = SpamBlock(frame.getstate())
-        self.pendingblocks = collections.deque([initialblock])
-        self._init_graph(func, initialblock)
-
-        if self.is_generator:
-            initialblock.operations.append(
-                SpaceOperation('generator_mark', [], Variable()))
+        self.graph = frame._init_graph(func)
+        self.pendingblocks = collections.deque([self.graph.startblock])
 
         while self.pendingblocks:
             block = self.pendingblocks.popleft()
             try:
                 self.recorder = frame.recording(block)
-            except StopFlowing:
-                continue   # restarting a dead SpamBlock
-            try:
                 frame.frame_finished_execution = False
+                next_instr = frame.last_instr
                 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)
+                    next_instr = frame.handle_bytecode(next_instr)
 
-            except operation.OperationThatShouldNotBePropagatedError, e:
-                raise Exception(
-                    'found an operation that always raises %s: %s' % (
-                        self.space.unwrap(e.w_type).__name__,
-                        self.space.unwrap(e.get_w_value(self.space))))
-
-            except operation.ImplicitOperationError, e:
+            except ImplicitOperationError, e:
                 if isinstance(e.w_type, Constant):
                     exc_cls = e.w_type.value
                 else:
@@ -260,11 +216,9 @@
                 self.recorder.crnt_block.closeblock(link)
 
             except OperationError, e:
-                #print "OE", e.w_type, e.get_w_value(self.space)
-                if (self.space.do_imports_immediately and
-                    e.w_type is self.space.w_ImportError):
-                    raise ImportError('import statement always raises %s' % (
-                        e,))
+                if e.w_type is self.space.w_ImportError:
+                    msg = 'import statement always raises %s' % e
+                    raise ImportError(msg)
                 w_value = e.get_w_value(self.space)
                 link = self.make_link([e.w_type, w_value], 
self.graph.exceptblock)
                 self.recorder.crnt_block.closeblock(link)
@@ -275,23 +229,15 @@
             except MergeBlock, e:
                 self.mergeblock(e.block, e.currentstate)
 
-            else:
+            except Return:
+                w_result = frame.popvalue()
                 assert w_result is not None
                 link = self.make_link([w_result], self.graph.returnblock)
                 self.recorder.crnt_block.closeblock(link)
 
-            del self.recorder
+        del self.recorder
         self.fixeggblocks()
 
-    def generate_yield(self, frame, w_result):
-        assert self.is_generator
-        self.recorder.crnt_block.operations.append(
-            SpaceOperation('yield', [w_result], Variable()))
-        # we must push a dummy value that will be POPped: it's the .send()
-        # passed into the generator (2.5 feature)
-        assert sys.version_info >= (2, 5)
-        frame.pushvalue(None)
-        frame.last_instr += 1
 
     def fixeggblocks(self):
         # EggBlocks reuse the variables of their previous block,
@@ -358,15 +304,12 @@
             self.pendingblocks.append(newblock)
 
     def _convert_exc(self, operr):
-        if isinstance(operr, operation.ImplicitOperationError):
+        if isinstance(operr, ImplicitOperationError):
             # re-raising an implicit operation makes it an explicit one
             w_value = operr.get_w_value(self.space)
             operr = OperationError(operr.w_type, w_value)
         return operr
 
-    def exception_trace(self, frame, operationerr):
-        pass    # overridden for performance only
-
     # hack for unrolling iterables, don't use this
     def replace_in_stack(self, oldvalue, newvalue):
         w_new = Constant(newvalue)
@@ -383,15 +326,22 @@
 
 class FlowSpaceFrame(pyframe.CPythonFrame):
 
-    def __init__(self, space, code, func, constargs=None):
-        w_globals = Constant(func.func_globals)
-        class outerfunc: pass # hack
+    def __init__(self, space, func, constargs=None):
+        code = HostCode._from_code(space, func.func_code)
+        self.pycode = code
+        self.space = space
+        self.w_globals = Constant(func.func_globals)
+        self.locals_stack_w = [None] * (code.co_nlocals + code.co_stacksize)
+        self.valuestackdepth = code.co_nlocals
+        self.lastblock = None
+
         if func.func_closure is not None:
             cl = [c.cell_contents for c in func.func_closure]
-            outerfunc.closure = [nestedscope.Cell(Constant(value)) for value 
in cl]
+            closure = [Cell(Constant(value)) for value in cl]
         else:
-            outerfunc.closure = None
-        super(FlowSpaceFrame, self).__init__(space, code, w_globals, outerfunc)
+            closure = []
+        self.initialize_frame_scopes(closure, code)
+        self.f_lineno = code.co_firstlineno
         self.last_instr = 0
 
         if constargs is None:
@@ -402,6 +352,40 @@
             arg_list[position] = Constant(value)
         self.setfastscope(arg_list)
 
+        self.w_locals = None # XXX: only for compatibility with PyFrame
+
+    def initialize_frame_scopes(self, closure, code):
+        if not (code.co_flags & CO_NEWLOCALS):
+            raise ValueError("The code object for a function should have "
+                    "the flag CO_NEWLOCALS set.")
+        if len(closure) != len(code.co_freevars):
+            raise ValueError("code object received a closure with "
+                                 "an unexpected number of free variables")
+        self.cells = [Cell() for _ in code.co_cellvars] + closure
+
+    def _init_graph(self, func):
+        # CallableFactory.pycall may add class_ to functions that are methods
+        name = func.func_name
+        class_ = getattr(func, 'class_', None)
+        if class_ is not None:
+            name = '%s.%s' % (class_.__name__, name)
+        for c in "<>&!":
+            name = name.replace(c, '_')
+
+        initialblock = SpamBlock(self.getstate())
+        if self.pycode.is_generator:
+            initialblock.operations.append(
+                SpaceOperation('generator_mark', [], Variable()))
+        graph = FunctionGraph(name, initialblock)
+        graph.func = func
+        # attach a signature and defaults to the graph
+        # so that it becomes even more interchangeable with the function
+        # itself
+        graph.signature = self.pycode.signature()
+        graph.defaults = func.func_defaults or ()
+        graph.is_generator = self.pycode.is_generator
+        return graph
+
     def getstate(self):
         # getfastscope() can return real None, for undefined locals
         data = self.save_locals_stack()
@@ -413,8 +397,7 @@
             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,)
+            self.last_instr)   # == next_instr when between bytecodes
         return FrameState(data, nonmergeable)
 
     def setstate(self, state):
@@ -427,7 +410,7 @@
             self.last_exception = None
         else:
             self.last_exception = OperationError(data[-2], data[-1])
-        blocklist, self.last_instr, self.w_locals = state.nonmergeable
+        blocklist, self.last_instr = state.nonmergeable
         self.set_blocklist(blocklist)
 
     def recording(self, block):
@@ -448,6 +431,105 @@
             prevblock = parent
         return recorder
 
+    def handle_bytecode(self, next_instr):
+        try:
+            next_instr = self.dispatch_bytecode(next_instr)
+        except OperationThatShouldNotBePropagatedError, e:
+            raise Exception(
+                'found an operation that always raises %s: %s' % (
+                    self.space.unwrap(e.w_type).__name__,
+                    self.space.unwrap(e.get_w_value(self.space))))
+        except OperationError, operr:
+            self.attach_traceback(operr)
+            next_instr = self.handle_operation_error(operr)
+        except Reraise:
+            operr = self.last_exception
+            next_instr = self.handle_operation_error(operr)
+        except RaiseWithExplicitTraceback, e:
+            next_instr = self.handle_operation_error(e.operr)
+        return next_instr
+
+    def attach_traceback(self, operr):
+        if self.pycode.hidden_applevel:
+            return
+        tb = operr.get_traceback()
+        tb = PyTraceback(self.space, self, self.last_instr, tb)
+        operr.set_traceback(tb)
+
+    def handle_operation_error(self, operr):
+        block = self.unrollstack(SApplicationException.kind)
+        if block is None:
+            # no handler found for the OperationError
+            # try to preserve the CPython-level traceback
+            import sys
+            tb = sys.exc_info()[2]
+            raise OperationError, operr, tb
+        else:
+            unroller = SApplicationException(operr)
+            next_instr = block.handle(self, unroller)
+            return next_instr
+
+    def enter_bytecode(self, next_instr):
+        self.last_instr = next_instr
+        self.space.executioncontext.recorder.bytecode_trace(self)
+
+    def dispatch_bytecode(self, next_instr):
+        while True:
+            self.enter_bytecode(next_instr)
+            next_instr, methodname, oparg = self.pycode.read(next_instr)
+            res = getattr(self, methodname)(oparg, next_instr)
+            if res is not None:
+                next_instr = res
+
+    def IMPORT_NAME(self, nameindex, next_instr):
+        space = self.space
+        modulename = self.getname_u(nameindex)
+        glob = space.unwrap(self.w_globals)
+        fromlist = space.unwrap(self.popvalue())
+        level = self.popvalue().value
+        w_obj = space.import_name(modulename, glob, None, fromlist, level)
+        self.pushvalue(w_obj)
+
+    def IMPORT_FROM(self, nameindex, next_instr):
+        w_name = self.getname_w(nameindex)
+        w_module = self.peekvalue()
+        self.pushvalue(self.space.import_from(w_module, w_name))
+
+    def RETURN_VALUE(self, oparg, next_instr):
+        w_returnvalue = self.popvalue()
+        block = self.unrollstack(SReturnValue.kind)
+        if block is None:
+            self.pushvalue(w_returnvalue)   # XXX ping pong
+            raise Return
+        else:
+            unroller = SReturnValue(w_returnvalue)
+            next_instr = block.handle(self, unroller)
+            return next_instr    # now inside a 'finally' block
+
+    def END_FINALLY(self, oparg, next_instr):
+        unroller = self.end_finally()
+        if isinstance(unroller, SuspendedUnroller):
+            # go on unrolling the stack
+            block = self.unrollstack(unroller.kind)
+            if block is None:
+                w_result = unroller.nomoreblocks()
+                self.pushvalue(w_result)
+                raise Return
+            else:
+                next_instr = block.handle(self, unroller)
+        return next_instr
+
+    def JUMP_ABSOLUTE(self, jumpto, next_instr):
+        return jumpto
+
+    def YIELD_VALUE(self, _, next_instr):
+        assert self.pycode.is_generator
+        w_result = self.popvalue()
+        self.space.do_operation('yield', w_result)
+        # XXX yield expressions not supported. This will blow up if the value
+        # isn't popped straightaway.
+        self.pushvalue(None)
+
     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
@@ -461,6 +543,10 @@
         self.lastblock = block
         self.pushvalue(w_result)
 
+    def LOAD_GLOBAL(self, nameindex, next_instr):
+        w_result = self.space.find_global(self.w_globals, 
self.getname_u(nameindex))
+        self.pushvalue(w_result)
+
     def BUILD_LIST_FROM_ARG(self, _, next_instr):
         # This opcode was added with pypy-1.8.  Here is a simpler
         # version, enough for annotation.
@@ -488,13 +574,6 @@
     def argument_factory(self, *args):
         return ArgumentsForTranslation(self.space, *args)
 
-    def handle_operation_error(self, ec, operr, *args, **kwds):
-        # see test_propagate_attribute_error for why this is here
-        if isinstance(operr, 
operation.OperationThatShouldNotBePropagatedError):
-            raise operr
-        return pyframe.PyFrame.handle_operation_error(self, ec, operr,
-                                                      *args, **kwds)
-
     def call_contextmanager_exit_function(self, w_func, w_typ, w_val, w_tb):
         if w_typ is not self.space.w_None:
             # The annotator won't allow to merge exception types with None.
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,7 +5,6 @@
 import types
 from pypy.tool import error
 from pypy.interpreter.baseobjspace import ObjSpace, Wrappable
-from pypy.interpreter.module import Module
 from pypy.interpreter.error import OperationError
 from pypy.interpreter import pyframe, argument
 from pypy.objspace.flow.model import *
@@ -47,24 +46,16 @@
     """
 
     full_exceptions = False
-    do_imports_immediately = True
     FrameClass = flowcontext.FlowSpaceFrame
 
     def initialize(self):
-        self.concrete_mode = 1
         self.w_None     = Constant(None)
-        self.builtin    = Module(self, Constant('__builtin__'),
-                                 Constant(__builtin__.__dict__))
-        def pick_builtin(w_globals):
-            return self.builtin
-        self.builtin.pick_builtin = pick_builtin
-        self.sys        = Module(self, Constant('sys'), Constant(sys.__dict__))
-        self.sys.recursionlimit = 100
+        self.builtin = Constant(__builtin__)
+        self.sys = Constant(sys)
         self.w_False    = Constant(False)
         self.w_True     = Constant(True)
         self.w_type     = Constant(type)
         self.w_tuple    = Constant(tuple)
-        self.concrete_mode = 0
         for exc in [KeyError, ValueError, IndexError, StopIteration,
                     AssertionError, TypeError, AttributeError, ImportError]:
             clsname = exc.__name__
@@ -84,18 +75,9 @@
         # objects which should keep their SomeObjectness
         self.not_really_const = NOT_REALLY_CONST
 
-    def enter_cache_building_mode(self):
-        # when populating the caches, the flow space switches to
-        # "concrete mode".  In this mode, only Constants are allowed
-        # and no SpaceOperation is recorded.
-        previous_recorder = self.executioncontext.recorder
-        self.executioncontext.recorder = flowcontext.ConcreteNoOp()
-        self.concrete_mode += 1
-        return previous_recorder
-
-    def leave_cache_building_mode(self, previous_recorder):
-        self.executioncontext.recorder = previous_recorder
-        self.concrete_mode -= 1
+    # disable superclass methods
+    enter_cache_building_mode = None
+    leave_cache_building_mode = None
 
     def is_w(self, w_one, w_two):
         return self.is_true(self.is_(w_one, w_two))
@@ -104,8 +86,6 @@
     id  = None     # real version added by add_operations()
 
     def newdict(self, module="ignored"):
-        if self.concrete_mode:
-            return Constant({})
         return self.do_operation('newdict')
 
     def newtuple(self, args_w):
@@ -117,16 +97,9 @@
             return Constant(tuple(content))
 
     def newlist(self, args_w, sizehint=None):
-        if self.concrete_mode:
-            content = [self.unwrap(w_arg) for w_arg in args_w]
-            return Constant(content)
         return self.do_operation('newlist', *args_w)
 
     def newslice(self, w_start, w_stop, w_step):
-        if self.concrete_mode:
-            return Constant(slice(self.unwrap(w_start),
-                                  self.unwrap(w_stop),
-                                  self.unwrap(w_step)))
         return self.do_operation('newslice', w_start, w_stop, w_step)
 
     def wrap(self, obj):
@@ -189,12 +162,8 @@
             hasattr(to_check, '__class__') and to_check.__class__.__module__ 
!= '__builtin__'):
             frozen = hasattr(to_check, '_freeze_') and to_check._freeze_()
             if not frozen:
-                if self.concrete_mode:
-                    # xxx do we want some warning? notice that some stuff is 
harmless
-                    # like setitem(dict, 'n', mutable)
-                    pass
-                else: # cannot count on it not mutating at runtime!
-                    raise UnwrapException
+                # cannot count on it not mutating at runtime!
+                raise UnwrapException
         return obj
 
     def interpclass_w(self, w_obj):
@@ -263,14 +232,14 @@
         except error.FlowingError, a:
             # attach additional source info to AnnotatorError
             _, _, tb = sys.exc_info()
-            formated = error.format_global_error(ec.graph, ec.crnt_offset,
+            formated = error.format_global_error(ec.graph, ec.frame.last_instr,
                                                  str(a))
             e = error.FlowingError(formated)
             raise error.FlowingError, e, tb
 
         graph = ec.graph
         checkgraph(graph)
-        if ec.is_generator and tweak_for_generator:
+        if graph.is_generator and tweak_for_generator:
             from pypy.translator.generator import tweak_generator_graph
             tweak_generator_graph(graph)
         return graph
@@ -302,9 +271,8 @@
     # ____________________________________________________________
     def do_operation(self, name, *args_w):
         spaceop = SpaceOperation(name, args_w, Variable())
-        if hasattr(self, 'executioncontext'):  # not here during bootstrapping
-            spaceop.offset = self.executioncontext.crnt_offset
-            self.executioncontext.recorder.append(spaceop)
+        spaceop.offset = self.executioncontext.frame.last_instr
+        self.executioncontext.recorder.append(spaceop)
         return spaceop.result
 
     def do_operation_with_implicit_exceptions(self, name, *args_w):
@@ -366,15 +334,6 @@
         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)
-                key = self.unwrap_for_computation(w_key)
-                val = self.unwrap_for_computation(w_val)
-                operator.setitem(obj, key, val)
-                return self.w_None
-            except UnwrapException:
-                pass
         return self.do_operation_with_implicit_exceptions('setitem', w_obj,
                                                           w_key, w_val)
 
@@ -407,6 +366,23 @@
         return self.do_operation_with_implicit_exceptions('getattr',
                 w_obj, w_name)
 
+    def import_name(self, name, glob=None, loc=None, frm=None, level=-1):
+        try:
+            mod = __import__(name, glob, loc, frm, level)
+        except ImportError, e:
+            raise OperationError(self.w_ImportError, self.wrap(str(e)))
+        return self.wrap(mod)
+
+    def import_from(self, w_module, w_name):
+        try:
+            return self.getattr(w_module, w_name)
+        except OperationError, e:
+            if e.match(self, self.w_AttributeError):
+                raise OperationError(self.w_ImportError,
+                    self.wrap("cannot import name '%s'" % w_name.value))
+            else:
+                raise
+
     def call_function(self, w_func, *args_w):
         nargs = len(args_w)
         args = argument.ArgumentsForTranslation(self, list(args_w))
@@ -477,6 +453,18 @@
                 #pass
              raise operation.ImplicitOperationError(w_exc_cls, w_exc_value)
 
+    def find_global(self, w_globals, varname):
+        try:
+            value = self.unwrap(w_globals)[varname]
+        except KeyError:
+            # not in the globals, now look in the built-ins
+            try:
+                value = getattr(self.unwrap(self.builtin), varname)
+            except AttributeError:
+                message = "global name '%s' is not defined" % varname
+                raise OperationError(self.w_NameError, self.wrap(message))
+        return self.wrap(value)
+
     def w_KeyboardInterrupt(self):
         # the reason to do this is: if you interrupt the flowing of a function
         # with <Ctrl-C> the bytecode interpreter will raise an applevel
@@ -490,4 +478,82 @@
         raise RuntimeError("the interpreter raises RuntimeError during "
                            "flow graph construction")
     w_RuntimeError = prebuilt_recursion_error = property(w_RuntimeError)
-operation.add_operations(FlowObjSpace)
+
+def make_op(name, arity):
+    """Add function operation to the flow space."""
+    if getattr(FlowObjSpace, name, None) is not None:
+        return
+
+    op = None
+    skip = False
+    arithmetic = False
+
+    if (name.startswith('del') or
+        name.startswith('set') or
+        name.startswith('inplace_')):
+        # skip potential mutators
+        skip = True
+    elif name in ('id', 'hash', 'iter', 'userdel'):
+        # skip potential runtime context dependecies
+        skip = True
+    elif name in ('repr', 'str'):
+        rep = getattr(__builtin__, name)
+        def op(obj):
+            s = rep(obj)
+            if "at 0x" in s:
+                print >>sys.stderr, "Warning: captured address may be awkward"
+            return s
+    else:
+        op = operation.FunctionByName[name]
+        arithmetic = (name + '_ovf') in operation.FunctionByName
+
+    if not op and not skip:
+        raise ValueError("XXX missing operator: %s" % (name,))
+
+    def generic_operator(self, *args_w):
+        assert len(args_w) == arity, name + " got the wrong number of 
arguments"
+        if op:
+            args = []
+            for w_arg in args_w:
+                try:
+                    arg = self.unwrap_for_computation(w_arg)
+                except UnwrapException:
+                    break
+                else:
+                    args.append(arg)
+            else:
+                # All arguments are constants: call the operator now
+                try:
+                    result = op(*args)
+                except Exception, e:
+                    etype = e.__class__
+                    msg = "generated by a constant operation:\n\t%s%r" % (
+                        name, tuple(args))
+                    raise operation.OperationThatShouldNotBePropagatedError(
+                        self.wrap(etype), self.wrap(msg))
+                else:
+                    # don't try to constant-fold operations giving a 'long'
+                    # result.  The result is probably meant to be sent to
+                    # an intmask(), but the 'long' constant confuses the
+                    # annotator a lot.
+                    if arithmetic and type(result) is long:
+                        pass
+                    # don't constant-fold getslice on lists, either
+                    elif name == 'getslice' and type(result) is list:
+                        pass
+                    # otherwise, fine
+                    else:
+                        try:
+                            return self.wrap(result)
+                        except WrapException:
+                            # type cannot sanely appear in flow graph,
+                            # store operation with variable result instead
+                            pass
+        w_result = self.do_operation_with_implicit_exceptions(name, *args_w)
+        return w_result
+
+    setattr(FlowObjSpace, name, generic_operator)
+
+
+for (name, symbol, arity, specialnames) in ObjSpace.MethodTable:
+    make_op(name, arity)
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
@@ -304,83 +304,3 @@
 _add_exceptions("""pow""",
                 OverflowError) # for the float case
 del _add_exceptions, _add_except_ovf
-
-def make_op(fs, name, symbol, arity, specialnames):
-    if getattr(fs, name, None) is not None:
-        return
-
-    op = None
-    skip = False
-    arithmetic = False
-
-    if (name.startswith('del') or
-        name.startswith('set') or
-        name.startswith('inplace_')):
-        # skip potential mutators
-        skip = True
-    elif name in ('id', 'hash', 'iter', 'userdel'):
-        # skip potential runtime context dependecies
-        skip = True
-    elif name in ('repr', 'str'):
-        rep = getattr(__builtin__, name)
-        def op(obj):
-            s = rep(obj)
-            if "at 0x" in s:
-                print >>sys.stderr, "Warning: captured address may be awkward"
-            return s
-    else:
-        op = FunctionByName[name]
-        arithmetic = (name + '_ovf') in FunctionByName
-
-    if not op and not skip:
-        raise ValueError("XXX missing operator: %s" % (name,))
-
-    def generic_operator(self, *args_w):
-        assert len(args_w) == arity, name + " got the wrong number of 
arguments"
-        if op:
-            args = []
-            for w_arg in args_w:
-                try:
-                    arg = self.unwrap_for_computation(w_arg)
-                except model.UnwrapException:
-                    break
-                else:
-                    args.append(arg)
-            else:
-                # All arguments are constants: call the operator now
-                try:
-                    result = op(*args)
-                except Exception, e:
-                    etype = e.__class__
-                    msg = "generated by a constant operation:\n\t%s%r" % (
-                        name, tuple(args))
-                    raise OperationThatShouldNotBePropagatedError(
-                        self.wrap(etype), self.wrap(msg))
-                else:
-                    # don't try to constant-fold operations giving a 'long'
-                    # result.  The result is probably meant to be sent to
-                    # an intmask(), but the 'long' constant confuses the
-                    # annotator a lot.
-                    if arithmetic and type(result) is long:
-                        pass
-                    # don't constant-fold getslice on lists, either
-                    elif name == 'getslice' and type(result) is list:
-                        pass
-                    # otherwise, fine
-                    else:
-                        try:
-                            return self.wrap(result)
-                        except model.WrapException:
-                            # type cannot sanely appear in flow graph,
-                            # store operation with variable result instead
-                            pass
-        w_result = self.do_operation_with_implicit_exceptions(name, *args_w)
-        return w_result
-
-    setattr(fs, name, generic_operator)
-
-
-def add_operations(fs):
-    """Add function operations to the flow space."""
-    for line in ObjSpace.MethodTable:
-        make_op(fs, *line)
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
@@ -11,31 +11,8 @@
     args_w, kwds_w = args.unpack()
     assert kwds_w == {}, "should not call %r with keyword arguments" % (fn,)
     assert len(args_w) > 0 and len(args_w) <= 5, 'import needs 1 to 5 
arguments'
-    w_name = args_w[0]
-    w_None = space.wrap(None)
-    w_glob, w_loc, w_frm = w_None, w_None, w_None
-    if len(args_w) > 1:
-        w_glob = args_w[1]
-    if len(args_w) > 2:
-        w_loc = args_w[2]
-    if len(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
-        raise SyntaxError, "RPython: import * is not allowed in functions"
-    if space.do_imports_immediately:
-        name, glob, loc, frm = (space.unwrap(w_name), space.unwrap(w_glob),
-                                space.unwrap(w_loc), space.unwrap(w_frm))
-        try:
-            mod = __import__(name, glob, loc, frm)
-        except ImportError, e:
-            raise OperationError(space.w_ImportError, space.wrap(str(e)))
-        return space.wrap(mod)
-    # redirect it, but avoid exposing the globals
-    w_glob = Constant({})
-    return space.do_operation('simple_call', Constant(__import__),
-                               w_name, w_glob, w_loc, w_frm)
+    args = [space.unwrap(arg) for arg in args_w]
+    return space.import_name(*args)
 
 def sc_operator(space, fn, args):
     args_w, kwds_w = args.unpack()
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
@@ -10,14 +10,11 @@
         cls.space = FlowObjSpace()
 
     def getframe(self, func):
-        space = self.space
         try:
             func = func.im_func
         except AttributeError:
             pass
-        code = func.func_code
-        code = PyCode._from_code(self.space, code)
-        frame = FlowSpaceFrame(space, code, func)
+        frame = FlowSpaceFrame(self.space, func)
         # hack the frame
         frame.locals_stack_w[frame.pycode.co_nlocals-1] = Constant(None)
         return frame
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
@@ -701,6 +701,13 @@
             from pypy import this_does_not_exist
         py.test.raises(ImportError, 'self.codetest(f)')
 
+    def test_relative_import(self):
+        def f():
+            from ..test.test_objspace import FlowObjSpace
+        # Check that the function works in Python
+        assert f() is None
+        self.codetest(f)
+
     def test_mergeable(self):
         def myfunc(x):
             if x:
@@ -987,16 +994,14 @@
                 pass
         py.test.raises(error.FlowingError, "self.codetest(f)")
 
-
-class TestFlowObjSpaceDelay(Base):
-    def setup_class(cls):
-        cls.space = FlowObjSpace()
-        cls.space.do_imports_immediately = False
-
-    def test_import_something(self):
+    def test_locals_dict(self):
         def f():
-            from some.unknown.module import stuff
-        g = self.codetest(f)
+            x = 5
+            return x
+            exec "None"
+        graph = self.codetest(f)
+        assert len(graph.startblock.exits) == 1
+        assert graph.startblock.exits[0].target == graph.returnblock
 
 
 DATA = {'x': 5,
diff --git a/pypy/rpython/lltypesystem/rbuiltin.py 
b/pypy/rpython/lltypesystem/rbuiltin.py
--- a/pypy/rpython/lltypesystem/rbuiltin.py
+++ b/pypy/rpython/lltypesystem/rbuiltin.py
@@ -16,7 +16,7 @@
         v_obj, v_typ = hop.inputargs(pyobj_repr, pyobj_repr)
         c = hop.inputconst(pyobj_repr, isinstance)
         v = hop.genop('simple_call', [c, v_obj, v_typ], resulttype = 
pyobj_repr)
-        return hop.llops.convertvar(v, pyobj_repr, bool_repr)        
+        return hop.llops.convertvar(v, pyobj_repr, bool_repr)
 
     if hop.args_s[1].is_constant() and hop.args_s[1].const == list:
         if hop.args_s[0].knowntype != list:
@@ -58,17 +58,10 @@
         return hop.llops.convertvar(v, pyobj_repr, bool_repr)
     raise TyperError("hasattr is only suported on a constant or on PyObject")
 
-def rtype_builtin___import__(hop):
-    xxx    # should not be used any more
-    args_v = hop.inputargs(*[pyobj_repr for ign in hop.args_r])
-    c = hop.inputconst(pyobj_repr, __import__)
-    return hop.genop('simple_call', [c] + args_v, resulttype = pyobj_repr)
-
 BUILTIN_TYPER = {}
 BUILTIN_TYPER[objectmodel.instantiate] = rtype_instantiate
 BUILTIN_TYPER[isinstance] = rtype_builtin_isinstance
 BUILTIN_TYPER[hasattr] = rtype_builtin_hasattr
-BUILTIN_TYPER[__import__] = rtype_builtin___import__
 BUILTIN_TYPER[objectmodel.r_dict] = rtype_r_dict
 
 # _________________________________________________________________
diff --git a/pypy/translator/translator.py b/pypy/translator/translator.py
--- a/pypy/translator/translator.py
+++ b/pypy/translator/translator.py
@@ -66,12 +66,6 @@
                 log.start(nice_repr_for_func(func))
             from pypy.objspace.flow.objspace import FlowObjSpace
             space = FlowObjSpace(self.flowconfig)
-            if self.annotator:
-                # ZZZ
-                self.annotator.policy._adjust_space_config(space)
-            elif hasattr(self, 'no_annotator_but_do_imports_immediately'):
-                space.do_imports_immediately = (
-                    self.no_annotator_but_do_imports_immediately)
             graph = space.build_flow(func)
             if self.config.translation.simplifying:
                 simplify.simplify_graph(graph)
_______________________________________________
pypy-commit mailing list
[email protected]
http://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to