Author: Ronan Lamy <ronan.l...@gmail.com>
Branch: 
Changeset: r65342:7ba260941669
Date: 2013-07-11 13:06 +0200
http://bitbucket.org/pypy/pypy/changeset/7ba260941669/

Log:    Merge branch flowoperators

diff --git a/rpython/config/translationoption.py 
b/rpython/config/translationoption.py
--- a/rpython/config/translationoption.py
+++ b/rpython/config/translationoption.py
@@ -170,7 +170,6 @@
               cmdline="--make-jobs", default=detect_number_of_processors()),
 
     # Flags of the TranslationContext:
-    BoolOption("simplifying", "Simplify flow graphs", default=True),
     BoolOption("list_comprehension_operations",
                "When true, look for and special-case the sequence of "
                "operations that results from a list comprehension and "
diff --git a/rpython/flowspace/flowcontext.py b/rpython/flowspace/flowcontext.py
--- a/rpython/flowspace/flowcontext.py
+++ b/rpython/flowspace/flowcontext.py
@@ -14,7 +14,7 @@
     recursively_flatten)
 from rpython.flowspace.specialcase import (rpython_print_item,
     rpython_print_newline)
-from rpython.flowspace.operation import implicit_exceptions
+from rpython.flowspace.operation import op
 
 
 class FlowingError(Exception):
@@ -55,25 +55,44 @@
     pass
 
 class SpamBlock(Block):
-    # make slots optional, for debugging
-    if hasattr(Block, '__slots__'):
-        __slots__ = "dead framestate".split()
-
     def __init__(self, framestate):
         Block.__init__(self, framestate.getvariables())
         self.framestate = framestate
         self.dead = False
 
+    def make_recorder(self):
+        return BlockRecorder(self)
+
 class EggBlock(Block):
-    # make slots optional, for debugging
-    if hasattr(Block, '__slots__'):
-        __slots__ = "prevblock booloutcome last_exception".split()
-
     def __init__(self, inputargs, prevblock, booloutcome):
         Block.__init__(self, inputargs)
         self.prevblock = prevblock
         self.booloutcome = booloutcome
 
+    @property
+    def ancestor(self):
+        parent = self.prevblock
+        while isinstance(parent, EggBlock):
+            parent = parent.prevblock
+        return parent
+
+    @property
+    def dead(self):
+        return self.ancestor.dead
+
+    @property
+    def framestate(self):
+        return self.ancestor.framestate
+
+    def make_recorder(self):
+        recorder = BlockRecorder(self)
+        curr = self
+        while isinstance(curr, EggBlock):
+            prev = curr.prevblock
+            recorder = Replayer(prev, curr.booloutcome, recorder)
+            curr = prev
+        return recorder
+
     def extravars(self, last_exception=None, last_exc_value=None):
         self.last_exception = last_exception
 
@@ -209,6 +228,7 @@
             w_exc_cls, w_exc_value = egg.inputargs[-2:]
             if isinstance(egg.last_exception, Constant):
                 w_exc_cls = egg.last_exception
+                assert not isinstance(w_exc_cls.value, list)
             raise ImplicitOperationError(w_exc_cls, w_exc_value)
 
 # ____________________________________________________________
@@ -430,44 +450,23 @@
         self.last_instr = state.next_instr
         self.blockstack = state.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 guessbool(self, w_condition, **kwds):
+        return self.recorder.guessbool(self, w_condition, **kwds)
 
-    def record(self, spaceop):
-        """Record an operation into the active block"""
+    def do_operation(self, name, *args_w):
         recorder = self.recorder
         if getattr(recorder, 'final_state', None) is not None:
             self.mergeblock(recorder.crnt_block, recorder.final_state)
             raise StopFlowing
-        recorder.append(spaceop)
-
-    def guessbool(self, w_condition, **kwds):
-        return self.recorder.guessbool(self, w_condition, **kwds)
-
-    def do_operation(self, name, *args_w):
         spaceop = SpaceOperation(name, args_w, Variable())
         spaceop.offset = self.last_instr
-        self.record(spaceop)
+        recorder.append(spaceop)
         return spaceop.result
 
     def do_operation_with_implicit_exceptions(self, name, *args_w):
         w_result = self.do_operation(name, *args_w)
-        self.handle_implicit_exceptions(implicit_exceptions.get(name))
+        oper = getattr(op, name)
+        self.handle_implicit_exceptions(oper.canraise)
         return w_result
 
     def handle_implicit_exceptions(self, exceptions):
@@ -488,39 +487,44 @@
         self.pendingblocks = collections.deque([graph.startblock])
         while self.pendingblocks:
             block = self.pendingblocks.popleft()
-            try:
-                self.recorder = self.recording(block)
-                while True:
-                    self.last_instr = self.handle_bytecode(self.last_instr)
-                    self.recorder.final_state = self.getstate()
+            if not block.dead:
+                self.record_block(block)
 
-            except ImplicitOperationError, e:
-                if isinstance(e.w_type, Constant):
-                    exc_cls = e.w_type.value
-                else:
-                    exc_cls = Exception
-                msg = "implicit %s shouldn't occur" % exc_cls.__name__
-                w_type = Constant(AssertionError)
-                w_value = Constant(AssertionError(msg))
-                link = Link([w_type, w_value], graph.exceptblock)
-                self.recorder.crnt_block.closeblock(link)
+    def record_block(self, block):
+        self.setstate(block.framestate)
+        self.recorder = block.make_recorder()
+        try:
+            while True:
+                self.last_instr = self.handle_bytecode(self.last_instr)
+                self.recorder.final_state = self.getstate()
 
-            except FSException, e:
-                if e.w_type is self.space.w_ImportError:
-                    msg = 'import statement always raises %s' % e
-                    raise ImportError(msg)
-                link = Link([e.w_type, e.w_value], graph.exceptblock)
-                self.recorder.crnt_block.closeblock(link)
+        except ImplicitOperationError, e:
+            if isinstance(e.w_type, Constant):
+                exc_cls = e.w_type.value
+            else:
+                exc_cls = Exception
+            msg = "implicit %s shouldn't occur" % exc_cls.__name__
+            w_type = Constant(AssertionError)
+            w_value = Constant(AssertionError(msg))
+            link = Link([w_type, w_value], self.graph.exceptblock)
+            self.recorder.crnt_block.closeblock(link)
 
-            except StopFlowing:
-                pass
+        except FSException, e:
+            if e.w_type == self.space.w_ImportError:
+                msg = 'import statement always raises %s' % e
+                raise ImportError(msg)
+            link = Link([e.w_type, e.w_value], self.graph.exceptblock)
+            self.recorder.crnt_block.closeblock(link)
 
-            except Return as exc:
-                w_result = exc.value
-                link = Link([w_result], graph.returnblock)
-                self.recorder.crnt_block.closeblock(link)
+        except StopFlowing:
+            pass
 
-        del self.recorder
+        except Return as exc:
+            w_result = exc.value
+            link = Link([w_result], self.graph.returnblock)
+            self.recorder.crnt_block.closeblock(link)
+
+        self.recorder = None
 
     def mergeblock(self, currentblock, currentstate):
         next_instr = currentstate.next_instr
@@ -661,8 +665,8 @@
                 self.last_exception = operr
                 raise operr
             else:
-                raise FSException(space.w_TypeError,
-                    space.wrap("raise: no active exception to re-raise"))
+                raise space.exc_wrap(TypeError(
+                    "raise: no active exception to re-raise"))
 
         w_value = space.w_None
         if nbargs >= 3:
diff --git a/rpython/flowspace/model.py b/rpython/flowspace/model.py
--- a/rpython/flowspace/model.py
+++ b/rpython/flowspace/model.py
@@ -3,6 +3,7 @@
 #
 # the below object/attribute model evolved from
 # a discussion in Berlin, 4th of october 2003
+import types
 import py
 
 from rpython.tool.uid import uid, Hashable
@@ -261,6 +262,7 @@
     dummyname = 'v'
     namesdict = {dummyname : (dummyname, 0)}
 
+    @property
     def name(self):
         _name = self._name
         _nr = self._nr
@@ -270,11 +272,10 @@
             _nr = self._nr = nd[_name][1]
             nd[_name] = (_name, _nr + 1)
         return "%s%d" % (_name, _nr)
-    name = property(name)
 
+    @property
     def renamed(self):
         return self._name is not self.dummyname
-    renamed = property(renamed)
 
     def __init__(self, name=None):
         self._name = self.dummyname
@@ -314,6 +315,9 @@
         self._name = intern(name)
         self._nr = nr
 
+    def foldable(self):
+        return False
+
 
 class Constant(Hashable):
     __slots__ = ["concretetype"]
@@ -323,6 +327,25 @@
         if concretetype is not None:
             self.concretetype = concretetype
 
+    def foldable(self):
+        to_check = self.value
+        if hasattr(to_check, 'im_self'):
+            to_check = to_check.im_self
+        if isinstance(to_check, (type, types.ClassType, types.ModuleType)):
+            # classes/types/modules are assumed immutable
+            return True
+        if (hasattr(to_check, '__class__') and
+                to_check.__class__.__module__ == '__builtin__'):
+            # builtin object
+            return True
+        # User-created instance
+        if hasattr(to_check, '_freeze_'):
+            assert to_check._freeze_() is True
+            return True
+        else:
+            # cannot count on it not mutating at runtime!
+            return False
+
 
 class UnwrapException(Exception):
     """Attempted to unwrap a Variable."""
diff --git a/rpython/flowspace/objspace.py b/rpython/flowspace/objspace.py
--- a/rpython/flowspace/objspace.py
+++ b/rpython/flowspace/objspace.py
@@ -19,7 +19,7 @@
 from rpython.flowspace.pygraph import PyGraph
 from rpython.flowspace.specialcase import SPECIAL_CASES
 from rpython.rlib.unroll import unrolling_iterable, _unroller
-from rpython.rlib import rstackovf, rarithmetic
+from rpython.rlib import rstackovf
 from rpython.rlib.rarithmetic import is_valid_int
 
 
@@ -45,6 +45,16 @@
         }
     }
 
+# built-ins that can always raise exceptions
+builtins_exceptions = {
+    int: [ValueError],
+    float: [ValueError],
+    chr: [ValueError],
+    unichr: [ValueError],
+    unicode: [UnicodeDecodeError],
+}
+
+
 def _assert_rpythonic(func):
     """Raise ValueError if ``func`` is obviously not RPython"""
     if func.func_doc and func.func_doc.lstrip().startswith('NOT_RPYTHON'):
@@ -135,6 +145,11 @@
             raise WrapException
         return Constant(obj)
 
+    def exc_wrap(self, exc):
+        w_value = self.wrap(exc)
+        w_type = self.wrap(type(exc))
+        return FSException(w_type, w_value)
+
     def int_w(self, w_obj):
         if isinstance(w_obj, Constant):
             val = w_obj.value
@@ -143,15 +158,6 @@
             return val
         return self.unwrap(w_obj)
 
-    def uint_w(self, w_obj):
-        if isinstance(w_obj, Constant):
-            val = w_obj.value
-            if type(val) is not rarithmetic.r_uint:
-                raise TypeError("expected unsigned: " + repr(w_obj))
-            return val
-        return self.unwrap(w_obj)
-
-
     def str_w(self, w_obj):
         if isinstance(w_obj, Constant):
             val = w_obj.value
@@ -160,14 +166,6 @@
             return val
         return self.unwrap(w_obj)
 
-    def float_w(self, w_obj):
-        if isinstance(w_obj, Constant):
-            val = w_obj.value
-            if type(val) is not float:
-                raise TypeError("expected float: " + repr(w_obj))
-            return val
-        return self.unwrap(w_obj)
-
     def unwrap(self, w_obj):
         if isinstance(w_obj, Variable):
             raise UnwrapException
@@ -176,40 +174,9 @@
         else:
             raise TypeError("not wrapped: " + repr(w_obj))
 
-    def unwrap_for_computation(self, w_obj):
-        obj = self.unwrap(w_obj)
-        to_check = obj
-        if hasattr(to_check, 'im_self'):
-            to_check = to_check.im_self
-        if (not isinstance(to_check, (type, types.ClassType, 
types.ModuleType)) and
-            # classes/types/modules are assumed immutable
-            hasattr(to_check, '__class__') and to_check.__class__.__module__ 
!= '__builtin__'):
-            frozen = hasattr(to_check, '_freeze_')
-            if frozen:
-                assert to_check._freeze_() is True
-            else:
-                # cannot count on it not mutating at runtime!
-                raise UnwrapException
-        return obj
-
     def exception_issubclass_w(self, w_cls1, w_cls2):
         return self.is_true(self.issubtype(w_cls1, w_cls2))
 
-    def _exception_match(self, w_exc_type, w_check_class):
-        """Helper for exception_match
-
-        Handles the base case where w_check_class is a constant exception
-        type.
-        """
-        if self.is_w(w_exc_type, w_check_class):
-            return True   # fast path (also here to handle string exceptions)
-        try:
-            return self.exception_issubclass_w(w_exc_type, w_check_class)
-        except FSException, e:
-            if e.match(self, self.w_TypeError):   # string exceptions maybe
-                return False
-            raise
-
     def exception_match(self, w_exc_type, w_check_class):
         """Checks if the given exception type matches 'w_check_class'."""
         try:
@@ -221,47 +188,43 @@
                 "Catching %s is not valid in RPython" % check_class.__name__)
         if not isinstance(check_class, tuple):
             # the simple case
-            return self._exception_match(w_exc_type, w_check_class)
+            return self.exception_issubclass_w(w_exc_type, w_check_class)
         # special case for StackOverflow (see rlib/rstackovf.py)
         if check_class == rstackovf.StackOverflow:
             w_real_class = self.wrap(rstackovf._StackOverflow)
-            return self._exception_match(w_exc_type, w_real_class)
+            return self.exception_issubclass_w(w_exc_type, w_real_class)
         # checking a tuple of classes
         for w_klass in self.unpackiterable(w_check_class):
             if self.exception_match(w_exc_type, w_klass):
                 return True
         return False
 
-    def exc_from_raise(self, w_type, w_value):
+    def exc_from_raise(self, w_arg1, w_arg2):
         """
         Create a wrapped exception from the arguments of a raise statement.
 
         Returns an FSException object whose w_value is an instance of w_type.
         """
-        if self.isinstance_w(w_type, self.w_type):
+        if self.isinstance_w(w_arg1, self.w_type):
             # this is for all cases of the form (Class, something)
-            if self.is_w(w_value, self.w_None):
+            if self.is_w(w_arg2, self.w_None):
                 # raise Type: we assume we have to instantiate Type
-                w_value = self.call_function(w_type)
-                w_type = self.type(w_value)
+                w_value = self.call_function(w_arg1)
             else:
-                w_valuetype = self.type(w_value)
-                if self.exception_issubclass_w(w_valuetype, w_type):
+                w_valuetype = self.type(w_arg2)
+                if self.exception_issubclass_w(w_valuetype, w_arg1):
                     # raise Type, Instance: let etype be the exact type of 
value
-                    w_type = w_valuetype
+                    w_value = w_arg2
                 else:
                     # raise Type, X: assume X is the constructor argument
-                    w_value = self.call_function(w_type, w_value)
-                    w_type = self.type(w_value)
+                    w_value = self.call_function(w_arg1, w_arg2)
         else:
             # the only case left here is (inst, None), from a 'raise inst'.
-            w_inst = w_type
-            w_instclass = self.type(w_inst)
-            if not self.is_w(w_value, self.w_None):
-                raise FSException(self.w_TypeError, self.wrap(
+            if not self.is_w(w_arg2, self.w_None):
+                raise self.exc_wrap(TypeError(
                     "instance exception may not have a separate value"))
-            w_value = w_inst
-            w_type = w_instclass
+            w_value = w_arg1
+        w_type = self.type(w_value)
         return FSException(w_type, w_value)
 
     def unpackiterable(self, w_iterable):
@@ -291,12 +254,8 @@
         return self.wrap(not self.is_true(w_obj))
 
     def is_true(self, w_obj):
-        try:
-            obj = self.unwrap_for_computation(w_obj)
-        except UnwrapException:
-            pass
-        else:
-            return bool(obj)
+        if w_obj.foldable():
+            return bool(w_obj.value)
         w_truthvalue = self.frame.do_operation('is_true', w_obj)
         return self.frame.guessbool(w_truthvalue)
 
@@ -316,7 +275,7 @@
                 try:
                     v, next_unroller = it.step()
                 except IndexError:
-                    raise FSException(self.w_StopIteration, self.w_None)
+                    raise self.exc_wrap(StopIteration())
                 else:
                     frame.replace_in_stack(it, next_unroller)
                     return self.wrap(v)
@@ -324,16 +283,6 @@
         frame.handle_implicit_exceptions([StopIteration, RuntimeError])
         return w_item
 
-    def setitem(self, w_obj, w_key, w_val):
-        # protect us from globals write access
-        if w_obj is self.frame.w_globals:
-            raise FlowingError(self.frame,
-                    "Attempting to modify global variable  %r." % (w_key))
-        return self.frame.do_operation_with_implicit_exceptions('setitem',
-                w_obj, w_key, w_val)
-
-    def setitem_str(self, w_obj, key, w_value):
-        return self.setitem(w_obj, self.wrap(key), w_value)
 
     def getattr(self, w_obj, w_name):
         # handling special things like sys
@@ -343,12 +292,8 @@
             if w_name not in const_w:
                 return 
self.frame.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:
+        if w_obj.foldable() and w_name.foldable():
+            obj, name = w_obj.value, w_name.value
             try:
                 result = getattr(obj, name)
             except Exception, e:
@@ -369,8 +314,8 @@
     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 FSException(self.w_ImportError, self.wrap(str(e)))
+        except ImportError as e:
+            raise self.exc_wrap(e)
         return self.wrap(mod)
 
     def import_from(self, w_module, w_name):
@@ -378,15 +323,15 @@
         assert isinstance(w_name, Constant)
         # handle sys
         if w_module in self.not_really_const:
-            const_w = self.not_really_const[w_obj]
+            const_w = self.not_really_const[w_module]
             if w_name not in const_w:
                 return 
self.frame.do_operation_with_implicit_exceptions('getattr',
-                                                                w_obj, w_name)
+                                                                w_module, 
w_name)
         try:
             return self.wrap(getattr(w_module.value, w_name.value))
         except AttributeError:
-            raise FSException(self.w_ImportError,
-                self.wrap("cannot import name '%s'" % w_name.value))
+            raise self.exc_wrap(ImportError(
+                "cannot import name '%s'" % w_name.value))
 
     def call_method(self, w_obj, methname, *arg_w):
         w_meth = self.getattr(w_obj, self.wrap(methname))
@@ -417,7 +362,7 @@
                     args_w = args.arguments_w + 
self.unpackiterable(args.w_stararg)
                 else:
                     args_w = args.arguments_w
-                return sc(self, fn, args_w)
+                return sc(self, args_w)
 
         if args.keywords or isinstance(args.w_stararg, Variable):
             shape, args_w = args.flatten()
@@ -430,15 +375,6 @@
                 args_w = args.arguments_w
             w_res = self.frame.do_operation('simple_call', w_callable, *args_w)
 
-        # maybe the call has generated an exception (any one)
-        # but, let's say, not if we are calling a built-in class or function
-        # because this gets in the way of the special-casing of
-        #
-        #    raise SomeError(x)
-        #
-        # as shown by test_objspace.test_raise3.
-
-        exceptions = [Exception]   # *any* exception by default
         if isinstance(w_callable, Constant):
             c = w_callable.value
             if (isinstance(c, (types.BuiltinFunctionType,
@@ -446,8 +382,11 @@
                                types.ClassType,
                                types.TypeType)) and
                   c.__module__ in ['__builtin__', 'exceptions']):
-                exceptions = operation.implicit_exceptions.get(c)
-        self.frame.handle_implicit_exceptions(exceptions)
+                if c in builtins_exceptions:
+                    
self.frame.handle_implicit_exceptions(builtins_exceptions[c])
+                return w_res
+        # *any* exception for non-builtins
+        self.frame.handle_implicit_exceptions([Exception])
         return w_res
 
     def find_global(self, w_globals, varname):
@@ -462,82 +401,61 @@
                 raise FlowingError(self.frame, self.wrap(message))
         return self.wrap(value)
 
-def make_op(name, arity):
+def make_impure_op(oper):
+    def generic_operator(self, *args_w):
+        if len(args_w) != oper.arity:
+            raise TypeError(oper.name + " got the wrong number of arguments")
+        w_result = self.frame.do_operation_with_implicit_exceptions(oper.name, 
*args_w)
+        return w_result
+    return generic_operator
+
+def make_op(oper):
     """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,))
+    name = oper.name
+    func = oper.pyfunc
 
     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
+        assert len(args_w) == oper.arity, name + " got the wrong number of 
arguments"
+        args = []
+        if all(w_arg.foldable() for w_arg in args_w):
+            args = [w_arg.value for w_arg in args_w]
+            # All arguments are constants: call the operator now
+            try:
+                result = func(*args)
+            except Exception, e:
+                etype = e.__class__
+                msg = "%s%r always raises %s: %s" % (
+                    name, tuple(args), etype, e)
+                raise FlowingError(self.frame, 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 oper.can_overflow 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:
-                    args.append(arg)
-            else:
-                # All arguments are constants: call the operator now
-                try:
-                    result = op(*args)
-                except Exception, e:
-                    etype = e.__class__
-                    msg = "%s%r always raises %s: %s" % (
-                        name, tuple(args), etype, e)
-                    raise FlowingError(self.frame, 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:
+                    try:
+                        return self.wrap(result)
+                    except WrapException:
+                        # type cannot sanely appear in flow graph,
+                        # store operation with variable result instead
                         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.frame.do_operation_with_implicit_exceptions(name, 
*args_w)
         return w_result
+    return generic_operator
 
-    setattr(FlowObjSpace, name, generic_operator)
-
-for (name, symbol, arity, specialnames) in operation.MethodTable:
-    make_op(name, arity)
+for oper in operation.op.__dict__.values():
+    if getattr(FlowObjSpace, oper.name, None) is None:
+        if oper.pure:
+            op_method = make_op(oper)
+        else:
+            op_method = make_impure_op(oper)
+        setattr(FlowObjSpace, oper.name, op_method)
 
 
 def build_flow(func, space=FlowObjSpace()):
diff --git a/rpython/flowspace/operation.py b/rpython/flowspace/operation.py
--- a/rpython/flowspace/operation.py
+++ b/rpython/flowspace/operation.py
@@ -8,93 +8,53 @@
 import operator
 from rpython.tool.sourcetools import compile2
 from rpython.rlib.rarithmetic import ovfcheck
+from rpython.flowspace.model import Constant
 
-# this is a copy that should be shared with standard objspace
+class _OpHolder(object): pass
+op = _OpHolder()
 
-MethodTable = [
-# method name # symbol # number of arguments # special method name(s)
-    ('is_',             'is',        2, []),
-    ('id',              'id',        1, []),
-    ('type',            'type',      1, []),
-    ('isinstance',      'isinstance', 2, ['__instancecheck__']),
-    ('issubtype',       'issubtype', 2, ['__subclasscheck__']),  # not for 
old-style classes
-    ('repr',            'repr',      1, ['__repr__']),
-    ('str',             'str',       1, ['__str__']),
-    ('format',          'format',    2, ['__format__']),
-    ('len',             'len',       1, ['__len__']),
-    ('hash',            'hash',      1, ['__hash__']),
-    ('getattr',         'getattr',   2, ['__getattribute__']),
-    ('setattr',         'setattr',   3, ['__setattr__']),
-    ('delattr',         'delattr',   2, ['__delattr__']),
-    ('getitem',         'getitem',   2, ['__getitem__']),
-    ('setitem',         'setitem',   3, ['__setitem__']),
-    ('delitem',         'delitem',   2, ['__delitem__']),
-    ('getslice',        'getslice',  3, ['__getslice__']),
-    ('setslice',        'setslice',  4, ['__setslice__']),
-    ('delslice',        'delslice',  3, ['__delslice__']),
-    ('trunc',           'trunc',     1, ['__trunc__']),
-    ('pos',             'pos',       1, ['__pos__']),
-    ('neg',             'neg',       1, ['__neg__']),
-    ('nonzero',         'truth',     1, ['__nonzero__']),
-    ('abs' ,            'abs',       1, ['__abs__']),
-    ('hex',             'hex',       1, ['__hex__']),
-    ('oct',             'oct',       1, ['__oct__']),
-    ('ord',             'ord',       1, []),
-    ('invert',          '~',         1, ['__invert__']),
-    ('add',             '+',         2, ['__add__', '__radd__']),
-    ('sub',             '-',         2, ['__sub__', '__rsub__']),
-    ('mul',             '*',         2, ['__mul__', '__rmul__']),
-    ('truediv',         '/',         2, ['__truediv__', '__rtruediv__']),
-    ('floordiv',        '//',        2, ['__floordiv__', '__rfloordiv__']),
-    ('div',             'div',       2, ['__div__', '__rdiv__']),
-    ('mod',             '%',         2, ['__mod__', '__rmod__']),
-    ('divmod',          'divmod',    2, ['__divmod__', '__rdivmod__']),
-    ('pow',             '**',        3, ['__pow__', '__rpow__']),
-    ('lshift',          '<<',        2, ['__lshift__', '__rlshift__']),
-    ('rshift',          '>>',        2, ['__rshift__', '__rrshift__']),
-    ('and_',            '&',         2, ['__and__', '__rand__']),
-    ('or_',             '|',         2, ['__or__', '__ror__']),
-    ('xor',             '^',         2, ['__xor__', '__rxor__']),
-    ('int',             'int',       1, ['__int__']),
-    ('index',           'index',     1, ['__index__']),
-    ('float',           'float',     1, ['__float__']),
-    ('long',            'long',      1, ['__long__']),
-    ('inplace_add',     '+=',        2, ['__iadd__']),
-    ('inplace_sub',     '-=',        2, ['__isub__']),
-    ('inplace_mul',     '*=',        2, ['__imul__']),
-    ('inplace_truediv', '/=',        2, ['__itruediv__']),
-    ('inplace_floordiv','//=',       2, ['__ifloordiv__']),
-    ('inplace_div',     'div=',      2, ['__idiv__']),
-    ('inplace_mod',     '%=',        2, ['__imod__']),
-    ('inplace_pow',     '**=',       2, ['__ipow__']),
-    ('inplace_lshift',  '<<=',       2, ['__ilshift__']),
-    ('inplace_rshift',  '>>=',       2, ['__irshift__']),
-    ('inplace_and',     '&=',        2, ['__iand__']),
-    ('inplace_or',      '|=',        2, ['__ior__']),
-    ('inplace_xor',     '^=',        2, ['__ixor__']),
-    ('lt',              '<',         2, ['__lt__', '__gt__']),
-    ('le',              '<=',        2, ['__le__', '__ge__']),
-    ('eq',              '==',        2, ['__eq__', '__eq__']),
-    ('ne',              '!=',        2, ['__ne__', '__ne__']),
-    ('gt',              '>',         2, ['__gt__', '__lt__']),
-    ('ge',              '>=',        2, ['__ge__', '__le__']),
-    ('cmp',             'cmp',       2, ['__cmp__']),   # rich cmps preferred
-    ('coerce',          'coerce',    2, ['__coerce__', '__coerce__']),
-    ('contains',        'contains',  2, ['__contains__']),
-    ('iter',            'iter',      1, ['__iter__']),
-    ('next',            'next',      1, ['next']),
-#    ('call',            'call',      3, ['__call__']),
-    ('get',             'get',       3, ['__get__']),
-    ('set',             'set',       3, ['__set__']),
-    ('delete',          'delete',    2, ['__delete__']),
-    ('userdel',         'del',       1, ['__del__']),
-    ('buffer',          'buffer',    1, ['__buffer__']),   # see buffer.py
-    ]
+func2op = {}
 
+class SpaceOperator(object):
+    def __init__(self, name, arity, symbol, pyfunc, pure=False,
+            can_overflow=False):
+        self.name = name
+        self.arity = arity
+        self.symbol = symbol
+        self.pyfunc = pyfunc
+        self.pure = pure
+        self.can_overflow = can_overflow
+        self.canraise = []
 
-FunctionByName = {}   # dict {"operation_name": <built-in function>}
-OperationName  = {}   # dict {<built-in function>: "operation_name"}
-Arity          = {}   # dict {"operation name": number of arguments}
+    def make_sc(self):
+        def sc_operator(space, args_w):
+            if len(args_w) != self.arity:
+                if self is op.pow and len(args_w) == 2:
+                    args_w = args_w + [Constant(None)]
+                elif self is op.getattr and len(args_w) == 3:
+                    return space.frame.do_operation('simple_call', 
Constant(getattr), *args_w)
+                else:
+                    raise Exception("should call %r with exactly %d arguments" 
% (
+                        self.name, self.arity))
+            # completely replace the call with the underlying
+            # operation and its limited implicit exceptions semantic
+            return getattr(space, self.name)(*args_w)
+        return sc_operator
+
+
+def add_operator(name, arity, symbol, pyfunc=None, pure=False, ovf=False):
+    operator_func = getattr(operator, name, None)
+    oper = SpaceOperator(name, arity, symbol, pyfunc, pure, can_overflow=ovf)
+    setattr(op, name, oper)
+    if pyfunc is not None:
+        func2op[pyfunc] = oper
+    if operator_func:
+        func2op[operator_func] = oper
+        if pyfunc is None:
+            oper.pyfunc = operator_func
+    if ovf:
+        ovf_func = lambda *args: ovfcheck(oper.pyfunc(*args))
+        add_operator(name + '_ovf', arity, symbol, pyfunc=ovf_func)
 
 # ____________________________________________________________
 
@@ -186,33 +146,6 @@
 def userdel(x):
     x.__del__()
 
-def neg_ovf(x):
-    return ovfcheck(-x)
-
-def abs_ovf(x):
-    return ovfcheck(abs(x))
-
-def add_ovf(x, y):
-    return ovfcheck(x + y)
-
-def sub_ovf(x, y):
-    return ovfcheck(x - y)
-
-def mul_ovf(x, y):
-    return ovfcheck(x * y)
-
-def floordiv_ovf(x, y):
-    return ovfcheck(operator.floordiv(x, y))
-
-def div_ovf(x, y):
-    return ovfcheck(operator.div(x, y))
-
-def mod_ovf(x, y):
-    return ovfcheck(x % y)
-
-def lshift_ovf(x, y):
-    return ovfcheck(x << y)
-
 # slicing: operator.{get,set,del}slice() don't support b=None or c=None
 def do_getslice(a, b, c):
     return a[b:c]
@@ -226,101 +159,91 @@
 def unsupported(*args):
     raise ValueError("this is not supported")
 
-# ____________________________________________________________
 
-# The following table can list several times the same operation name,
-# if multiple built-in functions correspond to it.  The first one should
-# be picked, though, as the best built-in for the given operation name.
-# Lines ('name', operator.name) are added automatically.
+add_operator('is_', 2, 'is', pure=True)
+add_operator('id', 1, 'id', pyfunc=id)
+add_operator('type', 1, 'type', pyfunc=new_style_type, pure=True)
+add_operator('isinstance', 2, 'isinstance', pyfunc=isinstance, pure=True)
+add_operator('issubtype', 2, 'issubtype', pyfunc=issubclass, pure=True)  # not 
for old-style classes
+add_operator('repr', 1, 'repr', pyfunc=repr, pure=True)
+add_operator('str', 1, 'str', pyfunc=str, pure=True)
+add_operator('format', 2, 'format', pyfunc=unsupported)
+add_operator('len', 1, 'len', pyfunc=len, pure=True)
+add_operator('hash', 1, 'hash', pyfunc=hash)
+add_operator('getattr', 2, 'getattr', pyfunc=getattr, pure=True)
+add_operator('setattr', 3, 'setattr', pyfunc=setattr)
+add_operator('delattr', 2, 'delattr', pyfunc=delattr)
+add_operator('getitem', 2, 'getitem', pure=True)
+add_operator('setitem', 3, 'setitem')
+add_operator('delitem', 2, 'delitem')
+add_operator('getslice', 3, 'getslice', pyfunc=do_getslice, pure=True)
+add_operator('setslice', 4, 'setslice', pyfunc=do_setslice)
+add_operator('delslice', 3, 'delslice', pyfunc=do_delslice)
+add_operator('trunc', 1, 'trunc', pyfunc=unsupported)
+add_operator('pos', 1, 'pos', pure=True)
+add_operator('neg', 1, 'neg', pure=True, ovf=True)
+add_operator('nonzero', 1, 'truth', pyfunc=bool, pure=True)
+op.is_true = op.nonzero
+add_operator('abs' , 1, 'abs', pyfunc=abs, pure=True, ovf=True)
+add_operator('hex', 1, 'hex', pyfunc=hex, pure=True)
+add_operator('oct', 1, 'oct', pyfunc=oct, pure=True)
+add_operator('ord', 1, 'ord', pyfunc=ord, pure=True)
+add_operator('invert', 1, '~', pure=True)
+add_operator('add', 2, '+', pure=True, ovf=True)
+add_operator('sub', 2, '-', pure=True, ovf=True)
+add_operator('mul', 2, '*', pure=True, ovf=True)
+add_operator('truediv', 2, '/', pure=True)
+add_operator('floordiv', 2, '//', pure=True, ovf=True)
+add_operator('div', 2, 'div', pure=True, ovf=True)
+add_operator('mod', 2, '%', pure=True, ovf=True)
+add_operator('divmod', 2, 'divmod', pyfunc=divmod, pure=True)
+add_operator('pow', 3, '**', pyfunc=pow, pure=True)
+add_operator('lshift', 2, '<<', pure=True, ovf=True)
+add_operator('rshift', 2, '>>', pure=True)
+add_operator('and_', 2, '&', pure=True)
+add_operator('or_', 2, '|', pure=True)
+add_operator('xor', 2, '^', pure=True)
+add_operator('int', 1, 'int', pyfunc=do_int, pure=True)
+add_operator('index', 1, 'index', pyfunc=do_index, pure=True)
+add_operator('float', 1, 'float', pyfunc=do_float, pure=True)
+add_operator('long', 1, 'long', pyfunc=do_long, pure=True)
+add_operator('inplace_add', 2, '+=', pyfunc=inplace_add)
+add_operator('inplace_sub', 2, '-=', pyfunc=inplace_sub)
+add_operator('inplace_mul', 2, '*=', pyfunc=inplace_mul)
+add_operator('inplace_truediv', 2, '/=', pyfunc=inplace_truediv)
+add_operator('inplace_floordiv', 2, '//=', pyfunc=inplace_floordiv)
+add_operator('inplace_div', 2, 'div=', pyfunc=inplace_div)
+add_operator('inplace_mod', 2, '%=', pyfunc=inplace_mod)
+add_operator('inplace_pow', 2, '**=', pyfunc=inplace_pow)
+add_operator('inplace_lshift', 2, '<<=', pyfunc=inplace_lshift)
+add_operator('inplace_rshift', 2, '>>=', pyfunc=inplace_rshift)
+add_operator('inplace_and', 2, '&=', pyfunc=inplace_and)
+add_operator('inplace_or', 2, '|=', pyfunc=inplace_or)
+add_operator('inplace_xor', 2, '^=', pyfunc=inplace_xor)
+add_operator('lt', 2, '<', pure=True)
+add_operator('le', 2, '<=', pure=True)
+add_operator('eq', 2, '==', pure=True)
+add_operator('ne', 2, '!=', pure=True)
+add_operator('gt', 2, '>', pure=True)
+add_operator('ge', 2, '>=', pure=True)
+add_operator('cmp', 2, 'cmp', pyfunc=cmp, pure=True)   # rich cmps preferred
+add_operator('coerce', 2, 'coerce', pyfunc=coerce, pure=True)
+add_operator('contains', 2, 'contains', pure=True)
+add_operator('iter', 1, 'iter', pyfunc=iter)
+add_operator('next', 1, 'next', pyfunc=next)
+#add_operator('call', 3, 'call')
+add_operator('get', 3, 'get', pyfunc=get, pure=True)
+add_operator('set', 3, 'set', pyfunc=set)
+add_operator('delete', 2, 'delete', pyfunc=delete)
+add_operator('userdel', 1, 'del', pyfunc=userdel)
+add_operator('buffer', 1, 'buffer', pyfunc=buffer, pure=True)   # see buffer.py
 
-# INTERNAL ONLY, use the dicts declared at the top of the file.
-Table = [
-    ('id',              id),
-    ('type',            new_style_type),
-    ('type',            type),
-    ('isinstance',      isinstance),
-    ('issubtype',       issubclass),
-    ('repr',            repr),
-    ('str',             str),
-    ('format',          unsupported),
-    ('len',             len),
-    ('hash',            hash),
-    ('getattr',         getattr),
-    ('setattr',         setattr),
-    ('delattr',         delattr),
-    ('nonzero',         bool),
-    ('nonzero',         operator.truth),
-    ('is_true',         bool),
-    ('is_true',         operator.truth),
-    ('trunc',           unsupported),
-    ('abs' ,            abs),
-    ('hex',             hex),
-    ('oct',             oct),
-    ('ord',             ord),
-    ('divmod',          divmod),
-    ('pow',             pow),
-    ('int',             do_int),
-    ('index',           do_index),
-    ('float',           do_float),
-    ('long',            do_long),
-    ('inplace_add',     inplace_add),
-    ('inplace_sub',     inplace_sub),
-    ('inplace_mul',     inplace_mul),
-    ('inplace_truediv', inplace_truediv),
-    ('inplace_floordiv',inplace_floordiv),
-    ('inplace_div',     inplace_div),
-    ('inplace_mod',     inplace_mod),
-    ('inplace_pow',     inplace_pow),
-    ('inplace_lshift',  inplace_lshift),
-    ('inplace_rshift',  inplace_rshift),
-    ('inplace_and',     inplace_and),
-    ('inplace_or',      inplace_or),
-    ('inplace_xor',     inplace_xor),
-    ('cmp',             cmp),
-    ('coerce',          coerce),
-    ('iter',            iter),
-    ('next',            next),
-    ('get',             get),
-    ('set',             set),
-    ('delete',          delete),
-    ('userdel',         userdel),
-    ('buffer',          buffer),
-    ('getslice',        do_getslice),
-    ('setslice',        do_setslice),
-    ('delslice',        do_delslice),
-    # --- operations added by graph transformations ---
-    ('neg_ovf',         neg_ovf),
-    ('abs_ovf',         abs_ovf),
-    ('add_ovf',         add_ovf),
-    ('sub_ovf',         sub_ovf),
-    ('mul_ovf',         mul_ovf),
-    ('floordiv_ovf',    floordiv_ovf),
-    ('div_ovf',         div_ovf),
-    ('mod_ovf',         mod_ovf),
-    ('lshift_ovf',      lshift_ovf),
-]
+# Other functions that get directly translated to SpaceOperators
+func2op[type] = op.type
+func2op[operator.truth] = op.nonzero
 if hasattr(__builtin__, 'next'):
-    Table.append(('next', __builtin__.next))
+    func2op[__builtin__.next] = op.next
 
-def setup():
-    # insert all operators
-    for line in MethodTable:
-        name = line[0]
-        if hasattr(operator, name):
-            Table.append((name, getattr(operator, name)))
-    # build the dictionaries
-    for name, func in Table:
-        if name not in FunctionByName:
-            FunctionByName[name] = func
-        if func not in OperationName:
-            OperationName[func] = name
-    # check that the result is complete
-    for line in MethodTable:
-        name = line[0]
-        Arity[name] = line[2]
-        assert name in FunctionByName
-setup()
-del Table, setup # INTERNAL ONLY, use the dicts declared at the top of the file
 
 op_appendices = {
     OverflowError: 'ovf',
@@ -330,24 +253,18 @@
     ValueError: 'val',
     }
 
-implicit_exceptions = {
-    int: [ValueError],      # built-ins that can always raise exceptions
-    float: [ValueError],
-    chr: [ValueError],
-    unichr: [ValueError],
-    unicode: [UnicodeDecodeError],
-    # specifying IndexError, and KeyError beyond Exception,
-    # allows the annotator to be more precise, see 
test_reraiseAnything/KeyError in
-    # the annotator tests
-    'getitem': [IndexError, KeyError, Exception],
-    'setitem': [IndexError, KeyError, Exception],
-    'delitem': [IndexError, KeyError, Exception],
-    'contains': [Exception],    # from an r_dict
-    }
+# specifying IndexError, and KeyError beyond Exception,
+# allows the annotator to be more precise, see test_reraiseAnything/KeyError in
+# the annotator tests
+op.getitem.canraise = [IndexError, KeyError, Exception]
+op.setitem.canraise = [IndexError, KeyError, Exception]
+op.delitem.canraise = [IndexError, KeyError, Exception]
+op.contains.canraise = [Exception]    # from an r_dict
 
 def _add_exceptions(names, exc):
     for name in names.split():
-        lis = implicit_exceptions.setdefault(name, [])
+        oper = getattr(op, name)
+        lis = oper.canraise
         if exc in lis:
             raise ValueError, "your list is causing duplication!"
         lis.append(exc)
@@ -356,12 +273,13 @@
 def _add_except_ovf(names):
     # duplicate exceptions and add OverflowError
     for name in names.split():
-        lis = implicit_exceptions.setdefault(name, [])[:]
-        lis.append(OverflowError)
-        implicit_exceptions[name+"_ovf"] = lis
+        oper = getattr(op, name)
+        oper_ovf = getattr(op, name+'_ovf')
+        oper_ovf.canraise = list(oper.canraise)
+        oper_ovf.canraise.append(OverflowError)
 
 _add_exceptions("""div mod divmod truediv floordiv pow
-                   inplace_div inplace_mod inplace_divmod inplace_truediv
+                   inplace_div inplace_mod inplace_truediv
                    inplace_floordiv inplace_pow""", ZeroDivisionError)
 _add_exceptions("""pow inplace_pow lshift inplace_lshift rshift
                    inplace_rshift""", ValueError)
@@ -370,7 +288,7 @@
                    inplace_floordiv inplace_div inplace_mod inplace_pow
                    inplace_lshift""", OverflowError) # without a _ovf version
 _add_except_ovf("""neg abs add sub mul
-                   floordiv div mod pow lshift""")   # with a _ovf version
+                   floordiv div mod lshift""")   # with a _ovf version
 _add_exceptions("""pow""",
                 OverflowError) # for the float case
 del _add_exceptions, _add_except_ovf
diff --git a/rpython/flowspace/specialcase.py b/rpython/flowspace/specialcase.py
--- a/rpython/flowspace/specialcase.py
+++ b/rpython/flowspace/specialcase.py
@@ -1,27 +1,13 @@
 from rpython.flowspace.model import Constant
-from rpython.flowspace.operation import OperationName, Arity
+from rpython.flowspace.operation import func2op, op
 from rpython.rlib.rarithmetic import r_uint
 from rpython.rlib.objectmodel import we_are_translated
 
-def sc_import(space, fn, args_w):
+def sc_import(space, args_w):
     assert len(args_w) > 0 and len(args_w) <= 5, 'import needs 1 to 5 
arguments'
     args = [space.unwrap(arg) for arg in args_w]
     return space.import_name(*args)
 
-def sc_operator(space, fn, args_w):
-    opname = OperationName[fn]
-    if len(args_w) != Arity[opname]:
-        if opname == 'pow' and len(args_w) == 2:
-            args_w = args_w + [Constant(None)]
-        elif opname == 'getattr' and len(args_w) == 3:
-            return space.frame.do_operation('simple_call', Constant(getattr), 
*args_w)
-        else:
-            raise Exception("should call %r with exactly %d arguments" % (
-                fn, Arity[opname]))
-    # completely replace the call with the underlying
-    # operation and its limited implicit exceptions semantic
-    return getattr(space, opname)(*args_w)
-
 # _________________________________________________________________________
 # a simplified version of the basic printing routines, for RPython programs
 class StdOutBuffer:
@@ -47,7 +33,7 @@
 
 # _________________________________________________________________________
 
-def sc_r_uint(space, r_uint, args_w):
+def sc_r_uint(space, args_w):
     # 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)
@@ -56,10 +42,10 @@
         return Constant(r_uint(w_value.value))
     return space.frame.do_operation('simple_call', space.wrap(r_uint), w_value)
 
-def sc_we_are_translated(space, we_are_translated, args_w):
+def sc_we_are_translated(space, args_w):
     return Constant(True)
 
-def sc_locals(space, locals, args):
+def sc_locals(space, args):
     raise Exception(
         "A function calling locals() is not RPython.  "
         "Note that if you're translating code outside the PyPy "
@@ -71,5 +57,5 @@
 SPECIAL_CASES = {__import__: sc_import, r_uint: sc_r_uint,
         we_are_translated: sc_we_are_translated,
         locals: sc_locals}
-for fn in OperationName:
-    SPECIAL_CASES[fn] = sc_operator
+for fn, oper in func2op.items():
+    SPECIAL_CASES[fn] = oper.make_sc()
diff --git a/rpython/flowspace/test/test_objspace.py 
b/rpython/flowspace/test/test_objspace.py
--- a/rpython/flowspace/test/test_objspace.py
+++ b/rpython/flowspace/test/test_objspace.py
@@ -1,6 +1,6 @@
 from __future__ import with_statement
 import new
-import py, sys
+import py
 from contextlib import contextmanager
 
 from rpython.flowspace.model import Constant, mkentrymap, c_last_exception
@@ -1169,6 +1169,28 @@
                                               'iter': 1, 'newlist': 1,
                                               'next': 1, 'simple_call': 1}
 
+    def test_mutate_const_list(self):
+        lst = list('abcdef')
+        def f():
+            lst[0] = 'x'
+            return lst
+        graph = self.codetest(f)
+        assert 'setitem' in self.all_operations(graph)
+
+    def test_sys_getattr(self):
+        def f():
+            import sys
+            return sys.modules
+        graph = self.codetest(f)
+        assert 'getattr' in self.all_operations(graph)
+
+    def test_sys_import_from(self):
+        def f():
+            from sys import modules
+            return modules
+        graph = self.codetest(f)
+        assert 'getattr' in self.all_operations(graph)
+
 DATA = {'x': 5,
         'y': 6}
 
diff --git a/rpython/rtyper/lltypesystem/opimpl.py 
b/rpython/rtyper/lltypesystem/opimpl.py
--- a/rpython/rtyper/lltypesystem/opimpl.py
+++ b/rpython/rtyper/lltypesystem/opimpl.py
@@ -1,4 +1,4 @@
-from rpython.flowspace.operation import FunctionByName
+from rpython.flowspace.operation import op
 from rpython.rlib import debug
 from rpython.rlib.rarithmetic import is_valid_int
 from rpython.rtyper.lltypesystem import lltype, llmemory
@@ -13,7 +13,6 @@
                         'lt': True, 'le': True,
                         'eq': True, 'ne': True,
                         'is_true': True}
-ops_unary = {'is_true': True, 'neg': True, 'abs': True, 'invert': True}
 
 # global synonyms for some types
 from rpython.rlib.rarithmetic import intmask
@@ -46,11 +45,13 @@
 def get_primitive_op_src(fullopname):
     assert '_' in fullopname, "%s: not a primitive op" % (fullopname,)
     typname, opname = fullopname.split('_', 1)
-    if opname not in FunctionByName and (opname + '_') in FunctionByName:
-        func = FunctionByName[opname + '_']   # or_, and_
+    if hasattr(op, opname):
+        oper = getattr(op, opname)
+    elif hasattr(op, opname + '_'):
+        oper = getattr(op, opname + '_')   # or_, and_
     else:
-        assert opname in FunctionByName, "%s: not a primitive op" % 
(fullopname,)
-        func = FunctionByName[opname]
+        raise ValueError("%s: not a primitive op" % (fullopname,))
+    func = oper.pyfunc
 
     if typname == 'char':
         # char_lt, char_eq, ...
@@ -72,7 +73,7 @@
             fullopname,)
         argtype = argtype_by_name[typname]
 
-        if opname in ops_unary:
+        if oper.arity == 1:
             def op_function(x):
                 if not isinstance(x, argtype):
                     raise TypeError("%r arg must be %s, got %r instead" % (
diff --git a/rpython/translator/simplify.py b/rpython/translator/simplify.py
--- a/rpython/translator/simplify.py
+++ b/rpython/translator/simplify.py
@@ -120,7 +120,8 @@
     covf = Constant(rarithmetic.ovfcheck)
 
     def check_syntax(opname):
-        exlis = operation.implicit_exceptions.get("%s_ovf" % (opname,), [])
+        oper = getattr(operation.op, opname + "_ovf")
+        exlis = oper.canraise
         if OverflowError not in exlis:
             raise Exception("ovfcheck in %s: Operation %s has no"
                             " overflow variant" % (graph.name, opname))
@@ -495,11 +496,11 @@
         # look for removable operations whose result is never used
         for i in range(len(block.operations)-1, -1, -1):
             op = block.operations[i]
-            if op.result not in read_vars: 
+            if op.result not in read_vars:
                 if canremove(op, block):
                     del block.operations[i]
-                elif op.opname == 'simple_call': 
-                    # XXX we want to have a more effective and safe 
+                elif op.opname == 'simple_call':
+                    # XXX we want to have a more effective and safe
                     # way to check if this operation has side effects
                     # ...
                     if op.args and isinstance(op.args[0], Constant):
@@ -626,7 +627,7 @@
 
     while candidates:
         cand, tgts = candidates.pop()
-        newexits = list(cand.exits) 
+        newexits = list(cand.exits)
         for case, tgt in tgts:
             exit = cand.exits[case]
             rrenaming = dict(zip(tgt.inputargs,exit.args))
diff --git a/rpython/translator/test/test_translator.py 
b/rpython/translator/test/test_translator.py
--- a/rpython/translator/test/test_translator.py
+++ b/rpython/translator/test/test_translator.py
@@ -8,7 +8,7 @@
         d['key'] = 'value'
 
 def test_example():
-    t = TranslationContext(simplifying=True)
+    t = TranslationContext()
     t.buildflowgraph(example)
     # this specific example triggered a bug in simplify.py
     #t.view()
diff --git a/rpython/translator/translator.py b/rpython/translator/translator.py
--- a/rpython/translator/translator.py
+++ b/rpython/translator/translator.py
@@ -21,7 +21,6 @@
 class TranslationContext(object):
     FLOWING_FLAGS = {
         'verbose': False,
-        'simplifying': True,
         'list_comprehension_operations': False,   # True, - not super-tested
         }
 
@@ -30,8 +29,7 @@
             from rpython.config.translationoption import 
get_combined_translation_config
             config = get_combined_translation_config(translating=True)
         # ZZZ should go away in the end
-        for attr in ['verbose', 'simplifying',
-                     'list_comprehension_operations']:
+        for attr in ['verbose', 'list_comprehension_operations']:
             if attr in flowing_flags:
                 setattr(config.translation, attr, flowing_flags[attr])
         self.config = config
@@ -54,8 +52,7 @@
             if self.config.translation.verbose:
                 log.start(nice_repr_for_func(func))
             graph = build_flow(func)
-            if self.config.translation.simplifying:
-                simplify.simplify_graph(graph)
+            simplify.simplify_graph(graph)
             if self.config.translation.list_comprehension_operations:
                 simplify.detect_list_comprehension(graph)
             if self.config.translation.verbose:
_______________________________________________
pypy-commit mailing list
pypy-commit@python.org
http://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to